[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 (®_state[i].use_ruid, split_ruid);
> +- reload_combine_split_one_ruid (®_state[i].store_ruid, split_ruid);
> +- reload_combine_split_one_ruid (®_state[i].real_store_ruid,
> +- split_ruid);
> +- if (idx < 0)
> +- continue;
> +- for (j = idx; j < RELOAD_COMBINE_MAX_USES; j++)
> +- {
> +- reload_combine_split_one_ruid (®_state[i].reg_use[j].ruid,
> +- split_ruid);
> +- }
> +- }
> +-}
> +-
> +-/* Called when we are about to rescan a previously encountered insn with
> +- reload_combine_note_use after modifying some part of it. This clears all
> +- information about uses in that particular insn. */
> +-
> +-static void
> +-reload_combine_purge_insn_uses (rtx insn)
> +-{
> +- unsigned i;
> +-
> +- for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> +- {
> +- int j, k, idx = reg_state[i].use_index;
> +- if (idx < 0)
> +- continue;
> +- j = k = RELOAD_COMBINE_MAX_USES;
> +- while (j-- > idx)
> +- {
> +- if (reg_state[i].reg_use[j].insn != insn)
> +- {
> +- k--;
> +- if (k != j)
> +- reg_state[i].reg_use[k] = reg_state[i].reg_use[j];
> +- }
> +- }
> +- reg_state[i].use_index = k;
> +- }
> +-}
> +-
> +-/* Called when we need to forget about all uses of REGNO after an insn
> +- which is identified by RUID. */
> +-
> +-static void
> +-reload_combine_purge_reg_uses_after_ruid (unsigned regno, int ruid)
> +-{
> +- int j, k, idx = reg_state[regno].use_index;
> +- if (idx < 0)
> +- return;
> +- j = k = RELOAD_COMBINE_MAX_USES;
> +- while (j-- > idx)
> +- {
> +- if (reg_state[regno].reg_use[j].ruid >= ruid)
> +- {
> +- k--;
> +- if (k != j)
> +- reg_state[regno].reg_use[k] = reg_state[regno].reg_use[j];
> +- }
> +- }
> +- reg_state[regno].use_index = k;
> +-}
> +-
> +-/* Find the use of REGNO with the ruid that is highest among those
> +- lower than RUID_LIMIT, and return it if it is the only use of this
> +- reg in the insn. Return NULL otherwise. */
> +-
> +-static struct reg_use *
> +-reload_combine_closest_single_use (unsigned regno, int ruid_limit)
> +-{
> +- int i, best_ruid = 0;
> +- int use_idx = reg_state[regno].use_index;
> +- struct reg_use *retval;
> +-
> +- if (use_idx < 0)
> +- return NULL;
> +- retval = NULL;
> +- for (i = use_idx; i < RELOAD_COMBINE_MAX_USES; i++)
> +- {
> +- struct reg_use *use = reg_state[regno].reg_use + i;
> +- int this_ruid = use->ruid;
> +- if (this_ruid >= ruid_limit)
> +- continue;
> +- if (this_ruid > best_ruid)
> +- {
> +- best_ruid = this_ruid;
> +- retval = use;
> +- }
> +- else if (this_ruid == best_ruid)
> +- retval = NULL;
> +- }
> +- if (last_label_ruid >= best_ruid)
> +- return NULL;
> +- return retval;
> +-}
> +-
> +-/* After we've moved an add insn, fix up any debug insns that occur
> +- between the old location of the add and the new location. REG is
> +- the destination register of the add insn; REPLACEMENT is the
> +- SET_SRC of the add. FROM and TO specify the range in which we
> +- should make this change on debug insns. */
> +-
> +-static void
> +-fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
> +-{
> +- rtx insn;
> +- for (insn = from; insn != to; insn = NEXT_INSN (insn))
> +- {
> +- rtx t;
> +-
> +- if (!DEBUG_INSN_P (insn))
> +- continue;
> +-
> +- t = INSN_VAR_LOCATION_LOC (insn);
> +- t = simplify_replace_rtx (t, reg, replacement);
> +- validate_change (insn, &INSN_VAR_LOCATION_LOC (insn), t, 0);
> +- }
> +-}
> +-
> +-/* Subroutine of reload_combine_recognize_const_pattern. Try to replace REG
> +- with SRC in the insn described by USE, taking costs into account. Return
> +- true if we made the replacement. */
> +-
> +-static bool
> +-try_replace_in_use (struct reg_use *use, rtx reg, rtx src)
> +-{
> +- rtx use_insn = use->insn;
> +- rtx mem = use->containing_mem;
> +- bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
> +-
> +- if (mem != NULL_RTX)
> +- {
> +- addr_space_t as = MEM_ADDR_SPACE (mem);
> +- rtx oldaddr = XEXP (mem, 0);
> +- rtx newaddr = NULL_RTX;
> +- int old_cost = address_cost (oldaddr, GET_MODE (mem), as, speed);
> +- int new_cost;
> +-
> +- newaddr = simplify_replace_rtx (oldaddr, reg, src);
> +- if (memory_address_addr_space_p (GET_MODE (mem), newaddr, as))
> +- {
> +- XEXP (mem, 0) = newaddr;
> +- new_cost = address_cost (newaddr, GET_MODE (mem), as, speed);
> +- XEXP (mem, 0) = oldaddr;
> +- if (new_cost <= old_cost
> +- && validate_change (use_insn,
> +- &XEXP (mem, 0), newaddr, 0))
> +- return true;
> +- }
> +- }
> +- else
> +- {
> +- rtx new_set = single_set (use_insn);
> +- if (new_set
> +- && REG_P (SET_DEST (new_set))
> +- && GET_CODE (SET_SRC (new_set)) == PLUS
> +- && REG_P (XEXP (SET_SRC (new_set), 0))
> +- && CONSTANT_P (XEXP (SET_SRC (new_set), 1)))
> +- {
> +- rtx new_src;
> +- int old_cost = rtx_cost (SET_SRC (new_set), SET, speed);
> +-
> +- gcc_assert (rtx_equal_p (XEXP (SET_SRC (new_set), 0), reg));
> +- new_src = simplify_replace_rtx (SET_SRC (new_set), reg, src);
> +-
> +- if (rtx_cost (new_src, SET, speed) <= old_cost
> +- && validate_change (use_insn, &SET_SRC (new_set),
> +- new_src, 0))
> +- return true;
> +- }
> +- }
> +- return false;
> +-}
> +-
> +-/* Called by reload_combine when scanning INSN. This function tries to detect
> +- patterns where a constant is added to a register, and the result is used
> +- in an address.
> +- Return true if no further processing is needed on INSN; false if it wasn't
> +- recognized and should be handled normally. */
> +-
> +-static bool
> +-reload_combine_recognize_const_pattern (rtx insn)
> +-{
> +- int from_ruid = reload_combine_ruid;
> +- rtx set, pat, reg, src, addreg;
> +- unsigned int regno;
> +- struct reg_use *use;
> +- bool must_move_add;
> +- rtx add_moved_after_insn = NULL_RTX;
> +- int add_moved_after_ruid = 0;
> +- int clobbered_regno = -1;
> +-
> +- set = single_set (insn);
> +- if (set == NULL_RTX)
> +- return false;
> +-
> +- reg = SET_DEST (set);
> +- src = SET_SRC (set);
> +- if (!REG_P (reg)
> +- || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1
> +- || GET_MODE (reg) != Pmode
> +- || reg == stack_pointer_rtx)
> +- return false;
> +-
> +- regno = REGNO (reg);
> +-
> +- /* We look for a REG1 = REG2 + CONSTANT insn, followed by either
> +- uses of REG1 inside an address, or inside another add insn. If
> +- possible and profitable, merge the addition into subsequent
> +- uses. */
> +- if (GET_CODE (src) != PLUS
> +- || !REG_P (XEXP (src, 0))
> +- || !CONSTANT_P (XEXP (src, 1)))
> +- return false;
> +-
> +- addreg = XEXP (src, 0);
> +- must_move_add = rtx_equal_p (reg, addreg);
> +-
> +- pat = PATTERN (insn);
> +- if (must_move_add && set != pat)
> +- {
> +- /* We have to be careful when moving the add; apart from the
> +- single_set there may also be clobbers. Recognize one special
> +- case, that of one clobber alongside the set (likely a clobber
> +- of the CC register). */
> +- gcc_assert (GET_CODE (PATTERN (insn)) == PARALLEL);
> +- if (XVECLEN (pat, 0) != 2 || XVECEXP (pat, 0, 0) != set
> +- || GET_CODE (XVECEXP (pat, 0, 1)) != CLOBBER
> +- || !REG_P (XEXP (XVECEXP (pat, 0, 1), 0)))
> +- return false;
> +- clobbered_regno = REGNO (XEXP (XVECEXP (pat, 0, 1), 0));
> +- }
> +-
> +- do
> +- {
> +- use = reload_combine_closest_single_use (regno, from_ruid);
> +-
> +- if (use)
> +- /* Start the search for the next use from here. */
> +- from_ruid = use->ruid;
> +-
> +- if (use && GET_MODE (*use->usep) == Pmode)
> +- {
> +- bool delete_add = false;
> +- rtx use_insn = use->insn;
> +- int use_ruid = use->ruid;
> +-
> +- /* Avoid moving the add insn past a jump. */
> +- if (must_move_add && use_ruid <= last_jump_ruid)
> +- break;
> +-
> +- /* If the add clobbers another hard reg in parallel, don't move
> +- it past a real set of this hard reg. */
> +- if (must_move_add && clobbered_regno >= 0
> +- && reg_state[clobbered_regno].real_store_ruid >= use_ruid)
> +- break;
> +-
> +- gcc_assert (reg_state[regno].store_ruid <= use_ruid);
> +- /* Avoid moving a use of ADDREG past a point where it is stored. */
> +- if (reg_state[REGNO (addreg)].store_ruid > use_ruid)
> +- break;
> +-
> +- /* We also must not move the addition past an insn that sets
> +- the same register, unless we can combine two add insns. */
> +- if (must_move_add && reg_state[regno].store_ruid == use_ruid)
> +- {
> +- if (use->containing_mem == NULL_RTX)
> +- delete_add = true;
> +- else
> +- break;
> +- }
> +-
> +- if (try_replace_in_use (use, reg, src))
> +- {
> +- reload_combine_purge_insn_uses (use_insn);
> +- reload_combine_note_use (&PATTERN (use_insn), use_insn,
> +- use_ruid, NULL_RTX);
> +-
> +- if (delete_add)
> +- {
> +- fixup_debug_insns (reg, src, insn, use_insn);
> +- delete_insn (insn);
> +- return true;
> +- }
> +- if (must_move_add)
> +- {
> +- add_moved_after_insn = use_insn;
> +- add_moved_after_ruid = use_ruid;
> +- }
> +- continue;
> +- }
> +- }
> +- /* If we get here, we couldn't handle this use. */
> +- if (must_move_add)
> +- break;
> +- }
> +- while (use);
> +-
> +- if (!must_move_add || add_moved_after_insn == NULL_RTX)
> +- /* Process the add normally. */
> +- return false;
> +-
> +- fixup_debug_insns (reg, src, insn, add_moved_after_insn);
> +-
> +- reorder_insns (insn, insn, add_moved_after_insn);
> +- reload_combine_purge_reg_uses_after_ruid (regno, add_moved_after_ruid);
> +- reload_combine_split_ruids (add_moved_after_ruid - 1);
> +- reload_combine_note_use (&PATTERN (insn), insn,
> +- add_moved_after_ruid, NULL_RTX);
> +- reg_state[regno].store_ruid = add_moved_after_ruid;
> +-
> +- return true;
> +-}
> +-
> +-/* Called by reload_combine when scanning INSN. Try to detect a pattern we
> +- can handle and improve. Return true if no further processing is needed on
> +- INSN; false if it wasn't recognized and should be handled normally. */
> +-
> +-static bool
> +-reload_combine_recognize_pattern (rtx insn)
> +-{
> +- rtx set, reg, src;
> +- unsigned int regno;
> +-
> +- set = single_set (insn);
> +- if (set == NULL_RTX)
> +- return false;
> +-
> +- reg = SET_DEST (set);
> +- src = SET_SRC (set);
> +- if (!REG_P (reg)
> +- || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1)
> +- return false;
> +-
> +- regno = REGNO (reg);
> +-
> +- /* Look for (set (REGX) (CONST_INT))
> +- (set (REGX) (PLUS (REGX) (REGY)))
> +- ...
> +- ... (MEM (REGX)) ...
> +- and convert it to
> +- (set (REGZ) (CONST_INT))
> +- ...
> +- ... (MEM (PLUS (REGZ) (REGY)))... .
> +-
> +- First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
> +- and that we know all uses of REGX before it dies.
> +- Also, explicitly check that REGX != REGY; our life information
> +- does not yet show whether REGY changes in this insn. */
> +-
> +- if (GET_CODE (src) == PLUS
> +- && reg_state[regno].all_offsets_match
> +- && last_index_reg != -1
> +- && REG_P (XEXP (src, 1))
> +- && rtx_equal_p (XEXP (src, 0), reg)
> +- && !rtx_equal_p (XEXP (src, 1), reg)
> +- && reg_state[regno].use_index >= 0
> +- && reg_state[regno].use_index < RELOAD_COMBINE_MAX_USES
> +- && last_label_ruid < reg_state[regno].use_ruid)
> +- {
> +- rtx base = XEXP (src, 1);
> +- rtx prev = prev_nonnote_insn (insn);
> +- rtx prev_set = prev ? single_set (prev) : NULL_RTX;
> +- rtx index_reg = NULL_RTX;
> +- rtx reg_sum = NULL_RTX;
> +- int i;
> +-
> +- /* Now we need to set INDEX_REG to an index register (denoted as
> +- REGZ in the illustration above) and REG_SUM to the expression
> +- register+register that we want to use to substitute uses of REG
> +- (typically in MEMs) with. First check REG and BASE for being
> +- index registers; we can use them even if they are not dead. */
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
> +- || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> +- REGNO (base)))
> +- {
> +- index_reg = reg;
> +- reg_sum = src;
> +- }
> +- else
> +- {
> +- /* Otherwise, look for a free index register. Since we have
> +- checked above that neither REG nor BASE are index registers,
> +- if we find anything at all, it will be different from these
> +- two registers. */
> +- for (i = first_index_reg; i <= last_index_reg; i++)
> +- {
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)
> +- && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
> +- && reg_state[i].store_ruid <= reg_state[regno].use_ruid
> +- && (call_used_regs[i] || df_regs_ever_live_p (i))
> +- && (!frame_pointer_needed || i != HARD_FRAME_POINTER_REGNUM)
> +- && !fixed_regs[i] && !global_regs[i]
> +- && hard_regno_nregs[i][GET_MODE (reg)] == 1
> +- && targetm.hard_regno_scratch_ok (i))
> +- {
> +- index_reg = gen_rtx_REG (GET_MODE (reg), i);
> +- reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
> +- break;
> +- }
> +- }
> +- }
> +-
> +- /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
> +- (REGY), i.e. BASE, is not clobbered before the last use we'll
> +- create. */
> +- if (reg_sum
> +- && prev_set
> +- && CONST_INT_P (SET_SRC (prev_set))
> +- && rtx_equal_p (SET_DEST (prev_set), reg)
> +- && (reg_state[REGNO (base)].store_ruid
> +- <= reg_state[regno].use_ruid))
> +- {
> +- /* Change destination register and, if necessary, the constant
> +- value in PREV, the constant loading instruction. */
> +- validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
> +- if (reg_state[regno].offset != const0_rtx)
> +- validate_change (prev,
> +- &SET_SRC (prev_set),
> +- GEN_INT (INTVAL (SET_SRC (prev_set))
> +- + INTVAL (reg_state[regno].offset)),
> +- 1);
> +-
> +- /* Now for every use of REG that we have recorded, replace REG
> +- with REG_SUM. */
> +- for (i = reg_state[regno].use_index;
> +- i < RELOAD_COMBINE_MAX_USES; i++)
> +- validate_unshare_change (reg_state[regno].reg_use[i].insn,
> +- reg_state[regno].reg_use[i].usep,
> +- /* Each change must have its own
> +- replacement. */
> +- reg_sum, 1);
> +-
> +- if (apply_change_group ())
> +- {
> +- struct reg_use *lowest_ruid = NULL;
> +-
> +- /* For every new use of REG_SUM, we have to record the use
> +- of BASE therein, i.e. operand 1. */
> +- for (i = reg_state[regno].use_index;
> +- i < RELOAD_COMBINE_MAX_USES; i++)
> +- {
> +- struct reg_use *use = reg_state[regno].reg_use + i;
> +- reload_combine_note_use (&XEXP (*use->usep, 1), use->insn,
> +- use->ruid, use->containing_mem);
> +- if (lowest_ruid == NULL || use->ruid < lowest_ruid->ruid)
> +- lowest_ruid = use;
> +- }
> +-
> +- fixup_debug_insns (reg, reg_sum, insn, lowest_ruid->insn);
> +-
> +- /* Delete the reg-reg addition. */
> +- delete_insn (insn);
> +-
> +- if (reg_state[regno].offset != const0_rtx)
> +- /* Previous REG_EQUIV / REG_EQUAL notes for PREV
> +- are now invalid. */
> +- remove_reg_equal_equiv_notes (prev);
> +-
> +- reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
> +- return true;
> +- }
> +- }
> +- }
> +- return false;
> +-}
> +-
> + static void
> + reload_combine (void)
> + {
> +- rtx insn, prev;
> ++ rtx insn, set;
> ++ int first_index_reg = -1;
> ++ int last_index_reg = 0;
> + int i;
> + basic_block bb;
> + unsigned int r;
> ++ int last_label_ruid;
> + int min_labelno, n_labels;
> + HARD_REG_SET ever_live_at_start, *label_live;
> +
> ++ /* If reg+reg can be used in offsetable memory addresses, the main chunk of
> ++ reload has already used it where appropriate, so there is no use in
> ++ trying to generate it now. */
> ++ if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
> ++ return;
> ++
> + /* To avoid wasting too much time later searching for an index register,
> + determine the minimum and maximum index register numbers. */
> +- if (INDEX_REG_CLASS == NO_REGS)
> +- last_index_reg = -1;
> +- else if (first_index_reg == -1 && last_index_reg == 0)
> +- {
> +- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
> +- {
> +- if (first_index_reg == -1)
> +- first_index_reg = r;
> +-
> +- last_index_reg = r;
> +- }
> +-
> +- /* If no index register is available, we can quit now. Set LAST_INDEX_REG
> +- to -1 so we'll know to quit early the next time we get here. */
> +- if (first_index_reg == -1)
> +- {
> +- last_index_reg = -1;
> +- return;
> +- }
> +- }
> ++ for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
> ++ {
> ++ if (first_index_reg == -1)
> ++ first_index_reg = r;
> ++
> ++ last_index_reg = r;
> ++ }
> ++
> ++ /* If no index register is available, we can quit now. */
> ++ if (first_index_reg == -1)
> ++ return;
> +
> + /* Set up LABEL_LIVE and EVER_LIVE_AT_START. The register lifetime
> + information is a bit fuzzy immediately after reload, but it's
> +@@ -1278,23 +753,20 @@
> + }
> +
> + /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */
> +- last_label_ruid = last_jump_ruid = reload_combine_ruid = 0;
> ++ last_label_ruid = reload_combine_ruid = 0;
> + for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> + {
> +- reg_state[r].store_ruid = 0;
> +- reg_state[r].real_store_ruid = 0;
> ++ reg_state[r].store_ruid = reload_combine_ruid;
> + if (fixed_regs[r])
> + reg_state[r].use_index = -1;
> + else
> + reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
> + }
> +
> +- for (insn = get_last_insn (); insn; insn = prev)
> ++ for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
> + {
> + rtx note;
> +
> +- prev = PREV_INSN (insn);
> +-
> + /* We cannot do our optimization across labels. Invalidating all the use
> + information we have would be costly, so we just note where the label
> + is and then later disable any optimization that would cross it. */
> +@@ -1305,17 +777,141 @@
> + if (! fixed_regs[r])
> + reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
> +
> +- if (! NONDEBUG_INSN_P (insn))
> ++ if (! INSN_P (insn))
> + continue;
> +
> + reload_combine_ruid++;
> +
> +- if (control_flow_insn_p (insn))
> +- last_jump_ruid = reload_combine_ruid;
> +-
> +- if (reload_combine_recognize_const_pattern (insn)
> +- || reload_combine_recognize_pattern (insn))
> +- continue;
> ++ /* Look for (set (REGX) (CONST_INT))
> ++ (set (REGX) (PLUS (REGX) (REGY)))
> ++ ...
> ++ ... (MEM (REGX)) ...
> ++ and convert it to
> ++ (set (REGZ) (CONST_INT))
> ++ ...
> ++ ... (MEM (PLUS (REGZ) (REGY)))... .
> ++
> ++ First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
> ++ and that we know all uses of REGX before it dies.
> ++ Also, explicitly check that REGX != REGY; our life information
> ++ does not yet show whether REGY changes in this insn. */
> ++ set = single_set (insn);
> ++ if (set != NULL_RTX
> ++ && REG_P (SET_DEST (set))
> ++ && (hard_regno_nregs[REGNO (SET_DEST (set))]
> ++ [GET_MODE (SET_DEST (set))]
> ++ == 1)
> ++ && GET_CODE (SET_SRC (set)) == PLUS
> ++ && REG_P (XEXP (SET_SRC (set), 1))
> ++ && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
> ++ && !rtx_equal_p (XEXP (SET_SRC (set), 1), SET_DEST (set))
> ++ && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
> ++ {
> ++ rtx reg = SET_DEST (set);
> ++ rtx plus = SET_SRC (set);
> ++ rtx base = XEXP (plus, 1);
> ++ rtx prev = prev_nonnote_nondebug_insn (insn);
> ++ rtx prev_set = prev ? single_set (prev) : NULL_RTX;
> ++ unsigned int regno = REGNO (reg);
> ++ rtx index_reg = NULL_RTX;
> ++ rtx reg_sum = NULL_RTX;
> ++
> ++ /* Now we need to set INDEX_REG to an index register (denoted as
> ++ REGZ in the illustration above) and REG_SUM to the expression
> ++ register+register that we want to use to substitute uses of REG
> ++ (typically in MEMs) with. First check REG and BASE for being
> ++ index registers; we can use them even if they are not dead. */
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
> ++ || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> ++ REGNO (base)))
> ++ {
> ++ index_reg = reg;
> ++ reg_sum = plus;
> ++ }
> ++ else
> ++ {
> ++ /* Otherwise, look for a free index register. Since we have
> ++ checked above that neither REG nor BASE are index registers,
> ++ if we find anything at all, it will be different from these
> ++ two registers. */
> ++ for (i = first_index_reg; i <= last_index_reg; i++)
> ++ {
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> ++ i)
> ++ && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
> ++ && reg_state[i].store_ruid <= reg_state[regno].use_ruid
> ++ && hard_regno_nregs[i][GET_MODE (reg)] == 1)
> ++ {
> ++ index_reg = gen_rtx_REG (GET_MODE (reg), i);
> ++ reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
> ++ break;
> ++ }
> ++ }
> ++ }
> ++
> ++ /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
> ++ (REGY), i.e. BASE, is not clobbered before the last use we'll
> ++ create. */
> ++ if (reg_sum
> ++ && prev_set
> ++ && CONST_INT_P (SET_SRC (prev_set))
> ++ && rtx_equal_p (SET_DEST (prev_set), reg)
> ++ && reg_state[regno].use_index >= 0
> ++ && (reg_state[REGNO (base)].store_ruid
> ++ <= reg_state[regno].use_ruid))
> ++ {
> ++ int i;
> ++
> ++ /* Change destination register and, if necessary, the constant
> ++ value in PREV, the constant loading instruction. */
> ++ validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
> ++ if (reg_state[regno].offset != const0_rtx)
> ++ validate_change (prev,
> ++ &SET_SRC (prev_set),
> ++ GEN_INT (INTVAL (SET_SRC (prev_set))
> ++ + INTVAL (reg_state[regno].offset)),
> ++ 1);
> ++
> ++ /* Now for every use of REG that we have recorded, replace REG
> ++ with REG_SUM. */
> ++ for (i = reg_state[regno].use_index;
> ++ i < RELOAD_COMBINE_MAX_USES; i++)
> ++ validate_unshare_change (reg_state[regno].reg_use[i].insn,
> ++ reg_state[regno].reg_use[i].usep,
> ++ /* Each change must have its own
> ++ replacement. */
> ++ reg_sum, 1);
> ++
> ++ if (apply_change_group ())
> ++ {
> ++ /* For every new use of REG_SUM, we have to record the use
> ++ of BASE therein, i.e. operand 1. */
> ++ for (i = reg_state[regno].use_index;
> ++ i < RELOAD_COMBINE_MAX_USES; i++)
> ++ reload_combine_note_use
> ++ (&XEXP (*reg_state[regno].reg_use[i].usep, 1),
> ++ reg_state[regno].reg_use[i].insn);
> ++
> ++ if (reg_state[REGNO (base)].use_ruid
> ++ > reg_state[regno].use_ruid)
> ++ reg_state[REGNO (base)].use_ruid
> ++ = reg_state[regno].use_ruid;
> ++
> ++ /* Delete the reg-reg addition. */
> ++ delete_insn (insn);
> ++
> ++ if (reg_state[regno].offset != const0_rtx)
> ++ /* Previous REG_EQUIV / REG_EQUAL notes for PREV
> ++ are now invalid. */
> ++ remove_reg_equal_equiv_notes (prev);
> ++
> ++ reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
> ++ reg_state[REGNO (index_reg)].store_ruid
> ++ = reload_combine_ruid;
> ++ continue;
> ++ }
> ++ }
> ++ }
> +
> + note_stores (PATTERN (insn), reload_combine_note_store, NULL);
> +
> +@@ -1371,8 +967,7 @@
> + reg_state[i].use_index = -1;
> + }
> +
> +- reload_combine_note_use (&PATTERN (insn), insn,
> +- reload_combine_ruid, NULL_RTX);
> ++ reload_combine_note_use (&PATTERN (insn), insn);
> + for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
> + {
> + if (REG_NOTE_KIND (note) == REG_INC
> +@@ -1381,7 +976,6 @@
> + int regno = REGNO (XEXP (note, 0));
> +
> + reg_state[regno].store_ruid = reload_combine_ruid;
> +- reg_state[regno].real_store_ruid = reload_combine_ruid;
> + reg_state[regno].use_index = -1;
> + }
> + }
> +@@ -1391,8 +985,8 @@
> + }
> +
> + /* Check if DST is a register or a subreg of a register; if it is,
> +- update store_ruid, real_store_ruid and use_index in the reg_state
> +- structure accordingly. Called via note_stores from reload_combine. */
> ++ update reg_state[regno].store_ruid and reg_state[regno].use_index
> ++ accordingly. Called via note_stores from reload_combine. */
> +
> + static void
> + reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
> +@@ -1416,14 +1010,14 @@
> + /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
> + careful with registers / register parts that are not full words.
> + Similarly for ZERO_EXTRACT. */
> +- if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
> ++ if (GET_CODE (set) != SET
> ++ || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
> + || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
> + {
> + for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
> + {
> + reg_state[i].use_index = -1;
> + reg_state[i].store_ruid = reload_combine_ruid;
> +- reg_state[i].real_store_ruid = reload_combine_ruid;
> + }
> + }
> + else
> +@@ -1431,8 +1025,6 @@
> + for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
> + {
> + reg_state[i].store_ruid = reload_combine_ruid;
> +- if (GET_CODE (set) == SET)
> +- reg_state[i].real_store_ruid = reload_combine_ruid;
> + reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
> + }
> + }
> +@@ -1443,7 +1035,7 @@
> + *XP is the pattern of INSN, or a part of it.
> + Called from reload_combine, and recursively by itself. */
> + static void
> +-reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
> ++reload_combine_note_use (rtx *xp, rtx insn)
> + {
> + rtx x = *xp;
> + enum rtx_code code = x->code;
> +@@ -1456,7 +1048,7 @@
> + case SET:
> + if (REG_P (SET_DEST (x)))
> + {
> +- reload_combine_note_use (&SET_SRC (x), insn, ruid, NULL_RTX);
> ++ reload_combine_note_use (&SET_SRC (x), insn);
> + return;
> + }
> + break;
> +@@ -1512,11 +1104,6 @@
> + return;
> + }
> +
> +- /* We may be called to update uses in previously seen insns.
> +- Don't add uses beyond the last store we saw. */
> +- if (ruid < reg_state[regno].store_ruid)
> +- return;
> +-
> + /* If this register is already used in some unknown fashion, we
> + can't do anything.
> + If we decrement the index from zero to -1, we can't store more
> +@@ -1525,34 +1112,29 @@
> + if (use_index < 0)
> + return;
> +
> +- if (use_index == RELOAD_COMBINE_MAX_USES - 1)
> ++ if (use_index != RELOAD_COMBINE_MAX_USES - 1)
> ++ {
> ++ /* We have found another use for a register that is already
> ++ used later. Check if the offsets match; if not, mark the
> ++ register as used in an unknown fashion. */
> ++ if (! rtx_equal_p (offset, reg_state[regno].offset))
> ++ {
> ++ reg_state[regno].use_index = -1;
> ++ return;
> ++ }
> ++ }
> ++ else
> + {
> + /* This is the first use of this register we have seen since we
> + marked it as dead. */
> + reg_state[regno].offset = offset;
> +- reg_state[regno].all_offsets_match = true;
> +- reg_state[regno].use_ruid = ruid;
> +- }
> +- else
> +- {
> +- if (reg_state[regno].use_ruid > ruid)
> +- reg_state[regno].use_ruid = ruid;
> +-
> +- if (! rtx_equal_p (offset, reg_state[regno].offset))
> +- reg_state[regno].all_offsets_match = false;
> +- }
> +-
> ++ reg_state[regno].use_ruid = reload_combine_ruid;
> ++ }
> + reg_state[regno].reg_use[use_index].insn = insn;
> +- reg_state[regno].reg_use[use_index].ruid = ruid;
> +- reg_state[regno].reg_use[use_index].containing_mem = containing_mem;
> + reg_state[regno].reg_use[use_index].usep = xp;
> + return;
> + }
> +
> +- case MEM:
> +- containing_mem = x;
> +- break;
> +-
> + default:
> + break;
> + }
> +@@ -1562,12 +1144,11 @@
> + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
> + {
> + if (fmt[i] == 'e')
> +- reload_combine_note_use (&XEXP (x, i), insn, ruid, containing_mem);
> ++ reload_combine_note_use (&XEXP (x, i), insn);
> + else if (fmt[i] == 'E')
> + {
> + for (j = XVECLEN (x, i) - 1; j >= 0; j--)
> +- reload_combine_note_use (&XVECEXP (x, i, j), insn, ruid,
> +- containing_mem);
> ++ reload_combine_note_use (&XVECEXP (x, i, j), insn);
> + }
> + }
> + }
> +@@ -1615,10 +1196,9 @@
> + while REG is known to already have value (SYM + offset).
> + This function tries to change INSN into an add instruction
> + (set (REG) (plus (REG) (OFF - offset))) using the known value.
> +- It also updates the information about REG's known value.
> +- Return true if we made a change. */
> ++ It also updates the information about REG's known value. */
> +
> +-static bool
> ++static void
> + move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
> + {
> + rtx pat = PATTERN (insn);
> +@@ -1627,7 +1207,6 @@
> + rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[regno],
> + GET_MODE (reg));
> + bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
> +- bool changed = false;
> +
> + /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
> + use (set (reg) (reg)) instead.
> +@@ -1642,13 +1221,13 @@
> + (reg)), would be discarded. Maybe we should
> + try a truncMN pattern? */
> + if (INTVAL (off) == reg_offset [regno])
> +- changed = validate_change (insn, &SET_SRC (pat), reg, 0);
> ++ validate_change (insn, &SET_SRC (pat), reg, 0);
> + }
> + else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
> + && have_add2_insn (reg, new_src))
> + {
> + rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
> +- changed = validate_change (insn, &SET_SRC (pat), tem, 0);
> ++ validate_change (insn, &SET_SRC (pat), tem, 0);
> + }
> + else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
> + {
> +@@ -1673,9 +1252,8 @@
> + gen_rtx_STRICT_LOW_PART (VOIDmode,
> + narrow_reg),
> + narrow_src);
> +- changed = validate_change (insn, &PATTERN (insn),
> +- new_set, 0);
> +- if (changed)
> ++ if (validate_change (insn, &PATTERN (insn),
> ++ new_set, 0))
> + break;
> + }
> + }
> +@@ -1685,7 +1263,6 @@
> + reg_mode[regno] = GET_MODE (reg);
> + reg_symbol_ref[regno] = sym;
> + reg_offset[regno] = INTVAL (off);
> +- return changed;
> + }
> +
> +
> +@@ -1695,10 +1272,9 @@
> + value (SYM + offset) and change INSN into an add instruction
> + (set (REG) (plus (the found register) (OFF - offset))) if such
> + a register is found. It also updates the information about
> +- REG's known value.
> +- Return true iff we made a change. */
> ++ REG's known value. */
> +
> +-static bool
> ++static void
> + move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
> + {
> + rtx pat = PATTERN (insn);
> +@@ -1708,7 +1284,6 @@
> + int min_regno;
> + bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
> + int i;
> +- bool changed = false;
> +
> + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> + if (reg_set_luid[i] > move2add_last_label_luid
> +@@ -1753,25 +1328,20 @@
> + GET_MODE (reg));
> + tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src);
> + }
> +- if (validate_change (insn, &SET_SRC (pat), tem, 0))
> +- changed = true;
> ++ validate_change (insn, &SET_SRC (pat), tem, 0);
> + }
> + reg_set_luid[regno] = move2add_luid;
> + reg_base_reg[regno] = -1;
> + reg_mode[regno] = GET_MODE (reg);
> + reg_symbol_ref[regno] = sym;
> + reg_offset[regno] = INTVAL (off);
> +- return changed;
> + }
> +
> +-/* Convert move insns with constant inputs to additions if they are cheaper.
> +- Return true if any changes were made. */
> +-static bool
> ++static void
> + reload_cse_move2add (rtx first)
> + {
> + int i;
> + rtx insn;
> +- bool changed = false;
> +
> + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
> + {
> +@@ -1832,7 +1402,7 @@
> + && reg_base_reg[regno] < 0
> + && reg_symbol_ref[regno] == NULL_RTX)
> + {
> +- changed |= move2add_use_add2_insn (reg, NULL_RTX, src, insn);
> ++ move2add_use_add2_insn (reg, NULL_RTX, src, insn);
> + continue;
> + }
> +
> +@@ -1893,7 +1463,6 @@
> + }
> + if (success)
> + delete_insn (insn);
> +- changed |= success;
> + insn = next;
> + reg_mode[regno] = GET_MODE (reg);
> + reg_offset[regno] =
> +@@ -1939,12 +1508,12 @@
> + && reg_base_reg[regno] < 0
> + && reg_symbol_ref[regno] != NULL_RTX
> + && rtx_equal_p (sym, reg_symbol_ref[regno]))
> +- changed |= move2add_use_add2_insn (reg, sym, off, insn);
> ++ move2add_use_add2_insn (reg, sym, off, insn);
> +
> + /* Otherwise, we have to find a register whose value is sum
> + of sym and some constant value. */
> + else
> +- changed |= move2add_use_add3_insn (reg, sym, off, insn);
> ++ move2add_use_add3_insn (reg, sym, off, insn);
> +
> + continue;
> + }
> +@@ -1999,7 +1568,6 @@
> + }
> + }
> + }
> +- return changed;
> + }
> +
> + /* SET is a SET or CLOBBER that sets DST. DATA is the insn which
> +
> diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99432.patch
> new file mode 100644
> index 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 (®_state[i].use_ruid, split_ruid);
> ++ reload_combine_split_one_ruid (®_state[i].store_ruid, split_ruid);
> ++ reload_combine_split_one_ruid (®_state[i].real_store_ruid,
> ++ split_ruid);
> ++ if (idx < 0)
> ++ continue;
> ++ for (j = idx; j < RELOAD_COMBINE_MAX_USES; j++)
> ++ {
> ++ reload_combine_split_one_ruid (®_state[i].reg_use[j].ruid,
> ++ split_ruid);
> ++ }
> ++ }
> ++}
> ++
> ++/* Called when we are about to rescan a previously encountered insn with
> ++ reload_combine_note_use after modifying some part of it. This clears all
> ++ information about uses in that particular insn. */
> ++
> ++static void
> ++reload_combine_purge_insn_uses (rtx insn)
> ++{
> ++ unsigned i;
> ++
> ++ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> ++ {
> ++ int j, k, idx = reg_state[i].use_index;
> ++ if (idx < 0)
> ++ continue;
> ++ j = k = RELOAD_COMBINE_MAX_USES;
> ++ while (j-- > idx)
> ++ {
> ++ if (reg_state[i].reg_use[j].insn != insn)
> ++ {
> ++ k--;
> ++ if (k != j)
> ++ reg_state[i].reg_use[k] = reg_state[i].reg_use[j];
> ++ }
> ++ }
> ++ reg_state[i].use_index = k;
> ++ }
> ++}
> ++
> ++/* Called when we need to forget about all uses of REGNO after an insn
> ++ which is identified by RUID. */
> ++
> ++static void
> ++reload_combine_purge_reg_uses_after_ruid (unsigned regno, int ruid)
> ++{
> ++ int j, k, idx = reg_state[regno].use_index;
> ++ if (idx < 0)
> ++ return;
> ++ j = k = RELOAD_COMBINE_MAX_USES;
> ++ while (j-- > idx)
> ++ {
> ++ if (reg_state[regno].reg_use[j].ruid >= ruid)
> ++ {
> ++ k--;
> ++ if (k != j)
> ++ reg_state[regno].reg_use[k] = reg_state[regno].reg_use[j];
> ++ }
> ++ }
> ++ reg_state[regno].use_index = k;
> ++}
> ++
> ++/* Find the use of REGNO with the ruid that is highest among those
> ++ lower than RUID_LIMIT, and return it if it is the only use of this
> ++ reg in the insn. Return NULL otherwise. */
> ++
> ++static struct reg_use *
> ++reload_combine_closest_single_use (unsigned regno, int ruid_limit)
> ++{
> ++ int i, best_ruid = 0;
> ++ int use_idx = reg_state[regno].use_index;
> ++ struct reg_use *retval;
> ++
> ++ if (use_idx < 0)
> ++ return NULL;
> ++ retval = NULL;
> ++ for (i = use_idx; i < RELOAD_COMBINE_MAX_USES; i++)
> ++ {
> ++ struct reg_use *use = reg_state[regno].reg_use + i;
> ++ int this_ruid = use->ruid;
> ++ if (this_ruid >= ruid_limit)
> ++ continue;
> ++ if (this_ruid > best_ruid)
> ++ {
> ++ best_ruid = this_ruid;
> ++ retval = use;
> ++ }
> ++ else if (this_ruid == best_ruid)
> ++ retval = NULL;
> ++ }
> ++ if (last_label_ruid >= best_ruid)
> ++ return NULL;
> ++ return retval;
> ++}
> ++
> ++/* After we've moved an add insn, fix up any debug insns that occur
> ++ between the old location of the add and the new location. REG is
> ++ the destination register of the add insn; REPLACEMENT is the
> ++ SET_SRC of the add. FROM and TO specify the range in which we
> ++ should make this change on debug insns. */
> ++
> ++static void
> ++fixup_debug_insns (rtx reg, rtx replacement, rtx from, rtx to)
> ++{
> ++ rtx insn;
> ++ for (insn = from; insn != to; insn = NEXT_INSN (insn))
> ++ {
> ++ rtx t;
> ++
> ++ if (!DEBUG_INSN_P (insn))
> ++ continue;
> ++
> ++ t = INSN_VAR_LOCATION_LOC (insn);
> ++ t = simplify_replace_rtx (t, reg, replacement);
> ++ validate_change (insn, &INSN_VAR_LOCATION_LOC (insn), t, 0);
> ++ }
> ++}
> ++
> ++/* Subroutine of reload_combine_recognize_const_pattern. Try to replace REG
> ++ with SRC in the insn described by USE, taking costs into account. Return
> ++ true if we made the replacement. */
> ++
> ++static bool
> ++try_replace_in_use (struct reg_use *use, rtx reg, rtx src)
> ++{
> ++ rtx use_insn = use->insn;
> ++ rtx mem = use->containing_mem;
> ++ bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (use_insn));
> ++
> ++ if (mem != NULL_RTX)
> ++ {
> ++ addr_space_t as = MEM_ADDR_SPACE (mem);
> ++ rtx oldaddr = XEXP (mem, 0);
> ++ rtx newaddr = NULL_RTX;
> ++ int old_cost = address_cost (oldaddr, GET_MODE (mem), as, speed);
> ++ int new_cost;
> ++
> ++ newaddr = simplify_replace_rtx (oldaddr, reg, src);
> ++ if (memory_address_addr_space_p (GET_MODE (mem), newaddr, as))
> ++ {
> ++ XEXP (mem, 0) = newaddr;
> ++ new_cost = address_cost (newaddr, GET_MODE (mem), as, speed);
> ++ XEXP (mem, 0) = oldaddr;
> ++ if (new_cost <= old_cost
> ++ && validate_change (use_insn,
> ++ &XEXP (mem, 0), newaddr, 0))
> ++ return true;
> ++ }
> ++ }
> ++ else
> ++ {
> ++ rtx new_set = single_set (use_insn);
> ++ if (new_set
> ++ && REG_P (SET_DEST (new_set))
> ++ && GET_CODE (SET_SRC (new_set)) == PLUS
> ++ && REG_P (XEXP (SET_SRC (new_set), 0))
> ++ && CONSTANT_P (XEXP (SET_SRC (new_set), 1)))
> ++ {
> ++ rtx new_src;
> ++ int old_cost = rtx_cost (SET_SRC (new_set), SET, speed);
> ++
> ++ gcc_assert (rtx_equal_p (XEXP (SET_SRC (new_set), 0), reg));
> ++ new_src = simplify_replace_rtx (SET_SRC (new_set), reg, src);
> ++
> ++ if (rtx_cost (new_src, SET, speed) <= old_cost
> ++ && validate_change (use_insn, &SET_SRC (new_set),
> ++ new_src, 0))
> ++ return true;
> ++ }
> ++ }
> ++ return false;
> ++}
> ++
> ++/* Called by reload_combine when scanning INSN. This function tries to detect
> ++ patterns where a constant is added to a register, and the result is used
> ++ in an address.
> ++ Return true if no further processing is needed on INSN; false if it wasn't
> ++ recognized and should be handled normally. */
> ++
> ++static bool
> ++reload_combine_recognize_const_pattern (rtx insn)
> ++{
> ++ int from_ruid = reload_combine_ruid;
> ++ rtx set, pat, reg, src, addreg;
> ++ unsigned int regno;
> ++ struct reg_use *use;
> ++ bool must_move_add;
> ++ rtx add_moved_after_insn = NULL_RTX;
> ++ int add_moved_after_ruid = 0;
> ++ int clobbered_regno = -1;
> ++
> ++ set = single_set (insn);
> ++ if (set == NULL_RTX)
> ++ return false;
> ++
> ++ reg = SET_DEST (set);
> ++ src = SET_SRC (set);
> ++ if (!REG_P (reg)
> ++ || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1
> ++ || GET_MODE (reg) != Pmode
> ++ || reg == stack_pointer_rtx)
> ++ return false;
> ++
> ++ regno = REGNO (reg);
> ++
> ++ /* We look for a REG1 = REG2 + CONSTANT insn, followed by either
> ++ uses of REG1 inside an address, or inside another add insn. If
> ++ possible and profitable, merge the addition into subsequent
> ++ uses. */
> ++ if (GET_CODE (src) != PLUS
> ++ || !REG_P (XEXP (src, 0))
> ++ || !CONSTANT_P (XEXP (src, 1)))
> ++ return false;
> ++
> ++ addreg = XEXP (src, 0);
> ++ must_move_add = rtx_equal_p (reg, addreg);
> ++
> ++ pat = PATTERN (insn);
> ++ if (must_move_add && set != pat)
> ++ {
> ++ /* We have to be careful when moving the add; apart from the
> ++ single_set there may also be clobbers. Recognize one special
> ++ case, that of one clobber alongside the set (likely a clobber
> ++ of the CC register). */
> ++ gcc_assert (GET_CODE (PATTERN (insn)) == PARALLEL);
> ++ if (XVECLEN (pat, 0) != 2 || XVECEXP (pat, 0, 0) != set
> ++ || GET_CODE (XVECEXP (pat, 0, 1)) != CLOBBER
> ++ || !REG_P (XEXP (XVECEXP (pat, 0, 1), 0)))
> ++ return false;
> ++ clobbered_regno = REGNO (XEXP (XVECEXP (pat, 0, 1), 0));
> ++ }
> ++
> ++ do
> ++ {
> ++ use = reload_combine_closest_single_use (regno, from_ruid);
> ++
> ++ if (use)
> ++ /* Start the search for the next use from here. */
> ++ from_ruid = use->ruid;
> ++
> ++ if (use && GET_MODE (*use->usep) == Pmode)
> ++ {
> ++ bool delete_add = false;
> ++ rtx use_insn = use->insn;
> ++ int use_ruid = use->ruid;
> ++
> ++ /* Avoid moving the add insn past a jump. */
> ++ if (must_move_add && use_ruid <= last_jump_ruid)
> ++ break;
> ++
> ++ /* If the add clobbers another hard reg in parallel, don't move
> ++ it past a real set of this hard reg. */
> ++ if (must_move_add && clobbered_regno >= 0
> ++ && reg_state[clobbered_regno].real_store_ruid >= use_ruid)
> ++ break;
> ++
> ++ gcc_assert (reg_state[regno].store_ruid <= use_ruid);
> ++ /* Avoid moving a use of ADDREG past a point where it is stored. */
> ++ if (reg_state[REGNO (addreg)].store_ruid > use_ruid)
> ++ break;
> ++
> ++ /* We also must not move the addition past an insn that sets
> ++ the same register, unless we can combine two add insns. */
> ++ if (must_move_add && reg_state[regno].store_ruid == use_ruid)
> ++ {
> ++ if (use->containing_mem == NULL_RTX)
> ++ delete_add = true;
> ++ else
> ++ break;
> ++ }
> ++
> ++ if (try_replace_in_use (use, reg, src))
> ++ {
> ++ reload_combine_purge_insn_uses (use_insn);
> ++ reload_combine_note_use (&PATTERN (use_insn), use_insn,
> ++ use_ruid, NULL_RTX);
> ++
> ++ if (delete_add)
> ++ {
> ++ fixup_debug_insns (reg, src, insn, use_insn);
> ++ delete_insn (insn);
> ++ return true;
> ++ }
> ++ if (must_move_add)
> ++ {
> ++ add_moved_after_insn = use_insn;
> ++ add_moved_after_ruid = use_ruid;
> ++ }
> ++ continue;
> ++ }
> ++ }
> ++ /* If we get here, we couldn't handle this use. */
> ++ if (must_move_add)
> ++ break;
> ++ }
> ++ while (use);
> ++
> ++ if (!must_move_add || add_moved_after_insn == NULL_RTX)
> ++ /* Process the add normally. */
> ++ return false;
> ++
> ++ fixup_debug_insns (reg, src, insn, add_moved_after_insn);
> ++
> ++ reorder_insns (insn, insn, add_moved_after_insn);
> ++ reload_combine_purge_reg_uses_after_ruid (regno, add_moved_after_ruid);
> ++ reload_combine_split_ruids (add_moved_after_ruid - 1);
> ++ reload_combine_note_use (&PATTERN (insn), insn,
> ++ add_moved_after_ruid, NULL_RTX);
> ++ reg_state[regno].store_ruid = add_moved_after_ruid;
> ++
> ++ return true;
> ++}
> ++
> ++/* Called by reload_combine when scanning INSN. Try to detect a pattern we
> ++ can handle and improve. Return true if no further processing is needed on
> ++ INSN; false if it wasn't recognized and should be handled normally. */
> ++
> ++static bool
> ++reload_combine_recognize_pattern (rtx insn)
> ++{
> ++ rtx set, reg, src;
> ++ unsigned int regno;
> ++
> ++ set = single_set (insn);
> ++ if (set == NULL_RTX)
> ++ return false;
> ++
> ++ reg = SET_DEST (set);
> ++ src = SET_SRC (set);
> ++ if (!REG_P (reg)
> ++ || hard_regno_nregs[REGNO (reg)][GET_MODE (reg)] != 1)
> ++ return false;
> ++
> ++ regno = REGNO (reg);
> ++
> ++ /* Look for (set (REGX) (CONST_INT))
> ++ (set (REGX) (PLUS (REGX) (REGY)))
> ++ ...
> ++ ... (MEM (REGX)) ...
> ++ and convert it to
> ++ (set (REGZ) (CONST_INT))
> ++ ...
> ++ ... (MEM (PLUS (REGZ) (REGY)))... .
> ++
> ++ First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
> ++ and that we know all uses of REGX before it dies.
> ++ Also, explicitly check that REGX != REGY; our life information
> ++ does not yet show whether REGY changes in this insn. */
> ++
> ++ if (GET_CODE (src) == PLUS
> ++ && reg_state[regno].all_offsets_match
> ++ && last_index_reg != -1
> ++ && REG_P (XEXP (src, 1))
> ++ && rtx_equal_p (XEXP (src, 0), reg)
> ++ && !rtx_equal_p (XEXP (src, 1), reg)
> ++ && reg_state[regno].use_index >= 0
> ++ && reg_state[regno].use_index < RELOAD_COMBINE_MAX_USES
> ++ && last_label_ruid < reg_state[regno].use_ruid)
> ++ {
> ++ rtx base = XEXP (src, 1);
> ++ rtx prev = prev_nonnote_insn (insn);
> ++ rtx prev_set = prev ? single_set (prev) : NULL_RTX;
> ++ rtx index_reg = NULL_RTX;
> ++ rtx reg_sum = NULL_RTX;
> ++ int i;
> ++
> ++ /* Now we need to set INDEX_REG to an index register (denoted as
> ++ REGZ in the illustration above) and REG_SUM to the expression
> ++ register+register that we want to use to substitute uses of REG
> ++ (typically in MEMs) with. First check REG and BASE for being
> ++ index registers; we can use them even if they are not dead. */
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
> ++ || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> ++ REGNO (base)))
> ++ {
> ++ index_reg = reg;
> ++ reg_sum = src;
> ++ }
> ++ else
> ++ {
> ++ /* Otherwise, look for a free index register. Since we have
> ++ checked above that neither REG nor BASE are index registers,
> ++ if we find anything at all, it will be different from these
> ++ two registers. */
> ++ for (i = first_index_reg; i <= last_index_reg; i++)
> ++ {
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], i)
> ++ && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
> ++ && reg_state[i].store_ruid <= reg_state[regno].use_ruid
> ++ && (call_used_regs[i] || df_regs_ever_live_p (i))
> ++ && (!frame_pointer_needed || i != HARD_FRAME_POINTER_REGNUM)
> ++ && !fixed_regs[i] && !global_regs[i]
> ++ && hard_regno_nregs[i][GET_MODE (reg)] == 1
> ++ && targetm.hard_regno_scratch_ok (i))
> ++ {
> ++ index_reg = gen_rtx_REG (GET_MODE (reg), i);
> ++ reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
> ++ break;
> ++ }
> ++ }
> ++ }
> ++
> ++ /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
> ++ (REGY), i.e. BASE, is not clobbered before the last use we'll
> ++ create. */
> ++ if (reg_sum
> ++ && prev_set
> ++ && CONST_INT_P (SET_SRC (prev_set))
> ++ && rtx_equal_p (SET_DEST (prev_set), reg)
> ++ && (reg_state[REGNO (base)].store_ruid
> ++ <= reg_state[regno].use_ruid))
> ++ {
> ++ /* Change destination register and, if necessary, the constant
> ++ value in PREV, the constant loading instruction. */
> ++ validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
> ++ if (reg_state[regno].offset != const0_rtx)
> ++ validate_change (prev,
> ++ &SET_SRC (prev_set),
> ++ GEN_INT (INTVAL (SET_SRC (prev_set))
> ++ + INTVAL (reg_state[regno].offset)),
> ++ 1);
> ++
> ++ /* Now for every use of REG that we have recorded, replace REG
> ++ with REG_SUM. */
> ++ for (i = reg_state[regno].use_index;
> ++ i < RELOAD_COMBINE_MAX_USES; i++)
> ++ validate_unshare_change (reg_state[regno].reg_use[i].insn,
> ++ reg_state[regno].reg_use[i].usep,
> ++ /* Each change must have its own
> ++ replacement. */
> ++ reg_sum, 1);
> ++
> ++ if (apply_change_group ())
> ++ {
> ++ struct reg_use *lowest_ruid = NULL;
> ++
> ++ /* For every new use of REG_SUM, we have to record the use
> ++ of BASE therein, i.e. operand 1. */
> ++ for (i = reg_state[regno].use_index;
> ++ i < RELOAD_COMBINE_MAX_USES; i++)
> ++ {
> ++ struct reg_use *use = reg_state[regno].reg_use + i;
> ++ reload_combine_note_use (&XEXP (*use->usep, 1), use->insn,
> ++ use->ruid, use->containing_mem);
> ++ if (lowest_ruid == NULL || use->ruid < lowest_ruid->ruid)
> ++ lowest_ruid = use;
> ++ }
> ++
> ++ fixup_debug_insns (reg, reg_sum, insn, lowest_ruid->insn);
> ++
> ++ /* Delete the reg-reg addition. */
> ++ delete_insn (insn);
> ++
> ++ if (reg_state[regno].offset != const0_rtx)
> ++ /* Previous REG_EQUIV / REG_EQUAL notes for PREV
> ++ are now invalid. */
> ++ remove_reg_equal_equiv_notes (prev);
> ++
> ++ reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
> ++ return true;
> ++ }
> ++ }
> ++ }
> ++ return false;
> ++}
> ++
> + static void
> + reload_combine (void)
> + {
> +- rtx insn, set;
> +- int first_index_reg = -1;
> +- int last_index_reg = 0;
> ++ rtx insn, prev;
> + int i;
> + basic_block bb;
> + unsigned int r;
> +- int last_label_ruid;
> + int min_labelno, n_labels;
> + HARD_REG_SET ever_live_at_start, *label_live;
> +
> +- /* If reg+reg can be used in offsetable memory addresses, the main chunk of
> +- reload has already used it where appropriate, so there is no use in
> +- trying to generate it now. */
> +- if (double_reg_address_ok && INDEX_REG_CLASS != NO_REGS)
> +- return;
> +-
> + /* To avoid wasting too much time later searching for an index register,
> + determine the minimum and maximum index register numbers. */
> +- for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
> +- {
> +- if (first_index_reg == -1)
> +- first_index_reg = r;
> +-
> +- last_index_reg = r;
> +- }
> +-
> +- /* If no index register is available, we can quit now. */
> +- if (first_index_reg == -1)
> +- return;
> ++ if (INDEX_REG_CLASS == NO_REGS)
> ++ last_index_reg = -1;
> ++ else if (first_index_reg == -1 && last_index_reg == 0)
> ++ {
> ++ for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> ++ if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], r))
> ++ {
> ++ if (first_index_reg == -1)
> ++ first_index_reg = r;
> ++
> ++ last_index_reg = r;
> ++ }
> ++
> ++ /* If no index register is available, we can quit now. Set LAST_INDEX_REG
> ++ to -1 so we'll know to quit early the next time we get here. */
> ++ if (first_index_reg == -1)
> ++ {
> ++ last_index_reg = -1;
> ++ return;
> ++ }
> ++ }
> +
> + /* Set up LABEL_LIVE and EVER_LIVE_AT_START. The register lifetime
> + information is a bit fuzzy immediately after reload, but it's
> +@@ -753,20 +1278,23 @@
> + }
> +
> + /* Initialize last_label_ruid, reload_combine_ruid and reg_state. */
> +- last_label_ruid = reload_combine_ruid = 0;
> ++ last_label_ruid = last_jump_ruid = reload_combine_ruid = 0;
> + for (r = 0; r < FIRST_PSEUDO_REGISTER; r++)
> + {
> +- reg_state[r].store_ruid = reload_combine_ruid;
> ++ reg_state[r].store_ruid = 0;
> ++ reg_state[r].real_store_ruid = 0;
> + if (fixed_regs[r])
> + reg_state[r].use_index = -1;
> + else
> + reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
> + }
> +
> +- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
> ++ for (insn = get_last_insn (); insn; insn = prev)
> + {
> + rtx note;
> +
> ++ prev = PREV_INSN (insn);
> ++
> + /* We cannot do our optimization across labels. Invalidating all the use
> + information we have would be costly, so we just note where the label
> + is and then later disable any optimization that would cross it. */
> +@@ -777,141 +1305,17 @@
> + if (! fixed_regs[r])
> + reg_state[r].use_index = RELOAD_COMBINE_MAX_USES;
> +
> +- if (! INSN_P (insn))
> ++ if (! NONDEBUG_INSN_P (insn))
> + continue;
> +
> + reload_combine_ruid++;
> +
> +- /* Look for (set (REGX) (CONST_INT))
> +- (set (REGX) (PLUS (REGX) (REGY)))
> +- ...
> +- ... (MEM (REGX)) ...
> +- and convert it to
> +- (set (REGZ) (CONST_INT))
> +- ...
> +- ... (MEM (PLUS (REGZ) (REGY)))... .
> +-
> +- First, check that we have (set (REGX) (PLUS (REGX) (REGY)))
> +- and that we know all uses of REGX before it dies.
> +- Also, explicitly check that REGX != REGY; our life information
> +- does not yet show whether REGY changes in this insn. */
> +- set = single_set (insn);
> +- if (set != NULL_RTX
> +- && REG_P (SET_DEST (set))
> +- && (hard_regno_nregs[REGNO (SET_DEST (set))]
> +- [GET_MODE (SET_DEST (set))]
> +- == 1)
> +- && GET_CODE (SET_SRC (set)) == PLUS
> +- && REG_P (XEXP (SET_SRC (set), 1))
> +- && rtx_equal_p (XEXP (SET_SRC (set), 0), SET_DEST (set))
> +- && !rtx_equal_p (XEXP (SET_SRC (set), 1), SET_DEST (set))
> +- && last_label_ruid < reg_state[REGNO (SET_DEST (set))].use_ruid)
> +- {
> +- rtx reg = SET_DEST (set);
> +- rtx plus = SET_SRC (set);
> +- rtx base = XEXP (plus, 1);
> +- rtx prev = prev_nonnote_nondebug_insn (insn);
> +- rtx prev_set = prev ? single_set (prev) : NULL_RTX;
> +- unsigned int regno = REGNO (reg);
> +- rtx index_reg = NULL_RTX;
> +- rtx reg_sum = NULL_RTX;
> +-
> +- /* Now we need to set INDEX_REG to an index register (denoted as
> +- REGZ in the illustration above) and REG_SUM to the expression
> +- register+register that we want to use to substitute uses of REG
> +- (typically in MEMs) with. First check REG and BASE for being
> +- index registers; we can use them even if they are not dead. */
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS], regno)
> +- || TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> +- REGNO (base)))
> +- {
> +- index_reg = reg;
> +- reg_sum = plus;
> +- }
> +- else
> +- {
> +- /* Otherwise, look for a free index register. Since we have
> +- checked above that neither REG nor BASE are index registers,
> +- if we find anything at all, it will be different from these
> +- two registers. */
> +- for (i = first_index_reg; i <= last_index_reg; i++)
> +- {
> +- if (TEST_HARD_REG_BIT (reg_class_contents[INDEX_REG_CLASS],
> +- i)
> +- && reg_state[i].use_index == RELOAD_COMBINE_MAX_USES
> +- && reg_state[i].store_ruid <= reg_state[regno].use_ruid
> +- && hard_regno_nregs[i][GET_MODE (reg)] == 1)
> +- {
> +- index_reg = gen_rtx_REG (GET_MODE (reg), i);
> +- reg_sum = gen_rtx_PLUS (GET_MODE (reg), index_reg, base);
> +- break;
> +- }
> +- }
> +- }
> +-
> +- /* Check that PREV_SET is indeed (set (REGX) (CONST_INT)) and that
> +- (REGY), i.e. BASE, is not clobbered before the last use we'll
> +- create. */
> +- if (reg_sum
> +- && prev_set
> +- && CONST_INT_P (SET_SRC (prev_set))
> +- && rtx_equal_p (SET_DEST (prev_set), reg)
> +- && reg_state[regno].use_index >= 0
> +- && (reg_state[REGNO (base)].store_ruid
> +- <= reg_state[regno].use_ruid))
> +- {
> +- int i;
> +-
> +- /* Change destination register and, if necessary, the constant
> +- value in PREV, the constant loading instruction. */
> +- validate_change (prev, &SET_DEST (prev_set), index_reg, 1);
> +- if (reg_state[regno].offset != const0_rtx)
> +- validate_change (prev,
> +- &SET_SRC (prev_set),
> +- GEN_INT (INTVAL (SET_SRC (prev_set))
> +- + INTVAL (reg_state[regno].offset)),
> +- 1);
> +-
> +- /* Now for every use of REG that we have recorded, replace REG
> +- with REG_SUM. */
> +- for (i = reg_state[regno].use_index;
> +- i < RELOAD_COMBINE_MAX_USES; i++)
> +- validate_unshare_change (reg_state[regno].reg_use[i].insn,
> +- reg_state[regno].reg_use[i].usep,
> +- /* Each change must have its own
> +- replacement. */
> +- reg_sum, 1);
> +-
> +- if (apply_change_group ())
> +- {
> +- /* For every new use of REG_SUM, we have to record the use
> +- of BASE therein, i.e. operand 1. */
> +- for (i = reg_state[regno].use_index;
> +- i < RELOAD_COMBINE_MAX_USES; i++)
> +- reload_combine_note_use
> +- (&XEXP (*reg_state[regno].reg_use[i].usep, 1),
> +- reg_state[regno].reg_use[i].insn);
> +-
> +- if (reg_state[REGNO (base)].use_ruid
> +- > reg_state[regno].use_ruid)
> +- reg_state[REGNO (base)].use_ruid
> +- = reg_state[regno].use_ruid;
> +-
> +- /* Delete the reg-reg addition. */
> +- delete_insn (insn);
> +-
> +- if (reg_state[regno].offset != const0_rtx)
> +- /* Previous REG_EQUIV / REG_EQUAL notes for PREV
> +- are now invalid. */
> +- remove_reg_equal_equiv_notes (prev);
> +-
> +- reg_state[regno].use_index = RELOAD_COMBINE_MAX_USES;
> +- reg_state[REGNO (index_reg)].store_ruid
> +- = reload_combine_ruid;
> +- continue;
> +- }
> +- }
> +- }
> ++ if (control_flow_insn_p (insn))
> ++ last_jump_ruid = reload_combine_ruid;
> ++
> ++ if (reload_combine_recognize_const_pattern (insn)
> ++ || reload_combine_recognize_pattern (insn))
> ++ continue;
> +
> + note_stores (PATTERN (insn), reload_combine_note_store, NULL);
> +
> +@@ -967,7 +1371,8 @@
> + reg_state[i].use_index = -1;
> + }
> +
> +- reload_combine_note_use (&PATTERN (insn), insn);
> ++ reload_combine_note_use (&PATTERN (insn), insn,
> ++ reload_combine_ruid, NULL_RTX);
> + for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
> + {
> + if (REG_NOTE_KIND (note) == REG_INC
> +@@ -976,6 +1381,7 @@
> + int regno = REGNO (XEXP (note, 0));
> +
> + reg_state[regno].store_ruid = reload_combine_ruid;
> ++ reg_state[regno].real_store_ruid = reload_combine_ruid;
> + reg_state[regno].use_index = -1;
> + }
> + }
> +@@ -985,8 +1391,8 @@
> + }
> +
> + /* Check if DST is a register or a subreg of a register; if it is,
> +- update reg_state[regno].store_ruid and reg_state[regno].use_index
> +- accordingly. Called via note_stores from reload_combine. */
> ++ update store_ruid, real_store_ruid and use_index in the reg_state
> ++ structure accordingly. Called via note_stores from reload_combine. */
> +
> + static void
> + reload_combine_note_store (rtx dst, const_rtx set, void *data ATTRIBUTE_UNUSED)
> +@@ -1010,14 +1416,14 @@
> + /* note_stores might have stripped a STRICT_LOW_PART, so we have to be
> + careful with registers / register parts that are not full words.
> + Similarly for ZERO_EXTRACT. */
> +- if (GET_CODE (set) != SET
> +- || GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
> ++ if (GET_CODE (SET_DEST (set)) == ZERO_EXTRACT
> + || GET_CODE (SET_DEST (set)) == STRICT_LOW_PART)
> + {
> + for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
> + {
> + reg_state[i].use_index = -1;
> + reg_state[i].store_ruid = reload_combine_ruid;
> ++ reg_state[i].real_store_ruid = reload_combine_ruid;
> + }
> + }
> + else
> +@@ -1025,6 +1431,8 @@
> + for (i = hard_regno_nregs[regno][mode] - 1 + regno; i >= regno; i--)
> + {
> + reg_state[i].store_ruid = reload_combine_ruid;
> ++ if (GET_CODE (set) == SET)
> ++ reg_state[i].real_store_ruid = reload_combine_ruid;
> + reg_state[i].use_index = RELOAD_COMBINE_MAX_USES;
> + }
> + }
> +@@ -1035,7 +1443,7 @@
> + *XP is the pattern of INSN, or a part of it.
> + Called from reload_combine, and recursively by itself. */
> + static void
> +-reload_combine_note_use (rtx *xp, rtx insn)
> ++reload_combine_note_use (rtx *xp, rtx insn, int ruid, rtx containing_mem)
> + {
> + rtx x = *xp;
> + enum rtx_code code = x->code;
> +@@ -1048,7 +1456,7 @@
> + case SET:
> + if (REG_P (SET_DEST (x)))
> + {
> +- reload_combine_note_use (&SET_SRC (x), insn);
> ++ reload_combine_note_use (&SET_SRC (x), insn, ruid, NULL_RTX);
> + return;
> + }
> + break;
> +@@ -1104,6 +1512,11 @@
> + return;
> + }
> +
> ++ /* We may be called to update uses in previously seen insns.
> ++ Don't add uses beyond the last store we saw. */
> ++ if (ruid < reg_state[regno].store_ruid)
> ++ return;
> ++
> + /* If this register is already used in some unknown fashion, we
> + can't do anything.
> + If we decrement the index from zero to -1, we can't store more
> +@@ -1112,29 +1525,34 @@
> + if (use_index < 0)
> + return;
> +
> +- if (use_index != RELOAD_COMBINE_MAX_USES - 1)
> +- {
> +- /* We have found another use for a register that is already
> +- used later. Check if the offsets match; if not, mark the
> +- register as used in an unknown fashion. */
> +- if (! rtx_equal_p (offset, reg_state[regno].offset))
> +- {
> +- reg_state[regno].use_index = -1;
> +- return;
> +- }
> +- }
> +- else
> ++ if (use_index == RELOAD_COMBINE_MAX_USES - 1)
> + {
> + /* This is the first use of this register we have seen since we
> + marked it as dead. */
> + reg_state[regno].offset = offset;
> +- reg_state[regno].use_ruid = reload_combine_ruid;
> +- }
> ++ reg_state[regno].all_offsets_match = true;
> ++ reg_state[regno].use_ruid = ruid;
> ++ }
> ++ else
> ++ {
> ++ if (reg_state[regno].use_ruid > ruid)
> ++ reg_state[regno].use_ruid = ruid;
> ++
> ++ if (! rtx_equal_p (offset, reg_state[regno].offset))
> ++ reg_state[regno].all_offsets_match = false;
> ++ }
> ++
> + reg_state[regno].reg_use[use_index].insn = insn;
> ++ reg_state[regno].reg_use[use_index].ruid = ruid;
> ++ reg_state[regno].reg_use[use_index].containing_mem = containing_mem;
> + reg_state[regno].reg_use[use_index].usep = xp;
> + return;
> + }
> +
> ++ case MEM:
> ++ containing_mem = x;
> ++ break;
> ++
> + default:
> + break;
> + }
> +@@ -1144,11 +1562,12 @@
> + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
> + {
> + if (fmt[i] == 'e')
> +- reload_combine_note_use (&XEXP (x, i), insn);
> ++ reload_combine_note_use (&XEXP (x, i), insn, ruid, containing_mem);
> + else if (fmt[i] == 'E')
> + {
> + for (j = XVECLEN (x, i) - 1; j >= 0; j--)
> +- reload_combine_note_use (&XVECEXP (x, i, j), insn);
> ++ reload_combine_note_use (&XVECEXP (x, i, j), insn, ruid,
> ++ containing_mem);
> + }
> + }
> + }
> +@@ -1196,9 +1615,10 @@
> + while REG is known to already have value (SYM + offset).
> + This function tries to change INSN into an add instruction
> + (set (REG) (plus (REG) (OFF - offset))) using the known value.
> +- It also updates the information about REG's known value. */
> ++ It also updates the information about REG's known value.
> ++ Return true if we made a change. */
> +
> +-static void
> ++static bool
> + move2add_use_add2_insn (rtx reg, rtx sym, rtx off, rtx insn)
> + {
> + rtx pat = PATTERN (insn);
> +@@ -1207,6 +1627,7 @@
> + rtx new_src = gen_int_mode (INTVAL (off) - reg_offset[regno],
> + GET_MODE (reg));
> + bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
> ++ bool changed = false;
> +
> + /* (set (reg) (plus (reg) (const_int 0))) is not canonical;
> + use (set (reg) (reg)) instead.
> +@@ -1221,13 +1642,13 @@
> + (reg)), would be discarded. Maybe we should
> + try a truncMN pattern? */
> + if (INTVAL (off) == reg_offset [regno])
> +- validate_change (insn, &SET_SRC (pat), reg, 0);
> ++ changed = validate_change (insn, &SET_SRC (pat), reg, 0);
> + }
> + else if (rtx_cost (new_src, PLUS, speed) < rtx_cost (src, SET, speed)
> + && have_add2_insn (reg, new_src))
> + {
> + rtx tem = gen_rtx_PLUS (GET_MODE (reg), reg, new_src);
> +- validate_change (insn, &SET_SRC (pat), tem, 0);
> ++ changed = validate_change (insn, &SET_SRC (pat), tem, 0);
> + }
> + else if (sym == NULL_RTX && GET_MODE (reg) != BImode)
> + {
> +@@ -1252,8 +1673,9 @@
> + gen_rtx_STRICT_LOW_PART (VOIDmode,
> + narrow_reg),
> + narrow_src);
> +- if (validate_change (insn, &PATTERN (insn),
> +- new_set, 0))
> ++ changed = validate_change (insn, &PATTERN (insn),
> ++ new_set, 0);
> ++ if (changed)
> + break;
> + }
> + }
> +@@ -1263,6 +1685,7 @@
> + reg_mode[regno] = GET_MODE (reg);
> + reg_symbol_ref[regno] = sym;
> + reg_offset[regno] = INTVAL (off);
> ++ return changed;
> + }
> +
> +
> +@@ -1272,9 +1695,10 @@
> + value (SYM + offset) and change INSN into an add instruction
> + (set (REG) (plus (the found register) (OFF - offset))) if such
> + a register is found. It also updates the information about
> +- REG's known value. */
> ++ REG's known value.
> ++ Return true iff we made a change. */
> +
> +-static void
> ++static bool
> + move2add_use_add3_insn (rtx reg, rtx sym, rtx off, rtx insn)
> + {
> + rtx pat = PATTERN (insn);
> +@@ -1284,6 +1708,7 @@
> + int min_regno;
> + bool speed = optimize_bb_for_speed_p (BLOCK_FOR_INSN (insn));
> + int i;
> ++ bool changed = false;
> +
> + for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
> + if (reg_set_luid[i] > move2add_last_label_luid
> +@@ -1328,20 +1753,25 @@
> + GET_MODE (reg));
> + tem = gen_rtx_PLUS (GET_MODE (reg), tem, new_src);
> + }
> +- validate_change (insn, &SET_SRC (pat), tem, 0);
> ++ if (validate_change (insn, &SET_SRC (pat), tem, 0))
> ++ changed = true;
> + }
> + reg_set_luid[regno] = move2add_luid;
> + reg_base_reg[regno] = -1;
> + reg_mode[regno] = GET_MODE (reg);
> + reg_symbol_ref[regno] = sym;
> + reg_offset[regno] = INTVAL (off);
> ++ return changed;
> + }
> +
> +-static void
> ++/* Convert move insns with constant inputs to additions if they are cheaper.
> ++ Return true if any changes were made. */
> ++static bool
> + reload_cse_move2add (rtx first)
> + {
> + int i;
> + rtx insn;
> ++ bool changed = false;
> +
> + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
> + {
> +@@ -1402,7 +1832,7 @@
> + && reg_base_reg[regno] < 0
> + && reg_symbol_ref[regno] == NULL_RTX)
> + {
> +- move2add_use_add2_insn (reg, NULL_RTX, src, insn);
> ++ changed |= move2add_use_add2_insn (reg, NULL_RTX, src, insn);
> + continue;
> + }
> +
> +@@ -1463,6 +1893,7 @@
> + }
> + if (success)
> + delete_insn (insn);
> ++ changed |= success;
> + insn = next;
> + reg_mode[regno] = GET_MODE (reg);
> + reg_offset[regno] =
> +@@ -1508,12 +1939,12 @@
> + && reg_base_reg[regno] < 0
> + && reg_symbol_ref[regno] != NULL_RTX
> + && rtx_equal_p (sym, reg_symbol_ref[regno]))
> +- move2add_use_add2_insn (reg, sym, off, insn);
> ++ changed |= move2add_use_add2_insn (reg, sym, off, insn);
> +
> + /* Otherwise, we have to find a register whose value is sum
> + of sym and some constant value. */
> + else
> +- move2add_use_add3_insn (reg, sym, off, insn);
> ++ changed |= move2add_use_add3_insn (reg, sym, off, insn);
> +
> + continue;
> + }
> +@@ -1568,6 +1999,7 @@
> + }
> + }
> + }
> ++ return changed;
> + }
> +
> + /* SET is a SET or CLOBBER that sets DST. DATA is the insn which
> +
> diff --git a/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch b/recipes/gcc/gcc-4.5/linaro/gcc-4.5-linaro-r99440.patch
> new file mode 100644
> index 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