OSDN Git Service

2011-04-17 Chung-Lin Tang <cltang@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / arm.c
index 23bc810..dc45eb0 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for ARM.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
@@ -41,7 +41,6 @@
 #include "expr.h"
 #include "optabs.h"
 #include "diagnostic-core.h"
-#include "toplev.h"
 #include "recog.h"
 #include "cgraph.h"
 #include "ggc.h"
@@ -57,6 +56,7 @@
 #include "intl.h"
 #include "libfuncs.h"
 #include "params.h"
+#include "opts.h"
 
 /* Forward definitions of types.  */
 typedef struct minipool_node    Mnode;
@@ -65,6 +65,7 @@ typedef struct minipool_fixup   Mfix;
 void (*arm_lang_output_object_attributes_hook)(void);
 
 /* Forward function declarations.  */
+static bool arm_needs_doubleword_align (enum machine_mode, const_tree);
 static int arm_compute_static_chain_stack_bytes (void);
 static arm_stack_offsets *arm_get_frame_offsets (void);
 static void arm_add_gc_roots (void);
@@ -164,6 +165,11 @@ static void emit_constant_insn (rtx cond, rtx pattern);
 static rtx emit_set_insn (rtx, rtx);
 static int arm_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
                                  tree, bool);
+static rtx arm_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+                            const_tree, bool);
+static void arm_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+                                     const_tree, bool);
+static unsigned int arm_function_arg_boundary (enum machine_mode, const_tree);
 static rtx aapcs_allocate_return_reg (enum machine_mode, const_tree,
                                      const_tree);
 static int aapcs_select_return_coproc (const_tree, const_tree);
@@ -189,10 +195,13 @@ static bool arm_align_anon_bitfield (void);
 static bool arm_return_in_msb (const_tree);
 static bool arm_must_pass_in_stack (enum machine_mode, const_tree);
 static bool arm_return_in_memory (const_tree, const_tree);
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 static void arm_unwind_emit (FILE *, rtx);
 static bool arm_output_ttype (rtx);
+static void arm_asm_emit_except_personality (rtx);
+static void arm_asm_init_sections (void);
 #endif
+static enum unwind_info_type arm_except_unwind_info (struct gcc_options *);
 static void arm_dwarf_handle_frame_unspec (const char *, rtx, int);
 static rtx arm_dwarf_register_span (rtx);
 
@@ -209,13 +218,13 @@ static void arm_init_libfuncs (void);
 static tree arm_build_builtin_va_list (void);
 static void arm_expand_builtin_va_start (tree, rtx);
 static tree arm_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *);
-static bool arm_handle_option (size_t, const char *, int);
-static void arm_target_help (void);
+static void arm_option_override (void);
 static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
 static bool arm_cannot_copy_insn_p (rtx);
 static bool arm_tls_symbol_p (rtx x);
 static int arm_issue_rate (void);
 static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static bool arm_output_addr_const_extra (FILE *, rtx);
 static bool arm_allocate_stack_slots_for_args (void);
 static const char *arm_invalid_parameter_type (const_tree t);
 static const char *arm_invalid_return_type (const_tree t);
@@ -228,25 +237,43 @@ static void arm_asm_trampoline_template (FILE *);
 static void arm_trampoline_init (rtx, tree, rtx);
 static rtx arm_trampoline_adjust_address (rtx);
 static rtx arm_pic_static_addr (rtx orig, rtx reg);
+static bool cortex_a9_sched_adjust_cost (rtx, rtx, rtx, int *);
+static bool xscale_sched_adjust_cost (rtx, rtx, rtx, int *);
+static bool fa726te_sched_adjust_cost (rtx, rtx, rtx, int *);
+static enum machine_mode arm_preferred_simd_mode (enum machine_mode);
+static bool arm_class_likely_spilled_p (reg_class_t);
+static bool arm_vector_alignment_reachable (const_tree type, bool is_packed);
+static bool arm_builtin_support_vector_misalignment (enum machine_mode mode,
+                                                    const_tree type,
+                                                    int misalignment,
+                                                    bool is_packed);
+static void arm_conditional_register_usage (void);
+static reg_class_t arm_preferred_rename_class (reg_class_t rclass);
+static unsigned int arm_autovectorize_vector_sizes (void);
 
 \f
 /* Table of machine attributes.  */
 static const struct attribute_spec arm_attribute_table[] =
 {
-  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
   /* Function calls made to this symbol must be done indirectly, because
      it may lie outside of the 26 bit addressing range of a normal function
      call.  */
-  { "long_call",    0, 0, false, true,  true,  NULL },
+  { "long_call",    0, 0, false, true,  true,  NULL, false },
   /* Whereas these functions are always known to reside within the 26 bit
      addressing range.  */
-  { "short_call",   0, 0, false, true,  true,  NULL },
+  { "short_call",   0, 0, false, true,  true,  NULL, false },
   /* Specify the procedure call conventions for a function.  */
-  { "pcs",          1, 1, false, true,  true,  arm_handle_pcs_attribute },
+  { "pcs",          1, 1, false, true,  true,  arm_handle_pcs_attribute,
+    false },
   /* Interrupt Service Routines have special prologue and epilogue requirements.  */
-  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute },
-  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute },
-  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute },
+  { "isr",          0, 1, false, false, false, arm_handle_isr_attribute,
+    false },
+  { "interrupt",    0, 1, false, false, false, arm_handle_isr_attribute,
+    false },
+  { "naked",        0, 0, true,  false, false, arm_handle_fndecl_attribute,
+    false },
 #ifdef ARM_PE
   /* ARM/PE has three new attributes:
      interfacearm - ?
@@ -257,16 +284,27 @@ static const struct attribute_spec arm_attribute_table[] =
      them with spaces.  We do NOT support this.  Instead, use __declspec
      multiple times.
   */
-  { "dllimport",    0, 0, true,  false, false, NULL },
-  { "dllexport",    0, 0, true,  false, false, NULL },
-  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute },
+  { "dllimport",    0, 0, true,  false, false, NULL, false },
+  { "dllexport",    0, 0, true,  false, false, NULL, false },
+  { "interfacearm", 0, 0, true,  false, false, arm_handle_fndecl_attribute,
+    false },
 #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
-  { "dllimport",    0, 0, false, false, false, handle_dll_attribute },
-  { "dllexport",    0, 0, false, false, false, handle_dll_attribute },
-  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute },
+  { "dllimport",    0, 0, false, false, false, handle_dll_attribute, false },
+  { "dllexport",    0, 0, false, false, false, handle_dll_attribute, false },
+  { "notshared",    0, 0, false, true, false, arm_handle_notshared_attribute,
+    false },
 #endif
-  { NULL,           0, 0, false, false, false, NULL }
+  { NULL,           0, 0, false, false, false, NULL, false }
 };
+
+/* Set default optimization options.  */
+static const struct default_options arm_option_optimization_table[] =
+  {
+    /* Enable section anchors by default at -O1 or higher.  */
+    { OPT_LEVELS_1_PLUS, OPT_fsection_anchors, NULL, 1 },
+    { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+    { OPT_LEVELS_NONE, 0, NULL, 0 }
+  };
 \f
 /* Initialize the GCC target structure.  */
 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
@@ -297,6 +335,9 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
 #define TARGET_PRINT_OPERAND_PUNCT_VALID_P arm_print_operand_punct_valid_p
 
+#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA
+#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA arm_output_addr_const_extra
+
 #undef  TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
 
@@ -305,10 +346,10 @@ static const struct attribute_spec arm_attribute_table[] =
 
 #undef  TARGET_DEFAULT_TARGET_FLAGS
 #define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_SCHED_PROLOG)
-#undef  TARGET_HANDLE_OPTION
-#define TARGET_HANDLE_OPTION arm_handle_option
-#undef  TARGET_HELP
-#define TARGET_HELP arm_target_help
+#undef  TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE arm_option_override
+#undef  TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE arm_option_optimization_table
 
 #undef  TARGET_COMP_TYPE_ATTRIBUTES
 #define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
@@ -355,6 +396,11 @@ static const struct attribute_spec arm_attribute_table[] =
 #define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask
 #undef TARGET_VECTOR_MODE_SUPPORTED_P
 #define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
+#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
+#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE arm_preferred_simd_mode
+#undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES
+#define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES \
+  arm_autovectorize_vector_sizes
 
 #undef  TARGET_MACHINE_DEPENDENT_REORG
 #define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
@@ -375,6 +421,12 @@ static const struct attribute_spec arm_attribute_table[] =
 #define TARGET_PASS_BY_REFERENCE arm_pass_by_reference
 #undef TARGET_ARG_PARTIAL_BYTES
 #define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG arm_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE arm_function_arg_advance
+#undef TARGET_FUNCTION_ARG_BOUNDARY
+#define TARGET_FUNCTION_ARG_BOUNDARY arm_function_arg_boundary
 
 #undef  TARGET_SETUP_INCOMING_VARARGS
 #define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
@@ -435,7 +487,7 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
 
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 #undef TARGET_ASM_UNWIND_EMIT
 #define TARGET_ASM_UNWIND_EMIT arm_unwind_emit
 
@@ -445,7 +497,16 @@ static const struct attribute_spec arm_attribute_table[] =
 
 #undef TARGET_ARM_EABI_UNWINDER
 #define TARGET_ARM_EABI_UNWINDER true
-#endif /* TARGET_UNWIND_INFO */
+
+#undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY
+#define TARGET_ASM_EMIT_EXCEPT_PERSONALITY arm_asm_emit_except_personality
+
+#undef TARGET_ASM_INIT_SECTIONS
+#define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections
+#endif /* ARM_UNWIND_INFO */
+
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO  arm_except_unwind_info
 
 #undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
 #define TARGET_DWARF_HANDLE_FRAME_UNSPEC arm_dwarf_handle_frame_unspec
@@ -518,6 +579,24 @@ static const struct attribute_spec arm_attribute_table[] =
 #undef TARGET_CAN_ELIMINATE
 #define TARGET_CAN_ELIMINATE arm_can_eliminate
 
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE arm_conditional_register_usage
+
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P arm_class_likely_spilled_p
+
+#undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE
+#define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \
+  arm_vector_alignment_reachable
+
+#undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT
+#define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \
+  arm_builtin_support_vector_misalignment
+
+#undef TARGET_PREFERRED_RENAME_CLASS
+#define TARGET_PREFERRED_RENAME_CLASS \
+  arm_preferred_rename_class
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Obstack for minipool constant handling.  */
@@ -591,6 +670,7 @@ static int thumb_call_reg_needed;
 #define FL_NEON       (1 << 20)       /* Neon instructions.  */
 #define FL_ARCH7EM    (1 << 21)              /* Instructions present in the ARMv7E-M
                                         architecture.  */
+#define FL_ARCH7      (1 << 22)       /* Architecture 7.  */
 
 #define FL_IWMMXT     (1 << 29)              /* XScale v2 or "Intel Wireless MMX technology".  */
 
@@ -615,7 +695,7 @@ static int thumb_call_reg_needed;
 #define FL_FOR_ARCH6ZK FL_FOR_ARCH6K
 #define FL_FOR_ARCH6T2 (FL_FOR_ARCH6 | FL_THUMB2)
 #define FL_FOR_ARCH6M  (FL_FOR_ARCH6 & ~FL_NOTM)
-#define FL_FOR_ARCH7   (FL_FOR_ARCH6T2 &~ FL_NOTM)
+#define FL_FOR_ARCH7   ((FL_FOR_ARCH6T2 & ~FL_NOTM) | FL_ARCH7)
 #define FL_FOR_ARCH7A  (FL_FOR_ARCH7 | FL_NOTM | FL_ARCH6K)
 #define FL_FOR_ARCH7R  (FL_FOR_ARCH7A | FL_DIV)
 #define FL_FOR_ARCH7M  (FL_FOR_ARCH7 | FL_DIV)
@@ -653,6 +733,9 @@ int arm_arch6 = 0;
 /* Nonzero if this chip supports the ARM 6K extensions.  */
 int arm_arch6k = 0;
 
+/* Nonzero if this chip supports the ARM 7 extensions.  */
+int arm_arch7 = 0;
+
 /* Nonzero if instructions not present in the 'M' profile can be used.  */
 int arm_arch_notm = 0;
 
@@ -687,6 +770,9 @@ int arm_tune_cortex_a9 = 0;
 /* Nonzero if generating Thumb instructions.  */
 int thumb_code = 0;
 
+/* Nonzero if generating Thumb-1 instructions.  */
+int thumb1_code = 0;
+
 /* Nonzero if we should define __THUMB_INTERWORK__ in the
    preprocessor.
    XXX This is a bit of a hack, it's intended to help work around
@@ -718,6 +804,7 @@ enum arm_pcs arm_pcs_default;
 int arm_ccfsm_state;
 /* arm_current_cc is also used for Thumb-2 cond_exec blocks.  */
 enum arm_cond_code arm_current_cc;
+
 rtx arm_target_insn;
 int arm_target_label;
 /* The number of conditionally executed insns, including the current insn.  */
@@ -735,6 +822,12 @@ static const char * const arm_condition_codes[] =
   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
 };
 
+/* The register numbers in sequence, for passing to arm_gen_load_multiple.  */
+int arm_regs_in_sequence[] =
+{
+  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
 #define ARM_LSL_NAME (TARGET_UNIFIED_ASM ? "lsl" : "asl")
 #define streq(string1, string2) (strcmp (string1, string2) == 0)
 
@@ -753,30 +846,62 @@ struct processors
   const struct tune_params *const tune;
 };
 
+
+#define ARM_PREFETCH_NOT_BENEFICIAL 0, -1, -1
+#define ARM_PREFETCH_BENEFICIAL(prefetch_slots,l1_size,l1_line_size) \
+  prefetch_slots, \
+  l1_size, \
+  l1_line_size
+
 const struct tune_params arm_slowmul_tune =
 {
   arm_slowmul_rtx_costs,
-  3
+  NULL,
+  3,
+  ARM_PREFETCH_NOT_BENEFICIAL
 };
 
 const struct tune_params arm_fastmul_tune =
 {
   arm_fastmul_rtx_costs,
-  1
+  NULL,
+  1,
+  ARM_PREFETCH_NOT_BENEFICIAL
 };
 
 const struct tune_params arm_xscale_tune =
 {
   arm_xscale_rtx_costs,
-  2
+  xscale_sched_adjust_cost,
+  2,
+  ARM_PREFETCH_NOT_BENEFICIAL
 };
 
 const struct tune_params arm_9e_tune =
 {
   arm_9e_rtx_costs,
-  1
+  NULL,
+  1,
+  ARM_PREFETCH_NOT_BENEFICIAL
+};
+
+const struct tune_params arm_cortex_a9_tune =
+{
+  arm_9e_rtx_costs,
+  cortex_a9_sched_adjust_cost,
+  1,
+  ARM_PREFETCH_BENEFICIAL(4,32,32)
+};
+
+const struct tune_params arm_fa726te_tune =
+{
+  arm_9e_rtx_costs,
+  fa726te_sched_adjust_cost,
+  1,
+  ARM_PREFETCH_NOT_BENEFICIAL
 };
 
+
 /* Not all of these give usefully different compilation alternatives,
    but there is no simple way of generalizing them.  */
 static const struct processors all_cores[] =
@@ -795,33 +920,10 @@ static const struct processors all_architectures[] =
   /* We don't specify tuning costs here as it will be figured out
      from the core.  */
 
-  {"armv2",   arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
-  {"armv2a",  arm2,       "2",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
-  {"armv3",   arm6,       "3",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL},
-  {"armv3m",  arm7m,      "3M",  FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL},
-  {"armv4",   arm7tdmi,   "4",   FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL},
-  /* Strictly, FL_MODE26 is a permitted option for v4t, but there are no
-     implementations that support it, so we will leave it out for now.  */
-  {"armv4t",  arm7tdmi,   "4T",  FL_CO_PROC |             FL_FOR_ARCH4T, NULL},
-  {"armv5",   arm10tdmi,  "5",   FL_CO_PROC |             FL_FOR_ARCH5, NULL},
-  {"armv5t",  arm10tdmi,  "5T",  FL_CO_PROC |             FL_FOR_ARCH5T, NULL},
-  {"armv5e",  arm1026ejs, "5E",  FL_CO_PROC |             FL_FOR_ARCH5E, NULL},
-  {"armv5te", arm1026ejs, "5TE", FL_CO_PROC |             FL_FOR_ARCH5TE, NULL},
-  {"armv6",   arm1136js,  "6",   FL_CO_PROC |             FL_FOR_ARCH6, NULL},
-  {"armv6j",  arm1136js,  "6J",  FL_CO_PROC |             FL_FOR_ARCH6J, NULL},
-  {"armv6k",  mpcore,    "6K",  FL_CO_PROC |             FL_FOR_ARCH6K, NULL},
-  {"armv6z",  arm1176jzs, "6Z",  FL_CO_PROC |             FL_FOR_ARCH6Z, NULL},
-  {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
-  {"armv6t2", arm1156t2s, "6T2", FL_CO_PROC |             FL_FOR_ARCH6T2, NULL},
-  {"armv6-m", cortexm1,          "6M",                           FL_FOR_ARCH6M, NULL},
-  {"armv7",   cortexa8,          "7",   FL_CO_PROC |             FL_FOR_ARCH7, NULL},
-  {"armv7-a", cortexa8,          "7A",  FL_CO_PROC |             FL_FOR_ARCH7A, NULL},
-  {"armv7-r", cortexr4,          "7R",  FL_CO_PROC |             FL_FOR_ARCH7R, NULL},
-  {"armv7-m", cortexm3,          "7M",  FL_CO_PROC |             FL_FOR_ARCH7M, NULL},
-  {"armv7e-m", cortexm4,  "7EM", FL_CO_PROC |            FL_FOR_ARCH7EM, NULL},
-  {"ep9312",  ep9312,     "4T",  FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
-  {"iwmmxt",  iwmmxt,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
-  {"iwmmxt2", iwmmxt2,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
+#define ARM_ARCH(NAME, CORE, ARCH, FLAGS) \
+  {NAME, CORE, #ARCH, FLAGS, NULL},
+#include "arm-arches.def"
+#undef ARM_ARCH
   {NULL, arm_none, NULL, 0 , NULL}
 };
 
@@ -1140,6 +1242,7 @@ arm_build_builtin_va_list (void)
                             va_list_type);
   DECL_ARTIFICIAL (va_list_name) = 1;
   TYPE_NAME (va_list_type) = va_list_name;
+  TYPE_STUB_DECL (va_list_type) = va_list_name;
   /* Create the __ap field.  */
   ap_field = build_decl (BUILTINS_LOCATION,
                         FIELD_DECL, 
@@ -1192,148 +1295,24 @@ arm_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p,
   return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
 }
 
-/* Lookup NAME in SEL.  */
-
-static const struct processors *
-arm_find_cpu (const char *name, const struct processors *sel, const char *desc)
-{
-  if (!(name && *name))
-    return NULL;
-
-  for (; sel->name != NULL; sel++)
-    {
-      if (streq (name, sel->name))
-       return sel;
-    }
-
-  error ("bad value (%s) for %s switch", name, desc);
-  return NULL;
-}
-
-/* Implement TARGET_HANDLE_OPTION.  */
-
-static bool
-arm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
-{
-  switch (code)
-    {
-    case OPT_march_:
-      arm_selected_arch = arm_find_cpu(arg, all_architectures, "-march");
-      return true;
-
-    case OPT_mcpu_:
-      arm_selected_cpu = arm_find_cpu(arg, all_cores, "-mcpu");
-      return true;
-
-    case OPT_mhard_float:
-      target_float_abi_name = "hard";
-      return true;
-
-    case OPT_msoft_float:
-      target_float_abi_name = "soft";
-      return true;
-
-    case OPT_mtune_:
-      arm_selected_tune = arm_find_cpu(arg, all_cores, "-mtune");
-      return true;
-
-    default:
-      return true;
-    }
-}
-
+/* Fix up any incompatible options that the user has specified.  */
 static void
-arm_target_help (void)
+arm_option_override (void)
 {
-  int i;
-  static int columns = 0;
-  int remaining;
-
-  /* If we have not done so already, obtain the desired maximum width of
-     the output.  Note - this is a duplication of the code at the start of
-     gcc/opts.c:print_specific_help() - the two copies should probably be
-     replaced by a single function.  */
-  if (columns == 0)
-    {
-      const char *p;
-
-      GET_ENVIRONMENT (p, "COLUMNS");
-      if (p != NULL)
-       {
-         int value = atoi (p);
-
-         if (value > 0)
-           columns = value;
-       }
-
-      if (columns == 0)
-       /* Use a reasonable default.  */
-       columns = 80;
-    }
-
-  printf ("  Known ARM CPUs (for use with the -mcpu= and -mtune= options):\n");
-
-  /* The - 2 is because we know that the last entry in the array is NULL.  */
-  i = ARRAY_SIZE (all_cores) - 2;
-  gcc_assert (i > 0);
-  printf ("    %s", all_cores[i].name);
-  remaining = columns - (strlen (all_cores[i].name) + 4);
-  gcc_assert (remaining >= 0);
-
-  while (i--)
-    {
-      int len = strlen (all_cores[i].name);
-
-      if (remaining > len + 2)
-       {
-         printf (", %s", all_cores[i].name);
-         remaining -= len + 2;
-       }
-      else
-       {
-         if (remaining > 0)
-           printf (",");
-         printf ("\n    %s", all_cores[i].name);
-         remaining = columns - (len + 4);
-       }
-    }
-
-  printf ("\n\n  Known ARM architectures (for use with the -march= option):\n");
-
-  i = ARRAY_SIZE (all_architectures) - 2;
-  gcc_assert (i > 0);
-  
-  printf ("    %s", all_architectures[i].name);
-  remaining = columns - (strlen (all_architectures[i].name) + 4);
-  gcc_assert (remaining >= 0);
+  unsigned i;
 
-  while (i--)
-    {
-      int len = strlen (all_architectures[i].name);
+  if (global_options_set.x_arm_arch_option)
+    arm_selected_arch = &all_architectures[arm_arch_option];
 
-      if (remaining > len + 2)
-       {
-         printf (", %s", all_architectures[i].name);
-         remaining -= len + 2;
-       }
-      else
-       {
-         if (remaining > 0)
-           printf (",");
-         printf ("\n    %s", all_architectures[i].name);
-         remaining = columns - (len + 4);
-       }
-    }
-  printf ("\n");
+  if (global_options_set.x_arm_cpu_option)
+    arm_selected_cpu = &all_cores[(int) arm_cpu_option];
 
-}
+  if (global_options_set.x_arm_tune_option)
+    arm_selected_tune = &all_cores[(int) arm_tune_option];
 
-/* Fix up any incompatible options that the user has specified.
-   This has now turned into a maze.  */
-void
-arm_override_options (void)
-{
-  unsigned i;
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
 
   if (arm_selected_arch)
     {
@@ -1375,7 +1354,7 @@ arm_override_options (void)
          arm_selected_cpu = &all_cores[SUBTARGET_CPU_DEFAULT];
 #endif
          /* Default to ARM6.  */
-         if (arm_selected_cpu->name)
+         if (!arm_selected_cpu->name)
            arm_selected_cpu = &all_cores[arm6];
        }
 
@@ -1517,7 +1496,7 @@ arm_override_options (void)
   /* Callee super interworking implies thumb interworking.  Adding
      this to the flags here simplifies the logic elsewhere.  */
   if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
-      target_flags |= MASK_INTERWORK;
+    target_flags |= MASK_INTERWORK;
 
   /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
      from here where no function is being compiled currently.  */
@@ -1527,9 +1506,6 @@ arm_override_options (void)
   if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
     warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
 
-  if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
-    warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
-
   if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
     {
       warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
@@ -1565,6 +1541,7 @@ arm_override_options (void)
   arm_arch6 = (insn_flags & FL_ARCH6) != 0;
   arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
   arm_arch_notm = (insn_flags & FL_NOTM) != 0;
+  arm_arch7 = (insn_flags & FL_ARCH7) != 0;
   arm_arch7em = (insn_flags & FL_ARCH7EM) != 0;
   arm_arch_thumb2 = (insn_flags & FL_THUMB2) != 0;
   arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
@@ -1572,7 +1549,8 @@ arm_override_options (void)
 
   arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
   arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
-  thumb_code = (TARGET_ARM == 0);
+  thumb_code = TARGET_ARM == 0;
+  thumb1_code = TARGET_THUMB1 != 0;
   arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
   arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
   arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
@@ -1873,13 +1851,44 @@ arm_override_options (void)
       flag_reorder_blocks = 1;
     }
 
-  if (!PARAM_SET_P (PARAM_GCSE_UNRESTRICTED_COST)
-      && flag_pic)
+  if (flag_pic)
     /* Hoisting PIC address calculations more aggressively provides a small,
        but measurable, size reduction for PIC code.  Therefore, we decrease
        the bar for unrestricted expression hoisting to the cost of PIC address
        calculation, which is 2 instructions.  */
-    set_param_value ("gcse-unrestricted-cost", 2);
+    maybe_set_param_value (PARAM_GCSE_UNRESTRICTED_COST, 2,
+                          global_options.x_param_values,
+                          global_options_set.x_param_values);
+
+  /* ARM EABI defaults to strict volatile bitfields.  */
+  if (TARGET_AAPCS_BASED && flag_strict_volatile_bitfields < 0)
+    flag_strict_volatile_bitfields = 1;
+
+  /* Enable sw prefetching at -O3 for CPUS that have prefetch, and we have deemed
+     it beneficial (signified by setting num_prefetch_slots to 1 or more.)  */
+  if (flag_prefetch_loop_arrays < 0
+      && HAVE_prefetch
+      && optimize >= 3
+      && current_tune->num_prefetch_slots > 0)
+    flag_prefetch_loop_arrays = 1;
+
+  /* Set up parameters to be used in prefetching algorithm.  Do not override the
+     defaults unless we are tuning for a core we have researched values for.  */
+  if (current_tune->num_prefetch_slots > 0)
+    maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
+                           current_tune->num_prefetch_slots,
+                           global_options.x_param_values,
+                           global_options_set.x_param_values);
+  if (current_tune->l1_cache_line_size >= 0)
+    maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
+                           current_tune->l1_cache_line_size,
+                           global_options.x_param_values,
+                           global_options_set.x_param_values);
+  if (current_tune->l1_cache_size >= 0)
+    maybe_set_param_value (PARAM_L1_CACHE_SIZE,
+                           current_tune->l1_cache_size,
+                           global_options.x_param_values,
+                           global_options_set.x_param_values);
 
   /* Register global variables with the garbage collector.  */
   arm_add_gc_roots ();
@@ -1969,7 +1978,8 @@ arm_compute_func_type (void)
   if (optimize > 0
       && (TREE_NOTHROW (current_function_decl)
           || !(flag_unwind_tables
-               || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
+               || (flag_exceptions
+                  && arm_except_unwind_info (&global_options) != UI_SJLJ)))
       && TREE_THIS_VOLATILE (current_function_decl))
     type |= ARM_FT_VOLATILE;
 
@@ -2269,11 +2279,17 @@ const_ok_for_arm (HOST_WIDE_INT i)
     {
       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;
@@ -3692,16 +3708,14 @@ arm_get_pcs_model (const_tree type, const_tree decl)
       /* Detect varargs functions.  These always use the base rules
         (no argument is ever a candidate for a co-processor
         register).  */
-      bool base_rules = (TYPE_ARG_TYPES (type) != 0
-                        && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (type)))
-                            != void_type_node));
+      bool base_rules = stdarg_p (type);
       
       if (user_convention)
        {
          if (user_pcs > ARM_PCS_AAPCS_LOCAL)
-           sorry ("Non-AAPCS derived PCS variant");
+           sorry ("non-AAPCS derived PCS variant");
          else if (base_rules && user_pcs != ARM_PCS_AAPCS)
-           error ("Variadic functions must use the base AAPCS variant");
+           error ("variadic functions must use the base AAPCS variant");
        }
 
       if (base_rules)
@@ -4153,7 +4167,7 @@ static struct
 
 static int
 aapcs_select_call_coproc (CUMULATIVE_ARGS *pcum, enum machine_mode mode, 
-                         tree type)
+                         const_tree type)
 {
   int i;
 
@@ -4265,7 +4279,7 @@ aapcs_libcall_value (enum machine_mode mode)
    numbers referred to here are those in the AAPCS.  */
 static void
 aapcs_layout_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
-                 tree type, int named)
+                 const_tree type, bool named)
 {
   int nregs, nregs2;
   int ncrn;
@@ -4429,8 +4443,8 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
 
 
 /* Return true if mode/type need doubleword alignment.  */
-bool
-arm_needs_doubleword_align (enum machine_mode mode, tree type)
+static bool
+arm_needs_doubleword_align (enum machine_mode mode, const_tree type)
 {
   return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
          || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
@@ -4448,11 +4462,17 @@ arm_needs_doubleword_align (enum machine_mode mode, tree type)
    CUM is a variable of type CUMULATIVE_ARGS which gives info about
     the preceding args and about the function being called.
    NAMED is nonzero if this argument is a named parameter
-    (otherwise it is an extra parameter matching an ellipsis).  */
+    (otherwise it is an extra parameter matching an ellipsis).
 
-rtx
+   On the ARM, normally the first 16 bytes are passed in registers r0-r3; all
+   other arguments are passed on the stack.  If (NAMED == 0) (which happens
+   only in assign_parms, since TARGET_SETUP_INCOMING_VARARGS is
+   defined), say it is passed in the stack (function_prologue will
+   indeed make it pass in the stack if necessary).  */
+
+static rtx
 arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
-                 tree type, int named)
+                 const_tree type, bool named)
 {
   int nregs;
 
@@ -4502,6 +4522,14 @@ arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
   return gen_rtx_REG (mode, pcum->nregs);
 }
 
+static unsigned int
+arm_function_arg_boundary (enum machine_mode mode, const_tree type)
+{
+  return (ARM_DOUBLEWORD_ALIGN && arm_needs_doubleword_align (mode, type)
+         ? DOUBLEWORD_ALIGNMENT
+         : PARM_BOUNDARY);
+}
+
 static int
 arm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
                       tree type, bool named)
@@ -4525,9 +4553,13 @@ arm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
   return 0;
 }
 
-void
+/* Update the data in PCUM to advance over an argument
+   of mode MODE and data type TYPE.
+   (TYPE is null for libcalls where that information may not be available.)  */
+
+static void
 arm_function_arg_advance (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
-                         tree type, bool named)
+                         const_tree type, bool named)
 {
   if (pcum->pcs_variant <= ARM_PCS_AAPCS_LOCAL)
     {
@@ -4949,7 +4981,7 @@ require_pic_register (void)
        }
       else
        {
-         rtx seq;
+         rtx seq, insn;
 
          if (!cfun->machine->pic_reg)
            cfun->machine->pic_reg = gen_reg_rtx (Pmode);
@@ -4966,6 +4998,11 @@ require_pic_register (void)
 
              seq = get_insns ();
              end_sequence ();
+
+             for (insn = seq; insn; insn = NEXT_INSN (insn))
+               if (INSN_P (insn))
+                 INSN_LOCATOR (insn) = prologue_locator;
+
              /* We can be called during expansion of PHI nodes, where
                 we can't yet emit instructions directly in the final
                 insn stream.  Queue the insns on the entry edge, they will
@@ -5480,20 +5517,32 @@ arm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
 
   /* Standard coprocessor addressing modes.  */
   if (TARGET_HARD_FLOAT
-      && (TARGET_FPA || TARGET_MAVERICK)
-      && (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && (TARGET_VFP || TARGET_FPA || TARGET_MAVERICK)
+      && (mode == SFmode || mode == DFmode
          || (TARGET_MAVERICK && mode == DImode)))
     return (code == CONST_INT && INTVAL (index) < 1024
            && 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
@@ -5589,11 +5638,15 @@ thumb2_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
   /* ??? Combine arm and thumb2 coprocessor addressing modes.  */
   /* Standard coprocessor addressing modes.  */
   if (TARGET_HARD_FLOAT
-      && (TARGET_FPA || TARGET_MAVERICK)
-      && (GET_MODE_CLASS (mode) == MODE_FLOAT
+      && (TARGET_VFP || TARGET_FPA || TARGET_MAVERICK)
+      && (mode == SFmode || mode == DFmode
          || (TARGET_MAVERICK && mode == DImode)))
     return (code == CONST_INT && INTVAL (index) < 1024
-           && INTVAL (index) > -1024
+           /* Thumb-2 allows only > -256 index range for it's core register
+              load/stores. Since we allow SF/DF in core registers, we have
+              to use the intersection between -256~4096 (core) and -1024~1024
+              (coprocessor).  */
+           && INTVAL (index) > -256
            && (INTVAL (index) & 3) == 0);
 
   if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
@@ -5607,13 +5660,25 @@ thumb2_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
                && (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;
@@ -5784,7 +5849,8 @@ thumb1_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
               && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
                   || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM
                   || (REGNO (XEXP (x, 0)) >= FIRST_VIRTUAL_REGISTER
-                      && REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER))
+                      && REGNO (XEXP (x, 0))
+                         <= LAST_VIRTUAL_POINTER_REGISTER))
               && GET_MODE_SIZE (mode) >= 4
               && GET_CODE (XEXP (x, 1)) == CONST_INT
               && (INTVAL (XEXP (x, 1)) & 3) == 0)
@@ -6182,6 +6248,165 @@ thumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
   return x;
 }
 
+bool
+arm_legitimize_reload_address (rtx *p,
+                              enum machine_mode mode,
+                              int opnum, int type,
+                              int ind_levels ATTRIBUTE_UNUSED)
+{
+  if (GET_CODE (*p) == PLUS
+      && GET_CODE (XEXP (*p, 0)) == REG
+      && ARM_REGNO_OK_FOR_BASE_P (REGNO (XEXP (*p, 0)))
+      && GET_CODE (XEXP (*p, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (XEXP (*p, 1));
+      HOST_WIDE_INT low, high;
+
+      /* Detect coprocessor load/stores.  */
+      bool coproc_p = ((TARGET_HARD_FLOAT
+                       && (TARGET_VFP || TARGET_FPA || TARGET_MAVERICK)
+                       && (mode == SFmode || mode == DFmode
+                           || (mode == DImode && TARGET_MAVERICK)))
+                      || (TARGET_REALLY_IWMMXT
+                          && VALID_IWMMXT_REG_MODE (mode))
+                      || (TARGET_NEON
+                          && (VALID_NEON_DREG_MODE (mode)
+                              || VALID_NEON_QREG_MODE (mode))));
+
+      /* For some conditions, bail out when lower two bits are unaligned.  */
+      if ((val & 0x3) != 0
+         /* Coprocessor load/store indexes are 8-bits + '00' appended.  */
+         && (coproc_p
+             /* For DI, and DF under soft-float: */
+             || ((mode == DImode || mode == DFmode)
+                 /* Without ldrd, we use stm/ldm, which does not
+                    fair well with unaligned bits.  */
+                 && (! TARGET_LDRD
+                     /* Thumb-2 ldrd/strd is [-1020,+1020] in steps of 4.  */
+                     || TARGET_THUMB2))))
+       return false;
+
+      /* When breaking down a [reg+index] reload address into [(reg+high)+low],
+        of which the (reg+high) gets turned into a reload add insn,
+        we try to decompose the index into high/low values that can often
+        also lead to better reload CSE.
+        For example:
+                ldr r0, [r2, #4100]  // Offset too large
+                ldr r1, [r2, #4104]  // Offset too large
+
+        is best reloaded as:
+                add t1, r2, #4096
+                ldr r0, [t1, #4]
+                add t2, r2, #4096
+                ldr r1, [t2, #8]
+
+        which post-reload CSE can simplify in most cases to eliminate the
+        second add instruction:
+                add t1, r2, #4096
+                ldr r0, [t1, #4]
+                ldr r1, [t1, #8]
+
+        The idea here is that we want to split out the bits of the constant
+        as a mask, rather than as subtracting the maximum offset that the
+        respective type of load/store used can handle.
+
+        When encountering negative offsets, we can still utilize it even if
+        the overall offset is positive; sometimes this may lead to an immediate
+        that can be constructed with fewer instructions.
+        For example:
+                ldr r0, [r2, #0x3FFFFC]
+
+        This is best reloaded as:
+                add t1, r2, #0x400000
+                ldr r0, [t1, #-4]
+
+        The trick for spotting this for a load insn with N bits of offset
+        (i.e. bits N-1:0) is to look at bit N; if it is set, then chose a
+        negative offset that is going to make bit N and all the bits below
+        it become zero in the remainder part.
+
+        The SIGN_MAG_LOW_ADDR_BITS macro below implements this, with respect
+        to sign-magnitude addressing (i.e. separate +- bit, or 1's complement),
+        used in most cases of ARM load/store instructions.  */
+
+#define SIGN_MAG_LOW_ADDR_BITS(VAL, N)                                 \
+      (((VAL) & ((1 << (N)) - 1))                                      \
+       ? (((VAL) & ((1 << ((N) + 1)) - 1)) ^ (1 << (N))) - (1 << (N))  \
+       : 0)
+
+      if (coproc_p)
+       low = SIGN_MAG_LOW_ADDR_BITS (val, 10);
+      else if (GET_MODE_SIZE (mode) == 8)
+       {
+         if (TARGET_LDRD)
+           low = (TARGET_THUMB2
+                  ? SIGN_MAG_LOW_ADDR_BITS (val, 10)
+                  : SIGN_MAG_LOW_ADDR_BITS (val, 8));
+         else
+           /* For pre-ARMv5TE (without ldrd), we use ldm/stm(db/da/ib)
+              to access doublewords. The supported load/store offsets are
+              -8, -4, and 4, which we try to produce here.  */
+           low = ((val & 0xf) ^ 0x8) - 0x8;
+       }
+      else if (GET_MODE_SIZE (mode) < 8)
+       {
+         /* NEON element load/stores do not have an offset.  */
+         if (TARGET_NEON_FP16 && mode == HFmode)
+           return false;
+
+         if (TARGET_THUMB2)
+           {
+             /* Thumb-2 has an asymmetrical index range of (-256,4096).
+                Try the wider 12-bit range first, and re-try if the result
+                is out of range.  */
+             low = SIGN_MAG_LOW_ADDR_BITS (val, 12);
+             if (low < -255)
+               low = SIGN_MAG_LOW_ADDR_BITS (val, 8);
+           }
+         else
+           {
+             if (mode == HImode || mode == HFmode)
+               {
+                 if (arm_arch4)
+                   low = SIGN_MAG_LOW_ADDR_BITS (val, 8);
+                 else
+                   {
+                     /* The storehi/movhi_bytes fallbacks can use only
+                        [-4094,+4094] of the full ldrb/strb index range.  */
+                     low = SIGN_MAG_LOW_ADDR_BITS (val, 12);
+                     if (low == 4095 || low == -4095)
+                       return false;
+                   }
+               }
+             else
+               low = SIGN_MAG_LOW_ADDR_BITS (val, 12);
+           }
+       }
+      else
+       return false;
+
+      high = ((((val - low) & (unsigned HOST_WIDE_INT) 0xffffffff)
+              ^ (unsigned HOST_WIDE_INT) 0x80000000)
+             - (unsigned HOST_WIDE_INT) 0x80000000);
+      /* Check for overflow or zero */
+      if (low == 0 || high == 0 || (high + low != val))
+       return false;
+
+      /* Reload the high part into a base reg; leave the low part
+        in the mem.  */
+      *p = gen_rtx_PLUS (GET_MODE (*p),
+                        gen_rtx_PLUS (GET_MODE (*p), XEXP (*p, 0),
+                                      GEN_INT (high)),
+                        GEN_INT (low));
+      push_reload (XEXP (*p, 0), NULL_RTX, &XEXP (*p, 0), NULL,
+                  MODE_BASE_REG_CLASS (mode), GET_MODE (*p),
+                  VOIDmode, 0, 0, opnum, (enum reload_type) type);
+      return true;
+    }
+
+  return false;
+}
+
 rtx
 thumb_legitimize_reload_address (rtx *x_p,
                                 enum machine_mode mode,
@@ -6635,12 +6860,10 @@ arm_rtx_costs_1 (rtx x, enum rtx_code outer, int* total, bool speed)
         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)
        {
@@ -7683,15 +7906,13 @@ arm_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED)
   return TARGET_32BIT ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
 }
 
-static int
-arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
+/* Adjust cost hook for XScale.  */
+static bool
+xscale_sched_adjust_cost (rtx insn, rtx link, rtx dep, int * cost)
 {
-  rtx i_pat, d_pat;
-
   /* Some true dependencies can have a higher cost depending
      on precisely how certain input operands are used.  */
-  if (arm_tune_xscale
-      && REG_NOTE_KIND (link) == 0
+  if (REG_NOTE_KIND(link) == 0
       && recog_memoized (insn) >= 0
       && recog_memoized (dep) >= 0)
     {
@@ -7725,10 +7946,146 @@ arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
 
              if (reg_overlap_mentioned_p (recog_data.operand[opno],
                                           shifted_operand))
-               return 2;
+               {
+                 *cost = 2;
+                 return false;
+               }
            }
        }
     }
+  return true;
+}
+
+/* Adjust cost hook for Cortex A9.  */
+static bool
+cortex_a9_sched_adjust_cost (rtx insn, rtx link, rtx dep, int * cost)
+{
+  switch (REG_NOTE_KIND (link))
+    {
+    case REG_DEP_ANTI:
+      *cost = 0;
+      return false;
+
+    case REG_DEP_TRUE:
+    case REG_DEP_OUTPUT:
+       if (recog_memoized (insn) >= 0
+           && recog_memoized (dep) >= 0)
+         {
+           if (GET_CODE (PATTERN (insn)) == SET)
+             {
+               if (GET_MODE_CLASS 
+                   (GET_MODE (SET_DEST (PATTERN (insn)))) == MODE_FLOAT
+                 || GET_MODE_CLASS 
+                   (GET_MODE (SET_SRC (PATTERN (insn)))) == MODE_FLOAT)
+                 {
+                   enum attr_type attr_type_insn = get_attr_type (insn);
+                   enum attr_type attr_type_dep = get_attr_type (dep);
+
+                   /* By default all dependencies of the form
+                      s0 = s0 <op> s1
+                      s0 = s0 <op> s2
+                      have an extra latency of 1 cycle because
+                      of the input and output dependency in this
+                      case. However this gets modeled as an true
+                      dependency and hence all these checks.  */
+                   if (REG_P (SET_DEST (PATTERN (insn)))
+                       && REG_P (SET_DEST (PATTERN (dep)))
+                       && reg_overlap_mentioned_p (SET_DEST (PATTERN (insn)),
+                                                   SET_DEST (PATTERN (dep))))
+                     {
+                       /* FMACS is a special case where the dependant
+                          instruction can be issued 3 cycles before
+                          the normal latency in case of an output 
+                          dependency.  */
+                       if ((attr_type_insn == TYPE_FMACS
+                            || attr_type_insn == TYPE_FMACD)
+                           && (attr_type_dep == TYPE_FMACS
+                               || attr_type_dep == TYPE_FMACD))
+                         {
+                           if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+                             *cost = insn_default_latency (dep) - 3;
+                           else
+                             *cost = insn_default_latency (dep);
+                           return false;
+                         }
+                       else
+                         {
+                           if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+                             *cost = insn_default_latency (dep) + 1;
+                           else
+                             *cost = insn_default_latency (dep);
+                         }
+                       return false;
+                     }
+                 }
+             }
+         }
+       break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return true;
+}
+
+/* Adjust cost hook for FA726TE.  */
+static bool
+fa726te_sched_adjust_cost (rtx insn, rtx link, rtx dep, int * cost)
+{
+  /* For FA726TE, true dependency on CPSR (i.e. set cond followed by predicated)
+     have penalty of 3.  */
+  if (REG_NOTE_KIND (link) == REG_DEP_TRUE
+      && recog_memoized (insn) >= 0
+      && recog_memoized (dep) >= 0
+      && get_attr_conds (dep) == CONDS_SET)
+    {
+      /* Use of carry (e.g. 64-bit arithmetic) in ALU: 3-cycle latency.  */
+      if (get_attr_conds (insn) == CONDS_USE
+          && get_attr_type (insn) != TYPE_BRANCH)
+        {
+          *cost = 3;
+          return false;
+        }
+
+      if (GET_CODE (PATTERN (insn)) == COND_EXEC
+          || get_attr_conds (insn) == CONDS_USE)
+        {
+          *cost = 0;
+          return false;
+        }
+    }
+
+  return true;
+}
+
+/* This function implements the target macro TARGET_SCHED_ADJUST_COST.
+   It corrects the value of COST based on the relationship between
+   INSN and DEP through the dependence LINK.  It returns the new
+   value. There is a per-core adjust_cost hook to adjust scheduler costs
+   and the per-core hook can choose to completely override the generic 
+   adjust_cost function. Only put bits of code into arm_adjust_cost that 
+   are common across all cores.  */
+static int
+arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
+{
+  rtx i_pat, d_pat;
+
+ /* When generating Thumb-1 code, we want to place flag-setting operations
+    close to a conditional branch which depends on them, so that we can
+    omit the comparison. */
+  if (TARGET_THUMB1
+      && REG_NOTE_KIND (link) == 0
+      && recog_memoized (insn) == CODE_FOR_cbranchsi4_insn
+      && recog_memoized (dep) >= 0
+      && get_attr_conds (dep) == CONDS_SET)
+    return 0;
+
+  if (current_tune->sched_adjust_cost != NULL)
+    {
+      if (!current_tune->sched_adjust_cost (insn, link, dep, &cost))
+       return cost;
+    }
 
   /* XXX This is not strictly true for the FPA.  */
   if (REG_NOTE_KIND (link) == REG_DEP_ANTI
@@ -7751,7 +8108,8 @@ arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
         constant pool are cached, and that others will miss.  This is a
         hack.  */
 
-      if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
+      if ((GET_CODE (src_mem) == SYMBOL_REF 
+          && CONSTANT_POOL_ADDRESS_P (src_mem))
          || reg_mentioned_p (stack_pointer_rtx, src_mem)
          || reg_mentioned_p (frame_pointer_rtx, src_mem)
          || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
@@ -8655,7 +9013,8 @@ neon_vector_mem_operand (rtx op, int type)
     return arm_address_register_rtx_p (ind, 0);
 
   /* Allow post-increment with Neon registers.  */
-  if (type != 1 && (GET_CODE (ind) == POST_INC || GET_CODE (ind) == PRE_DEC))
+  if ((type != 1 && GET_CODE (ind) == POST_INC)
+      || (type == 0 && GET_CODE (ind) == PRE_DEC))
     return arm_address_register_rtx_p (XEXP (ind, 0), 0);
 
   /* FIXME: vld1 allows register post-modify.  */
@@ -8711,6 +9070,11 @@ neon_struct_mem_operand (rtx op)
   if (GET_CODE (ind) == REG)
     return arm_address_register_rtx_p (ind, 0);
 
+  /* vldm/vstm allows POST_INC (ia) and PRE_DEC (db).  */
+  if (GET_CODE (ind) == POST_INC
+      || GET_CODE (ind) == PRE_DEC)
+    return arm_address_register_rtx_p (XEXP (ind, 0), 0);
+
   return FALSE;
 }
 
@@ -8739,11 +9103,14 @@ coproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
       return GENERAL_REGS;
     }
 
+  /* The neon move patterns handle all legitimate vector and struct
+     addresses.  */
   if (TARGET_NEON
+      && MEM_P (x)
       && (GET_MODE_CLASS (mode) == MODE_VECTOR_INT
-          || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
-      && neon_vector_mem_operand (x, 0))
-     return NO_REGS;
+         || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT
+         || VALID_NEON_STRUCT_MODE (mode)))
+    return NO_REGS;
 
   if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
     return NO_REGS;
@@ -9163,6 +9530,36 @@ multiple_operation_profitable_p (bool is_store ATTRIBUTE_UNUSED,
   if (nops == 2 && arm_ld_sched && add_offset != 0)
     return false;
 
+  /* XScale has load-store double instructions, but they have stricter
+     alignment requirements than load-store multiple, so we cannot
+     use them.
+
+     For XScale ldm requires 2 + NREGS cycles to complete and blocks
+     the pipeline until completion.
+
+       NREGS           CYCLES
+         1               3
+         2               4
+         3               5
+         4               6
+
+     An ldr instruction takes 1-3 cycles, but does not block the
+     pipeline.
+
+       NREGS           CYCLES
+         1              1-3
+         2              2-6
+         3              3-9
+         4              4-12
+
+     Best case ldr will always win.  However, the more ldr instructions
+     we issue, the less likely we are to be able to schedule them well.
+     Using ldr instructions also increases code size.
+
+     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
+     for counts of 3 or 4 regs.  */
+  if (nops <= 2 && arm_tune_xscale && !optimize_size)
+    return false;
   return true;
 }
 
@@ -9206,13 +9603,29 @@ compute_offset_order (int nops, HOST_WIDE_INT *unsorted_offsets, int *order,
   return true;
 }
 
-int
-load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
-                       HOST_WIDE_INT *load_offset)
+/* Used to determine in a peephole whether a sequence of load
+   instructions can be changed into a load-multiple instruction.
+   NOPS is the number of separate load instructions we are examining.  The
+   first NOPS entries in OPERANDS are the destination registers, the
+   next NOPS entries are memory operands.  If this function is
+   successful, *BASE is set to the common base register of the memory
+   accesses; *LOAD_OFFSET is set to the first memory location's offset
+   from that base register.
+   REGS is an array filled in with the destination register numbers.
+   SAVED_ORDER (if nonnull), is an array filled in with an order that maps
+   insn numbers to an ascending order of stores.  If CHECK_REGS is true,
+   the sequence of registers in REGS matches the loads from ascending memory
+   locations, and the function verifies that the register numbers are
+   themselves ascending.  If CHECK_REGS is false, the register numbers
+   are stored in the order they are found in the operands.  */
+static int
+load_multiple_sequence (rtx *operands, int nops, int *regs, int *saved_order,
+                       int *base, HOST_WIDE_INT *load_offset, bool check_regs)
 {
   int unsorted_regs[MAX_LDM_STM_OPS];
   HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
   int order[MAX_LDM_STM_OPS];
+  rtx base_reg_rtx = NULL;
   int base_reg = -1;
   int i, ldm_case;
 
@@ -9256,13 +9669,16 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
                  == CONST_INT)))
        {
          if (i == 0)
-           base_reg = REGNO (reg);
-         else
            {
-             if (base_reg != (int) REGNO (reg))
-               /* Not addressed from the same base register.  */
+             base_reg = REGNO (reg);
+             base_reg_rtx = reg;
+             if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
                return 0;
            }
+         else if (base_reg != (int) REGNO (reg))
+           /* Not addressed from the same base register.  */
+           return 0;
+
          unsorted_regs[i] = (GET_CODE (operands[i]) == REG
                              ? REGNO (operands[i])
                              : REGNO (SUBREG_REG (operands[i])));
@@ -9270,7 +9686,9 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
          /* If it isn't an integer register, or if it overwrites the
             base register but isn't the last insn in the list, then
             we can't do this.  */
-         if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
+         if (unsorted_regs[i] < 0
+             || (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
+             || unsorted_regs[i] > 14
              || (i != nops - 1 && unsorted_regs[i] == base_reg))
            return 0;
 
@@ -9288,26 +9706,34 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
      order[0] has been set to the lowest offset in the list.  Sort
      the offsets into order, verifying that they are adjacent, and
      check that the register numbers are ascending.  */
-  if (!compute_offset_order (nops, unsorted_offsets, order, unsorted_regs))
+  if (!compute_offset_order (nops, unsorted_offsets, order,
+                            check_regs ? unsorted_regs : NULL))
     return 0;
 
+  if (saved_order)
+    memcpy (saved_order, order, sizeof order);
+
   if (base)
     {
       *base = base_reg;
 
       for (i = 0; i < nops; i++)
-       regs[i] = unsorted_regs[order[i]];
+       regs[i] = unsorted_regs[check_regs ? order[i] : i];
 
       *load_offset = unsorted_offsets[order[0]];
     }
 
+  if (TARGET_THUMB1
+      && !peep2_reg_dead_p (nops, base_reg_rtx))
+    return 0;
+
   if (unsorted_offsets[order[0]] == 0)
     ldm_case = 1; /* ldmia */
   else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
     ldm_case = 2; /* ldmib */
   else if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
     ldm_case = 3; /* ldmda */
-  else if (unsorted_offsets[order[nops - 1]] == -4)
+  else if (TARGET_32BIT && unsorted_offsets[order[nops - 1]] == -4)
     ldm_case = 4; /* ldmdb */
   else if (const_ok_for_arm (unsorted_offsets[order[0]])
           || const_ok_for_arm (-unsorted_offsets[order[0]]))
@@ -9323,72 +9749,34 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
   return ldm_case;
 }
 
-const char *
-emit_ldm_seq (rtx *operands, int nops)
-{
-  int regs[MAX_LDM_STM_OPS];
-  int base_reg;
-  HOST_WIDE_INT offset;
-  char buf[100];
-  int i;
-
-  switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
-    {
-    case 1:
-      strcpy (buf, "ldm%(ia%)\t");
-      break;
-
-    case 2:
-      strcpy (buf, "ldm%(ib%)\t");
-      break;
-
-    case 3:
-      strcpy (buf, "ldm%(da%)\t");
-      break;
-
-    case 4:
-      strcpy (buf, "ldm%(db%)\t");
-      break;
-
-    case 5:
-      if (offset >= 0)
-       sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
-                reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
-                (long) offset);
-      else
-       sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
-                reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
-                (long) -offset);
-      output_asm_insn (buf, operands);
-      base_reg = regs[0];
-      strcpy (buf, "ldm%(ia%)\t");
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
-          reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
-
-  for (i = 1; i < nops; i++)
-    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
-            reg_names[regs[i]]);
-
-  strcat (buf, "}\t%@ phole ldm");
-
-  output_asm_insn (buf, operands);
-  return "";
-}
-
-int
-store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
-                        HOST_WIDE_INT * load_offset)
+/* Used to determine in a peephole whether a sequence of store instructions can
+   be changed into a store-multiple instruction.
+   NOPS is the number of separate store instructions we are examining.
+   NOPS_TOTAL is the total number of instructions recognized by the peephole
+   pattern.
+   The first NOPS entries in OPERANDS are the source registers, the next
+   NOPS entries are memory operands.  If this function is successful, *BASE is
+   set to the common base register of the memory accesses; *LOAD_OFFSET is set
+   to the first memory location's offset from that base register.  REGS is an
+   array filled in with the source register numbers, REG_RTXS (if nonnull) is
+   likewise filled with the corresponding rtx's.
+   SAVED_ORDER (if nonnull), is an array filled in with an order that maps insn
+   numbers to an ascending order of stores.
+   If CHECK_REGS is true, the sequence of registers in *REGS matches the stores
+   from ascending memory locations, and the function verifies that the register
+   numbers are themselves ascending.  If CHECK_REGS is false, the register
+   numbers are stored in the order they are found in the operands.  */
+static int
+store_multiple_sequence (rtx *operands, int nops, int nops_total,
+                        int *regs, rtx *reg_rtxs, int *saved_order, int *base,
+                        HOST_WIDE_INT *load_offset, bool check_regs)
 {
   int unsorted_regs[MAX_LDM_STM_OPS];
+  rtx unsorted_reg_rtxs[MAX_LDM_STM_OPS];
   HOST_WIDE_INT unsorted_offsets[MAX_LDM_STM_OPS];
   int order[MAX_LDM_STM_OPS];
   int base_reg = -1;
+  rtx base_reg_rtx = NULL;
   int i, stm_case;
 
   /* Can only handle up to MAX_LDM_STM_OPS insns at present, though could be
@@ -9430,17 +9818,27 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
              && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
                  == CONST_INT)))
        {
-         unsorted_regs[i] = (GET_CODE (operands[i]) == REG
-                             ? REGNO (operands[i])
-                             : REGNO (SUBREG_REG (operands[i])));
+         unsorted_reg_rtxs[i] = (GET_CODE (operands[i]) == REG
+                                 ? operands[i] : SUBREG_REG (operands[i]));
+         unsorted_regs[i] = REGNO (unsorted_reg_rtxs[i]);
+
          if (i == 0)
-           base_reg = REGNO (reg);
+           {
+             base_reg = REGNO (reg);
+             base_reg_rtx = reg;
+             if (TARGET_THUMB1 && base_reg > LAST_LO_REGNUM)
+               return 0;
+           }
          else if (base_reg != (int) REGNO (reg))
            /* Not addressed from the same base register.  */
            return 0;
 
          /* If it isn't an integer register, then we can't do this.  */
-         if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
+         if (unsorted_regs[i] < 0
+             || (TARGET_THUMB1 && unsorted_regs[i] > LAST_LO_REGNUM)
+             || (TARGET_THUMB2 && unsorted_regs[i] == base_reg)
+             || (TARGET_THUMB2 && unsorted_regs[i] == SP_REGNUM)
+             || unsorted_regs[i] > 14)
            return 0;
 
          unsorted_offsets[i] = INTVAL (offset);
@@ -9457,26 +9855,38 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
      order[0] has been set to the lowest offset in the list.  Sort
      the offsets into order, verifying that they are adjacent, and
      check that the register numbers are ascending.  */
-  if (!compute_offset_order (nops, unsorted_offsets, order, unsorted_regs))
+  if (!compute_offset_order (nops, unsorted_offsets, order,
+                            check_regs ? unsorted_regs : NULL))
     return 0;
 
+  if (saved_order)
+    memcpy (saved_order, order, sizeof order);
+
   if (base)
     {
       *base = base_reg;
 
       for (i = 0; i < nops; i++)
-       regs[i] = unsorted_regs[order[i]];
+       {
+         regs[i] = unsorted_regs[check_regs ? order[i] : i];
+         if (reg_rtxs)
+           reg_rtxs[i] = unsorted_reg_rtxs[check_regs ? order[i] : i];
+       }
 
       *load_offset = unsorted_offsets[order[0]];
     }
 
+  if (TARGET_THUMB1
+      && !peep2_reg_dead_p (nops_total, base_reg_rtx))
+    return 0;
+
   if (unsorted_offsets[order[0]] == 0)
     stm_case = 1; /* stmia */
   else if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
     stm_case = 2; /* stmib */
   else if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
     stm_case = 3; /* stmda */
-  else if (unsorted_offsets[order[nops - 1]] == -4)
+  else if (TARGET_32BIT && unsorted_offsets[order[nops - 1]] == -4)
     stm_case = 4; /* stmdb */
   else
     return 0;
@@ -9486,110 +9896,85 @@ store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
 
   return stm_case;
 }
+\f
+/* Routines for use in generating RTL.  */
 
-const char *
-emit_stm_seq (rtx *operands, int nops)
+/* Generate a load-multiple instruction.  COUNT is the number of loads in
+   the instruction; REGS and MEMS are arrays containing the operands.
+   BASEREG is the base register to be used in addressing the memory operands.
+   WBACK_OFFSET is nonzero if the instruction should update the base
+   register.  */
+
+static rtx
+arm_gen_load_multiple_1 (int count, int *regs, rtx *mems, rtx basereg,
+                        HOST_WIDE_INT wback_offset)
 {
-  int regs[MAX_LDM_STM_OPS];
-  int base_reg;
-  HOST_WIDE_INT offset;
-  char buf[100];
-  int i;
+  int i = 0, j;
+  rtx result;
 
-  switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
+  if (!multiple_operation_profitable_p (false, count, 0))
     {
-    case 1:
-      strcpy (buf, "stm%(ia%)\t");
-      break;
+      rtx seq;
 
-    case 2:
-      strcpy (buf, "stm%(ib%)\t");
-      break;
+      start_sequence ();
 
-    case 3:
-      strcpy (buf, "stm%(da%)\t");
-      break;
+      for (i = 0; i < count; i++)
+       emit_move_insn (gen_rtx_REG (SImode, regs[i]), mems[i]);
 
-    case 4:
-      strcpy (buf, "stm%(db%)\t");
-      break;
+      if (wback_offset != 0)
+       emit_move_insn (basereg, plus_constant (basereg, wback_offset));
 
-    default:
-      gcc_unreachable ();
-    }
+      seq = get_insns ();
+      end_sequence ();
 
-  sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
-          reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
+      return seq;
+    }
 
-  for (i = 1; i < nops; i++)
-    sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
-            reg_names[regs[i]]);
+  result = gen_rtx_PARALLEL (VOIDmode,
+                            rtvec_alloc (count + (wback_offset != 0 ? 1 : 0)));
+  if (wback_offset != 0)
+    {
+      XVECEXP (result, 0, 0)
+       = gen_rtx_SET (VOIDmode, basereg,
+                      plus_constant (basereg, wback_offset));
+      i = 1;
+      count++;
+    }
 
-  strcat (buf, "}\t%@ phole stm");
+  for (j = 0; i < count; i++, j++)
+    XVECEXP (result, 0, i)
+      = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regs[j]), mems[j]);
 
-  output_asm_insn (buf, operands);
-  return "";
+  return result;
 }
-\f
-/* Routines for use in generating RTL.  */
 
-rtx
-arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
-                      int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
+/* Generate a store-multiple instruction.  COUNT is the number of stores in
+   the instruction; REGS and MEMS are arrays containing the operands.
+   BASEREG is the base register to be used in addressing the memory operands.
+   WBACK_OFFSET is nonzero if the instruction should update the base
+   register.  */
+
+static rtx
+arm_gen_store_multiple_1 (int count, int *regs, rtx *mems, rtx basereg,
+                         HOST_WIDE_INT wback_offset)
 {
-  HOST_WIDE_INT offset = *offsetp;
   int i = 0, j;
   rtx result;
-  int sign = up ? 1 : -1;
-  rtx mem, addr;
 
-  /* XScale has load-store double instructions, but they have stricter
-     alignment requirements than load-store multiple, so we cannot
-     use them.
+  if (GET_CODE (basereg) == PLUS)
+    basereg = XEXP (basereg, 0);
 
-     For XScale ldm requires 2 + NREGS cycles to complete and blocks
-     the pipeline until completion.
-
-       NREGS           CYCLES
-         1               3
-         2               4
-         3               5
-         4               6
-
-     An ldr instruction takes 1-3 cycles, but does not block the
-     pipeline.
-
-       NREGS           CYCLES
-         1              1-3
-         2              2-6
-         3              3-9
-         4              4-12
-
-     Best case ldr will always win.  However, the more ldr instructions
-     we issue, the less likely we are to be able to schedule them well.
-     Using ldr instructions also increases code size.
-
-     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
-     for counts of 3 or 4 regs.  */
-  if (arm_tune_xscale && count <= 2 && ! optimize_size)
+  if (!multiple_operation_profitable_p (false, count, 0))
     {
       rtx seq;
 
       start_sequence ();
 
       for (i = 0; i < count; i++)
-       {
-         addr = plus_constant (from, i * 4 * sign);
-         mem = adjust_automodify_address (basemem, SImode, addr, offset);
-         emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
-         offset += 4 * sign;
-       }
+       emit_move_insn (mems[i], gen_rtx_REG (SImode, regs[i]));
 
-      if (write_back)
-       {
-         emit_move_insn (from, plus_constant (from, count * 4 * sign));
-         *offsetp = offset;
-       }
+      if (wback_offset != 0)
+       emit_move_insn (basereg, plus_constant (basereg, wback_offset));
 
       seq = get_insns ();
       end_sequence ();
@@ -9598,92 +9983,319 @@ arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
     }
 
   result = gen_rtx_PARALLEL (VOIDmode,
-                            rtvec_alloc (count + (write_back ? 1 : 0)));
-  if (write_back)
+                            rtvec_alloc (count + (wback_offset != 0 ? 1 : 0)));
+  if (wback_offset != 0)
     {
       XVECEXP (result, 0, 0)
-       = gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
+       = gen_rtx_SET (VOIDmode, basereg,
+                      plus_constant (basereg, wback_offset));
       i = 1;
       count++;
     }
 
   for (j = 0; i < count; i++, j++)
+    XVECEXP (result, 0, i)
+      = gen_rtx_SET (VOIDmode, mems[j], gen_rtx_REG (SImode, regs[j]));
+
+  return result;
+}
+
+/* Generate either a load-multiple or a store-multiple instruction.  This
+   function can be used in situations where we can start with a single MEM
+   rtx and adjust its address upwards.
+   COUNT is the number of operations in the instruction, not counting a
+   possible update of the base register.  REGS is an array containing the
+   register operands.
+   BASEREG is the base register to be used in addressing the memory operands,
+   which are constructed from BASEMEM.
+   WRITE_BACK specifies whether the generated instruction should include an
+   update of the base register.
+   OFFSETP is used to pass an offset to and from this function; this offset
+   is not used when constructing the address (instead BASEMEM should have an
+   appropriate offset in its address), it is used only for setting
+   MEM_OFFSET.  It is updated only if WRITE_BACK is true.*/
+
+static rtx
+arm_gen_multiple_op (bool is_load, int *regs, int count, rtx basereg,
+                    bool write_back, rtx basemem, HOST_WIDE_INT *offsetp)
+{
+  rtx mems[MAX_LDM_STM_OPS];
+  HOST_WIDE_INT offset = *offsetp;
+  int i;
+
+  gcc_assert (count <= MAX_LDM_STM_OPS);
+
+  if (GET_CODE (basereg) == PLUS)
+    basereg = XEXP (basereg, 0);
+
+  for (i = 0; i < count; i++)
     {
-      addr = plus_constant (from, j * 4 * sign);
-      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
-      XVECEXP (result, 0, i)
-       = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
-      offset += 4 * sign;
+      rtx addr = plus_constant (basereg, i * 4);
+      mems[i] = adjust_automodify_address_nv (basemem, SImode, addr, offset);
+      offset += 4;
     }
 
   if (write_back)
     *offsetp = offset;
 
-  return result;
+  if (is_load)
+    return arm_gen_load_multiple_1 (count, regs, mems, basereg,
+                                   write_back ? 4 * count : 0);
+  else
+    return arm_gen_store_multiple_1 (count, regs, mems, basereg,
+                                    write_back ? 4 * count : 0);
 }
 
 rtx
-arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
-                       int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
+arm_gen_load_multiple (int *regs, int count, rtx basereg, int write_back,
+                      rtx basemem, HOST_WIDE_INT *offsetp)
 {
-  HOST_WIDE_INT offset = *offsetp;
-  int i = 0, j;
-  rtx result;
-  int sign = up ? 1 : -1;
-  rtx mem, addr;
+  return arm_gen_multiple_op (TRUE, regs, count, basereg, write_back, basemem,
+                             offsetp);
+}
 
-  /* See arm_gen_load_multiple for discussion of
-     the pros/cons of ldm/stm usage for XScale.  */
-  if (arm_tune_xscale && count <= 2 && ! optimize_size)
-    {
-      rtx seq;
+rtx
+arm_gen_store_multiple (int *regs, int count, rtx basereg, int write_back,
+                       rtx basemem, HOST_WIDE_INT *offsetp)
+{
+  return arm_gen_multiple_op (FALSE, regs, count, basereg, write_back, basemem,
+                             offsetp);
+}
 
-      start_sequence ();
+/* Called from a peephole2 expander to turn a sequence of loads into an
+   LDM instruction.  OPERANDS are the operands found by the peephole matcher;
+   NOPS indicates how many separate loads we are trying to combine.  SORT_REGS
+   is true if we can reorder the registers because they are used commutatively
+   subsequently.
+   Returns true iff we could generate a new instruction.  */
 
-      for (i = 0; i < count; i++)
-       {
-         addr = plus_constant (to, i * 4 * sign);
-         mem = adjust_automodify_address (basemem, SImode, addr, offset);
-         emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
-         offset += 4 * sign;
-       }
+bool
+gen_ldm_seq (rtx *operands, int nops, bool sort_regs)
+{
+  int regs[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
+  rtx mems[MAX_LDM_STM_OPS];
+  int i, j, base_reg;
+  rtx base_reg_rtx;
+  HOST_WIDE_INT offset;
+  int write_back = FALSE;
+  int ldm_case;
+  rtx addr;
 
-      if (write_back)
+  ldm_case = load_multiple_sequence (operands, nops, regs, mem_order,
+                                    &base_reg, &offset, !sort_regs);
+
+  if (ldm_case == 0)
+    return false;
+
+  if (sort_regs)
+    for (i = 0; i < nops - 1; i++)
+      for (j = i + 1; j < nops; j++)
+       if (regs[i] > regs[j])
+         {
+           int t = regs[i];
+           regs[i] = regs[j];
+           regs[j] = t;
+         }
+  base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
+
+  if (TARGET_THUMB1)
+    {
+      gcc_assert (peep2_reg_dead_p (nops, base_reg_rtx));
+      gcc_assert (ldm_case == 1 || ldm_case == 5);
+      write_back = TRUE;
+    }
+
+  if (ldm_case == 5)
+    {
+      rtx newbase = TARGET_THUMB1 ? base_reg_rtx : gen_rtx_REG (SImode, regs[0]);
+      emit_insn (gen_addsi3 (newbase, base_reg_rtx, GEN_INT (offset)));
+      offset = 0;
+      if (!TARGET_THUMB1)
        {
-         emit_move_insn (to, plus_constant (to, count * 4 * sign));
-         *offsetp = offset;
+         base_reg = regs[0];
+         base_reg_rtx = newbase;
        }
+    }
 
-      seq = get_insns ();
-      end_sequence ();
+  for (i = 0; i < nops; i++)
+    {
+      addr = plus_constant (base_reg_rtx, offset + i * 4);
+      mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
+                                             SImode, addr, 0);
+    }
+  emit_insn (arm_gen_load_multiple_1 (nops, regs, mems, base_reg_rtx,
+                                     write_back ? offset + i * 4 : 0));
+  return true;
+}
 
-      return seq;
+/* Called from a peephole2 expander to turn a sequence of stores into an
+   STM instruction.  OPERANDS are the operands found by the peephole matcher;
+   NOPS indicates how many separate stores we are trying to combine.
+   Returns true iff we could generate a new instruction.  */
+
+bool
+gen_stm_seq (rtx *operands, int nops)
+{
+  int i;
+  int regs[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
+  rtx mems[MAX_LDM_STM_OPS];
+  int base_reg;
+  rtx base_reg_rtx;
+  HOST_WIDE_INT offset;
+  int write_back = FALSE;
+  int stm_case;
+  rtx addr;
+  bool base_reg_dies;
+
+  stm_case = store_multiple_sequence (operands, nops, nops, regs, NULL,
+                                     mem_order, &base_reg, &offset, true);
+
+  if (stm_case == 0)
+    return false;
+
+  base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
+
+  base_reg_dies = peep2_reg_dead_p (nops, base_reg_rtx);
+  if (TARGET_THUMB1)
+    {
+      gcc_assert (base_reg_dies);
+      write_back = TRUE;
     }
 
-  result = gen_rtx_PARALLEL (VOIDmode,
-                            rtvec_alloc (count + (write_back ? 1 : 0)));
-  if (write_back)
+  if (stm_case == 5)
     {
-      XVECEXP (result, 0, 0)
-       = gen_rtx_SET (VOIDmode, to,
-                      plus_constant (to, count * 4 * sign));
-      i = 1;
-      count++;
+      gcc_assert (base_reg_dies);
+      emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, GEN_INT (offset)));
+      offset = 0;
     }
 
-  for (j = 0; i < count; i++, j++)
+  addr = plus_constant (base_reg_rtx, offset);
+
+  for (i = 0; i < nops; i++)
     {
-      addr = plus_constant (to, j * 4 * sign);
-      mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
-      XVECEXP (result, 0, i)
-       = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
-      offset += 4 * sign;
+      addr = plus_constant (base_reg_rtx, offset + i * 4);
+      mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
+                                             SImode, addr, 0);
     }
+  emit_insn (arm_gen_store_multiple_1 (nops, regs, mems, base_reg_rtx,
+                                      write_back ? offset + i * 4 : 0));
+  return true;
+}
 
-  if (write_back)
-    *offsetp = offset;
+/* Called from a peephole2 expander to turn a sequence of stores that are
+   preceded by constant loads into an STM instruction.  OPERANDS are the
+   operands found by the peephole matcher; NOPS indicates how many
+   separate stores we are trying to combine; there are 2 * NOPS
+   instructions in the peephole.
+   Returns true iff we could generate a new instruction.  */
 
-  return result;
+bool
+gen_const_stm_seq (rtx *operands, int nops)
+{
+  int regs[MAX_LDM_STM_OPS], sorted_regs[MAX_LDM_STM_OPS];
+  int reg_order[MAX_LDM_STM_OPS], mem_order[MAX_LDM_STM_OPS];
+  rtx reg_rtxs[MAX_LDM_STM_OPS], orig_reg_rtxs[MAX_LDM_STM_OPS];
+  rtx mems[MAX_LDM_STM_OPS];
+  int base_reg;
+  rtx base_reg_rtx;
+  HOST_WIDE_INT offset;
+  int write_back = FALSE;
+  int stm_case;
+  rtx addr;
+  bool base_reg_dies;
+  int i, j;
+  HARD_REG_SET allocated;
+
+  stm_case = store_multiple_sequence (operands, nops, 2 * nops, regs, reg_rtxs,
+                                     mem_order, &base_reg, &offset, false);
+
+  if (stm_case == 0)
+    return false;
+
+  memcpy (orig_reg_rtxs, reg_rtxs, sizeof orig_reg_rtxs);
+
+  /* If the same register is used more than once, try to find a free
+     register.  */
+  CLEAR_HARD_REG_SET (allocated);
+  for (i = 0; i < nops; i++)
+    {
+      for (j = i + 1; j < nops; j++)
+       if (regs[i] == regs[j])
+         {
+           rtx t = peep2_find_free_register (0, nops * 2,
+                                             TARGET_THUMB1 ? "l" : "r",
+                                             SImode, &allocated);
+           if (t == NULL_RTX)
+             return false;
+           reg_rtxs[i] = t;
+           regs[i] = REGNO (t);
+         }
+    }
+
+  /* Compute an ordering that maps the register numbers to an ascending
+     sequence.  */
+  reg_order[0] = 0;
+  for (i = 0; i < nops; i++)
+    if (regs[i] < regs[reg_order[0]])
+      reg_order[0] = i;
+
+  for (i = 1; i < nops; i++)
+    {
+      int this_order = reg_order[i - 1];
+      for (j = 0; j < nops; j++)
+       if (regs[j] > regs[reg_order[i - 1]]
+           && (this_order == reg_order[i - 1]
+               || regs[j] < regs[this_order]))
+         this_order = j;
+      reg_order[i] = this_order;
+    }
+
+  /* Ensure that registers that must be live after the instruction end
+     up with the correct value.  */
+  for (i = 0; i < nops; i++)
+    {
+      int this_order = reg_order[i];
+      if ((this_order != mem_order[i]
+          || orig_reg_rtxs[this_order] != reg_rtxs[this_order])
+         && !peep2_reg_dead_p (nops * 2, orig_reg_rtxs[this_order]))
+       return false;
+    }
+
+  /* Load the constants.  */
+  for (i = 0; i < nops; i++)
+    {
+      rtx op = operands[2 * nops + mem_order[i]];
+      sorted_regs[i] = regs[reg_order[i]];
+      emit_move_insn (reg_rtxs[reg_order[i]], op);
+    }
+
+  base_reg_rtx = gen_rtx_REG (Pmode, base_reg);
+
+  base_reg_dies = peep2_reg_dead_p (nops * 2, base_reg_rtx);
+  if (TARGET_THUMB1)
+    {
+      gcc_assert (base_reg_dies);
+      write_back = TRUE;
+    }
+
+  if (stm_case == 5)
+    {
+      gcc_assert (base_reg_dies);
+      emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, GEN_INT (offset)));
+      offset = 0;
+    }
+
+  addr = plus_constant (base_reg_rtx, offset);
+
+  for (i = 0; i < nops; i++)
+    {
+      addr = plus_constant (base_reg_rtx, offset + i * 4);
+      mems[i] = adjust_automodify_address_nv (operands[nops + mem_order[i]],
+                                             SImode, addr, 0);
+    }
+  emit_insn (arm_gen_store_multiple_1 (nops, sorted_regs, mems, base_reg_rtx,
+                                      write_back ? offset + i * 4 : 0));
+  return true;
 }
 
 int
@@ -9719,20 +10331,21 @@ arm_gen_movmemqi (rtx *operands)
   for (i = 0; in_words_to_go >= 2; i+=4)
     {
       if (in_words_to_go > 4)
-       emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
-                                         srcbase, &srcoffset));
+       emit_insn (arm_gen_load_multiple (arm_regs_in_sequence, 4, src,
+                                         TRUE, srcbase, &srcoffset));
       else
-       emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
-                                         FALSE, srcbase, &srcoffset));
+       emit_insn (arm_gen_load_multiple (arm_regs_in_sequence, in_words_to_go,
+                                         src, FALSE, srcbase,
+                                         &srcoffset));
 
       if (out_words_to_go)
        {
          if (out_words_to_go > 4)
-           emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
-                                              dstbase, &dstoffset));
+           emit_insn (arm_gen_store_multiple (arm_regs_in_sequence, 4, dst,
+                                              TRUE, dstbase, &dstoffset));
          else if (out_words_to_go != 1)
-           emit_insn (arm_gen_store_multiple (0, out_words_to_go,
-                                              dst, TRUE,
+           emit_insn (arm_gen_store_multiple (arm_regs_in_sequence,
+                                              out_words_to_go, dst,
                                               (last_bytes == 0
                                                ? FALSE : TRUE),
                                               dstbase, &dstoffset));
@@ -10060,12 +10673,14 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
 
   /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
   if (GET_CODE (x) == AND
+      && (op == EQ || op == NE)
       && COMPARISON_P (XEXP (x, 0))
       && COMPARISON_P (XEXP (x, 1)))
     return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
                                         DOM_CC_X_AND_Y);
 
   if (GET_CODE (x) == IOR
+      && (op == EQ || op == NE)
       && COMPARISON_P (XEXP (x, 0))
       && COMPARISON_P (XEXP (x, 1)))
     return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
@@ -10233,14 +10848,14 @@ arm_reload_in_hi (rtx *operands)
         are two cases here: the first where there is a simple
         stack-slot replacement and a second where the stack-slot is
         out of range, or is used as a subreg.  */
-      if (reg_equiv_mem[REGNO (ref)])
+      if (reg_equiv_mem (REGNO (ref)))
        {
-         ref = reg_equiv_mem[REGNO (ref)];
+         ref = reg_equiv_mem (REGNO (ref));
          base = find_replacement (&XEXP (ref, 0));
        }
       else
        /* The slot is out of range, or was dressed up in a SUBREG.  */
-       base = reg_equiv_address[REGNO (ref)];
+       base = reg_equiv_address (REGNO (ref));
     }
   else
     base = find_replacement (&XEXP (ref, 0));
@@ -10350,14 +10965,14 @@ arm_reload_out_hi (rtx *operands)
         are two cases here: the first where there is a simple
         stack-slot replacement and a second where the stack-slot is
         out of range, or is used as a subreg.  */
-      if (reg_equiv_mem[REGNO (ref)])
+      if (reg_equiv_mem (REGNO (ref)))
        {
-         ref = reg_equiv_mem[REGNO (ref)];
+         ref = reg_equiv_mem (REGNO (ref));
          base = find_replacement (&XEXP (ref, 0));
        }
       else
        /* The slot is out of range, or was dressed up in a SUBREG.  */
-       base = reg_equiv_address[REGNO (ref)];
+       base = reg_equiv_address (REGNO (ref));
     }
   else
     base = find_replacement (&XEXP (ref, 0));
@@ -11374,6 +11989,16 @@ create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
   /* Make sure that we found a place to insert the jump.  */
   gcc_assert (selected);
 
+  /* Make sure we do not split a call and its corresponding
+     CALL_ARG_LOCATION note.  */
+  if (CALL_P (selected))
+    {
+      rtx next = NEXT_INSN (selected);
+      if (next && NOTE_P (next)
+         && NOTE_KIND (next) == NOTE_INSN_CALL_ARG_LOCATION)
+         selected = next;
+    }
+
   /* Create a new JUMP_INSN that branches around a barrier.  */
   from = emit_jump_insn_after (gen_jump (label), selected);
   JUMP_LABEL (from) = label;
@@ -11646,6 +12271,7 @@ thumb2_reorg (void)
   FOR_EACH_BB (bb)
     {
       rtx insn;
+
       COPY_REG_SET (&live, DF_LR_OUT (bb));
       df_simulate_initialize_backwards (bb, &live);
       FOR_BB_INSNS_REVERSE (bb, insn)
@@ -11663,21 +12289,43 @@ thumb2_reorg (void)
                  rtx dst = XEXP (pat, 0);
                  rtx src = XEXP (pat, 1);
                  rtx op0 = XEXP (src, 0);
+                 rtx op1 = (GET_RTX_CLASS (GET_CODE (src)) == RTX_COMM_ARITH
+                            ? XEXP (src, 1) : NULL);
+
                  if (rtx_equal_p (dst, op0)
                      || GET_CODE (src) == PLUS || GET_CODE (src) == MINUS)
                    {
                      rtx ccreg = gen_rtx_REG (CCmode, CC_REGNUM);
                      rtx clobber = gen_rtx_CLOBBER (VOIDmode, ccreg);
                      rtvec vec = gen_rtvec (2, pat, clobber);
+
+                     PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec);
+                     INSN_CODE (insn) = -1;
+                   }
+                 /* We can also handle a commutative operation where the
+                    second operand matches the destination.  */
+                 else if (op1 && rtx_equal_p (dst, op1))
+                   {
+                     rtx ccreg = gen_rtx_REG (CCmode, CC_REGNUM);
+                     rtx clobber = gen_rtx_CLOBBER (VOIDmode, ccreg);
+                     rtvec vec;
+
+                     src = copy_rtx (src);
+                     XEXP (src, 0) = op1;
+                     XEXP (src, 1) = op0;
+                     pat = gen_rtx_SET (VOIDmode, dst, src);
+                     vec = gen_rtvec (2, pat, clobber);
                      PATTERN (insn) = gen_rtx_PARALLEL (VOIDmode, vec);
                      INSN_CODE (insn) = -1;
                    }
                }
            }
+
          if (NONDEBUG_INSN_P (insn))
            df_simulate_one_insn_backwards (bb, insn, &live);
        }
     }
+
   CLEAR_REG_SET (&live);
 }
 
@@ -12292,9 +12940,8 @@ output_mov_double_arm_from_fpa (rtx *operands)
   return "";
 }
 
-/* Output a move between double words.
-   It must be REG<-REG, REG<-CONST_DOUBLE, REG<-CONST_INT, REG<-MEM
-   or MEM<-REG and all MEMs must be offsettable addresses.  */
+/* Output a move between double words.  It must be REG<-MEM
+   or MEM<-REG.  */
 const char *
 output_move_double (rtx *operands)
 {
@@ -12567,13 +13214,13 @@ output_move_double (rtx *operands)
            {
              if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
                {
-                 output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
-                 output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
+                 output_asm_insn ("str%?\t%0, [%1, %2]!", otherops);
+                 output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
                }
              else
                {
-                 output_asm_insn ("ldr%?\t%H0, [%1, #4]", otherops);
-                 output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
+                 output_asm_insn ("str%?\t%H0, [%1, #4]", otherops);
+                 output_asm_insn ("str%?\t%0, [%1], %2", otherops);
                }
            }
          else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
@@ -12933,6 +13580,34 @@ arm_attr_length_move_neon (rtx insn)
     return 4;
 }
 
+/* Return nonzero if the offset in the address is an immediate.  Otherwise,
+   return zero.  */
+
+int
+arm_address_offset_is_imm (rtx insn)
+{
+  rtx mem, addr;
+
+  extract_insn_cached (insn);
+
+  if (REG_P (recog_data.operand[0]))
+    return 0;
+
+  mem = recog_data.operand[0];
+
+  gcc_assert (MEM_P (mem));
+
+  addr = XEXP (mem, 0);
+
+  if (GET_CODE (addr) == REG
+      || (GET_CODE (addr) == PLUS
+         && GET_CODE (XEXP (addr, 0)) == REG
+         && GET_CODE (XEXP (addr, 1)) == CONST_INT))
+    return 1;
+  else
+    return 0;
+}
+
 /* Output an ADD r, s, #n where n may be too big for one instruction.
    If adding zero to one register, output nothing.  */
 const char *
@@ -14090,7 +14765,8 @@ arm_output_epilogue (rtx sibling)
                  && !crtl->tail_call_emit)
                {
                  unsigned long mask;
-                 mask = (1 << (arm_size_return_regs() / 4)) - 1;
+                  /* Preserve return values, of any size.  */
+                 mask = (1 << ((arm_size_return_regs() + 3) / 4)) - 1;
                  mask ^= 0xf;
                  mask &= ~saved_regs_mask;
                  reg = 0;
@@ -14549,6 +15225,31 @@ thumb_force_lr_save (void)
 }
 
 
+/* Return true if r3 is used by any of the tail call insns in the
+   current function.  */
+
+static bool
+any_sibcall_uses_r3 (void)
+{
+  edge_iterator ei;
+  edge e;
+
+  if (!crtl->tail_call_emit)
+    return false;
+  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
+    if (e->flags & EDGE_SIBCALL)
+      {
+       rtx call = BB_END (e->src);
+       if (!CALL_P (call))
+         call = prev_nonnote_nondebug_insn (call);
+       gcc_assert (CALL_P (call) && SIBLING_CALL_P (call));
+       if (find_regno_fusage (call, USE, 3))
+         return true;
+      }
+  return false;
+}
+
+
 /* Compute the distance from register FROM to register TO.
    These can be the arg pointer (26), the soft frame pointer (25),
    the stack pointer (13) or the hard frame pointer (11).
@@ -14691,7 +15392,10 @@ arm_get_frame_offsets (void)
   offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
   /* A leaf function does not need any stack alignment if it has nothing
      on the stack.  */
-  if (leaf && frame_size == 0)
+  if (leaf && frame_size == 0
+      /* However if it calls alloca(), we have a dynamically allocated
+        block of BIGGEST_ALIGNMENT on stack, so still do stack alignment.  */
+      && ! cfun->calls_alloca)
     {
       offsets->outgoing_args = offsets->soft_frame;
       offsets->locals_base = offsets->soft_frame;
@@ -14713,7 +15417,7 @@ arm_get_frame_offsets (void)
          /* If it is safe to use r3, then do so.  This sometimes 
             generates better code on Thumb-2 by avoiding the need to
             use 32-bit push/pop instructions.  */
-         if (!crtl->tail_call_emit
+         if (! any_sibcall_uses_r3 ()
              && arm_size_return_regs () <= 12
              && (offsets->saved_regs_mask & (1 << 3)) == 0)
            {
@@ -15222,6 +15926,10 @@ arm_expand_prologue (void)
        }
     }
 
+  if (flag_stack_usage)
+    current_function_static_stack_size
+      = offsets->outgoing_args - offsets->saved_args;
+
   if (offsets->outgoing_args != offsets->saved_args + saved_regs)
     {
       /* This add can produce multiple insns for a large constant, so we
@@ -15269,7 +15977,8 @@ arm_expand_prologue (void)
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
   if (crtl->profile || !TARGET_SCHED_PROLOG
-      || (ARM_EABI_UNWIND_TABLES && cfun->can_throw_non_call_exceptions))
+      || (arm_except_unwind_info (&global_options) == UI_TARGET
+         && cfun->can_throw_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   /* If the link register is being kept alive, with the return address in it,
@@ -15862,6 +16571,8 @@ arm_print_operand (FILE *stream, rtx x, int code)
       {
        rtx addr;
        bool postinc = FALSE;
+       unsigned align, memsize, align_bits;
+
        gcc_assert (GET_CODE (x) == MEM);
        addr = XEXP (x, 0);
        if (GET_CODE (addr) == POST_INC)
@@ -15869,12 +16580,45 @@ arm_print_operand (FILE *stream, rtx x, int code)
            postinc = 1;
            addr = XEXP (addr, 0);
          }
-       asm_fprintf (stream, "[%r]", REGNO (addr));
+       asm_fprintf (stream, "[%r", REGNO (addr));
+
+       /* We know the alignment of this access, so we can emit a hint in the
+          instruction (for some alignments) as an aid to the memory subsystem
+          of the target.  */
+       align = MEM_ALIGN (x) >> 3;
+       memsize = INTVAL (MEM_SIZE (x));
+       
+       /* Only certain alignment specifiers are supported by the hardware.  */
+       if (memsize == 16 && (align % 32) == 0)
+         align_bits = 256;
+       else if ((memsize == 8 || memsize == 16) && (align % 16) == 0)
+         align_bits = 128;
+       else if ((align % 8) == 0)
+         align_bits = 64;
+       else
+         align_bits = 0;
+       
+       if (align_bits != 0)
+         asm_fprintf (stream, ":%d", align_bits);
+
+       asm_fprintf (stream, "]");
+
        if (postinc)
          fputs("!", stream);
       }
       return;
 
+    case 'C':
+      {
+       rtx addr;
+
+       gcc_assert (GET_CODE (x) == MEM);
+       addr = XEXP (x, 0);
+       gcc_assert (GET_CODE (addr) == REG);
+       asm_fprintf (stream, "[%r]", REGNO (addr));
+      }
+      return;
+
     /* Translate an S register number into a D register number and element index.  */
     case 'y':
       {
@@ -17507,12 +18251,14 @@ enum neon_builtin_type_bits {
   T_V2SI  = 0x0004,
   T_V2SF  = 0x0008,
   T_DI    = 0x0010,
+  T_DREG  = 0x001F,
   T_V16QI = 0x0020,
   T_V8HI  = 0x0040,
   T_V4SI  = 0x0080,
   T_V4SF  = 0x0100,
   T_V2DI  = 0x0200,
   T_TI   = 0x0400,
+  T_QREG  = 0x07E0,
   T_EI   = 0x0800,
   T_OI   = 0x1000
 };
@@ -18151,17 +18897,16 @@ arm_init_neon_builtins (void)
                /* Build a function type directly from the insn_data for this
                   builtin.  The build_function_type() function takes care of
                   removing duplicates for us.  */
-               for (k = insn_data[icode].n_operands - 1; k >= 0; k--)
+               for (k = insn_data[icode].n_generator_args - 1; k >= 0; k--)
                  {
                    tree eltype;
 
                    if (is_load && k == 1)
                      {
                        /* Neon load patterns always have the memory operand
-                          (a SImode pointer) in the operand 1 position.  We
-                          want a const pointer to the element type in that
-                          position.  */
-                       gcc_assert (insn_data[icode].operand[k].mode == SImode);
+                          in the operand 1 position.  */
+                       gcc_assert (insn_data[icode].operand[k].predicate
+                                   == neon_struct_operand);
 
                        switch (1 << j)
                          {
@@ -18196,10 +18941,9 @@ arm_init_neon_builtins (void)
                    else if (is_store && k == 0)
                      {
                        /* Similarly, Neon store patterns use operand 0 as
-                          the memory location to store to (a SImode pointer).
-                          Use a pointer to the element type of the store in
-                          that position.  */
-                       gcc_assert (insn_data[icode].operand[k].mode == SImode);
+                          the memory location to store to.  */
+                       gcc_assert (insn_data[icode].operand[k].predicate
+                                   == neon_struct_operand);
 
                        switch (1 << j)
                          {
@@ -18519,10 +19263,13 @@ neon_builtin_compare (const void *a, const void *b)
 }
 
 static enum insn_code
-locate_neon_builtin_icode (int fcode, neon_itype *itype)
+locate_neon_builtin_icode (int fcode, neon_itype *itype,
+                          enum neon_builtin_type_bits *type_bit)
 {
-  neon_builtin_datum key, *found;
-  int idx;
+  neon_builtin_datum key
+    = { NULL, (neon_itype) 0, 0, { CODE_FOR_nothing }, 0, 0 };
+  neon_builtin_datum *found;
+  int idx, type, ntypes;
 
   key.base_fcode = fcode;
   found = (neon_builtin_datum *)
@@ -18535,20 +19282,84 @@ locate_neon_builtin_icode (int fcode, neon_itype *itype)
   if (itype)
     *itype = found->itype;
 
+  if (type_bit)
+    {
+      ntypes = 0;
+      for (type = 0; type < T_MAX; type++)
+       if (found->bits & (1 << type))
+         {
+           if (ntypes == idx)
+             break;
+           ntypes++;
+         }
+      gcc_assert (type < T_MAX);
+      *type_bit = (enum neon_builtin_type_bits) (1 << type);
+    }
   return found->codes[idx];
 }
 
 typedef enum {
   NEON_ARG_COPY_TO_REG,
   NEON_ARG_CONSTANT,
+  NEON_ARG_MEMORY,
   NEON_ARG_STOP
 } builtin_arg;
 
 #define NEON_MAX_BUILTIN_ARGS 5
 
+/* EXP is a pointer argument to a Neon load or store intrinsic.  Derive
+   and return an expression for the accessed memory.
+
+   The intrinsic function operates on a block of registers that has
+   mode REG_MODE.  This block contains vectors of type TYPE_BIT.
+   The function references the memory at EXP in mode MEM_MODE;
+   this mode may be BLKmode if no more suitable mode is available.  */
+
+static tree
+neon_dereference_pointer (tree exp, enum machine_mode mem_mode,
+                         enum machine_mode reg_mode,
+                         enum neon_builtin_type_bits type_bit)
+{
+  HOST_WIDE_INT reg_size, vector_size, nvectors, nelems;
+  tree elem_type, upper_bound, array_type;
+
+  /* Work out the size of the register block in bytes.  */
+  reg_size = GET_MODE_SIZE (reg_mode);
+
+  /* Work out the size of each vector in bytes.  */
+  gcc_assert (type_bit & (T_DREG | T_QREG));
+  vector_size = (type_bit & T_QREG ? 16 : 8);
+
+  /* Work out how many vectors there are.  */
+  gcc_assert (reg_size % vector_size == 0);
+  nvectors = reg_size / vector_size;
+
+  /* Work out how many elements are being loaded or stored.
+     MEM_MODE == REG_MODE implies a one-to-one mapping between register
+     and memory elements; anything else implies a lane load or store.  */
+  if (mem_mode == reg_mode)
+    nelems = vector_size * nvectors;
+  else
+    nelems = nvectors;
+
+  /* Work out the type of each element.  */
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp)));
+  elem_type = TREE_TYPE (TREE_TYPE (exp));
+
+  /* Create a type that describes the full access.  */
+  upper_bound = build_int_cst (size_type_node, nelems - 1);
+  array_type = build_array_type (elem_type, build_index_type (upper_bound));
+
+  /* Dereference EXP using that type.  */
+  exp = convert (build_pointer_type (array_type), exp);
+  return fold_build2 (MEM_REF, array_type, exp,
+                     build_int_cst (TREE_TYPE (exp), 0));
+}
+
 /* Expand a Neon builtin.  */
 static rtx
 arm_expand_neon_args (rtx target, int icode, int have_retval,
+                     enum neon_builtin_type_bits type_bit,
                      tree exp, ...)
 {
   va_list ap;
@@ -18557,7 +19368,9 @@ arm_expand_neon_args (rtx target, int icode, int have_retval,
   rtx op[NEON_MAX_BUILTIN_ARGS];
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode[NEON_MAX_BUILTIN_ARGS];
+  enum machine_mode other_mode;
   int argc = 0;
+  int opno;
 
   if (have_retval
       && (!target
@@ -18575,26 +19388,46 @@ arm_expand_neon_args (rtx target, int icode, int have_retval,
         break;
       else
         {
+          opno = argc + have_retval;
+          mode[argc] = insn_data[icode].operand[opno].mode;
           arg[argc] = CALL_EXPR_ARG (exp, argc);
+          if (thisarg == NEON_ARG_MEMORY)
+            {
+              other_mode = insn_data[icode].operand[1 - opno].mode;
+              arg[argc] = neon_dereference_pointer (arg[argc], mode[argc],
+                                                    other_mode, type_bit);
+            }
           op[argc] = expand_normal (arg[argc]);
-          mode[argc] = insn_data[icode].operand[argc + have_retval].mode;
 
           switch (thisarg)
             {
             case NEON_ARG_COPY_TO_REG:
               /*gcc_assert (GET_MODE (op[argc]) == mode[argc]);*/
-              if (!(*insn_data[icode].operand[argc + have_retval].predicate)
+              if (!(*insn_data[icode].operand[opno].predicate)
                      (op[argc], mode[argc]))
                 op[argc] = copy_to_mode_reg (mode[argc], op[argc]);
               break;
 
             case NEON_ARG_CONSTANT:
               /* FIXME: This error message is somewhat unhelpful.  */
-              if (!(*insn_data[icode].operand[argc + have_retval].predicate)
+              if (!(*insn_data[icode].operand[opno].predicate)
                     (op[argc], mode[argc]))
                error ("argument must be a constant");
               break;
 
+            case NEON_ARG_MEMORY:
+             gcc_assert (MEM_P (op[argc]));
+             PUT_MODE (op[argc], mode[argc]);
+             /* ??? arm_neon.h uses the same built-in functions for signed
+                and unsigned accesses, casting where necessary.  This isn't
+                alias safe.  */
+             set_mem_alias_set (op[argc], 0);
+             if (!(*insn_data[icode].operand[opno].predicate)
+                    (op[argc], mode[argc]))
+               op[argc] = (replace_equiv_address
+                           (op[argc], force_reg (Pmode, XEXP (op[argc], 0))));
+              break;
+
             case NEON_ARG_STOP:
               gcc_unreachable ();
             }
@@ -18673,14 +19506,15 @@ static rtx
 arm_expand_neon_builtin (int fcode, tree exp, rtx target)
 {
   neon_itype itype;
-  enum insn_code icode = locate_neon_builtin_icode (fcode, &itype);
+  enum neon_builtin_type_bits type_bit;
+  enum insn_code icode = locate_neon_builtin_icode (fcode, &itype, &type_bit);
 
   switch (itype)
     {
     case NEON_UNOP:
     case NEON_CONVERT:
     case NEON_DUPLANE:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_BINOP:
@@ -18690,90 +19524,90 @@ arm_expand_neon_builtin (int fcode, tree exp, rtx target)
     case NEON_SCALARMULH:
     case NEON_SHIFTINSERT:
     case NEON_LOGICBINOP:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
         NEON_ARG_STOP);
 
     case NEON_TERNOP:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG,
         NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_GETLANE:
     case NEON_FIXCONV:
     case NEON_SHIFTIMM:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT, NEON_ARG_CONSTANT,
         NEON_ARG_STOP);
 
     case NEON_CREATE:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
 
     case NEON_DUP:
     case NEON_SPLIT:
     case NEON_REINTERP:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
 
     case NEON_COMBINE:
     case NEON_VTBL:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
 
     case NEON_RESULTPAIR:
-      return arm_expand_neon_args (target, icode, 0, exp,
+      return arm_expand_neon_args (target, icode, 0, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG,
         NEON_ARG_STOP);
 
     case NEON_LANEMUL:
     case NEON_LANEMULL:
     case NEON_LANEMULH:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
         NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_LANEMAC:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG,
         NEON_ARG_CONSTANT, NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_SHIFTACC:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
         NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
         NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_SCALARMAC:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
        NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG,
         NEON_ARG_CONSTANT, NEON_ARG_STOP);
 
     case NEON_SELECT:
     case NEON_VTBX:
-      return arm_expand_neon_args (target, icode, 1, exp,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
        NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG,
         NEON_ARG_STOP);
 
     case NEON_LOAD1:
     case NEON_LOADSTRUCT:
-      return arm_expand_neon_args (target, icode, 1, exp,
-       NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
+       NEON_ARG_MEMORY, NEON_ARG_STOP);
 
     case NEON_LOAD1LANE:
     case NEON_LOADSTRUCTLANE:
-      return arm_expand_neon_args (target, icode, 1, exp,
-       NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
+      return arm_expand_neon_args (target, icode, 1, type_bit, exp,
+       NEON_ARG_MEMORY, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
        NEON_ARG_STOP);
 
     case NEON_STORE1:
     case NEON_STORESTRUCT:
-      return arm_expand_neon_args (target, icode, 0, exp,
-       NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
+      return arm_expand_neon_args (target, icode, 0, type_bit, exp,
+       NEON_ARG_MEMORY, NEON_ARG_COPY_TO_REG, NEON_ARG_STOP);
 
     case NEON_STORE1LANE:
     case NEON_STORESTRUCTLANE:
-      return arm_expand_neon_args (target, icode, 0, exp,
-       NEON_ARG_COPY_TO_REG, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
+      return arm_expand_neon_args (target, icode, 0, type_bit, exp,
+       NEON_ARG_MEMORY, NEON_ARG_COPY_TO_REG, NEON_ARG_CONSTANT,
        NEON_ARG_STOP);
     }
 
@@ -19114,7 +19948,7 @@ thumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
       return;
     }
 
-  if (ARM_EABI_UNWIND_TABLES && push)
+  if (push && arm_except_unwind_info (&global_options) == UI_TARGET)
     {
       fprintf (f, "\t.save\t{");
       for (regno = 0; regno < 15; regno++)
@@ -19474,14 +20308,45 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   /* Return to caller.  */
   asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
 }
-
 \f
+/* Scan INSN just before assembler is output for it.
+   For Thumb-1, we track the status of the condition codes; this
+   information is used in the cbranchsi4_insn pattern.  */
 void
 thumb1_final_prescan_insn (rtx insn)
 {
   if (flag_print_asm_name)
     asm_fprintf (asm_out_file, "%@ 0x%04x\n",
                 INSN_ADDRESSES (INSN_UID (insn)));
+  /* Don't overwrite the previous setter when we get to a cbranch.  */
+  if (INSN_CODE (insn) != CODE_FOR_cbranchsi4_insn)
+    {
+      enum attr_conds conds;
+
+      if (cfun->machine->thumb1_cc_insn)
+       {
+         if (modified_in_p (cfun->machine->thumb1_cc_op0, insn)
+             || modified_in_p (cfun->machine->thumb1_cc_op1, insn))
+           CC_STATUS_INIT;
+       }
+      conds = get_attr_conds (insn);
+      if (conds == CONDS_SET)
+       {
+         rtx set = single_set (insn);
+         cfun->machine->thumb1_cc_insn = insn;
+         cfun->machine->thumb1_cc_op0 = SET_DEST (set);
+         cfun->machine->thumb1_cc_op1 = const0_rtx;
+         cfun->machine->thumb1_cc_mode = CC_NOOVmode;
+         if (INSN_CODE (insn) == CODE_FOR_thumb1_subsi3_insn)
+           {
+             rtx src1 = XEXP (SET_SRC (set), 1);
+             if (src1 == const0_rtx)
+               cfun->machine->thumb1_cc_mode = CCmode;
+           }
+       }
+      else if (conds != CONDS_NOCOND)
+       cfun->machine->thumb1_cc_insn = NULL_RTX;
+    }
 }
 
 int
@@ -19965,6 +20830,10 @@ thumb1_expand_prologue (void)
     emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
                    stack_pointer_rtx);
 
+  if (flag_stack_usage)
+    current_function_static_stack_size
+      = offsets->outgoing_args - offsets->saved_args;
+
   amount = offsets->outgoing_args - offsets->saved_regs;
   amount -= 4 * thumb1_extra_regs_pushed (offsets, true);
   if (amount)
@@ -20023,7 +20892,8 @@ thumb1_expand_prologue (void)
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
   if (crtl->profile || !TARGET_SCHED_PROLOG
-      || (ARM_EABI_UNWIND_TABLES && cfun->can_throw_non_call_exceptions))
+      || (arm_except_unwind_info (&global_options) == UI_TARGET
+         && cfun->can_throw_non_call_exceptions))
     emit_insn (gen_blockage ());
 
   cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
@@ -20136,7 +21006,7 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
   if (crtl->args.pretend_args_size)
     {
       /* Output unwind directive for the stack adjustment.  */
-      if (ARM_EABI_UNWIND_TABLES)
+      if (arm_except_unwind_info (&global_options) == UI_TARGET)
        fprintf (f, "\t.pad #%d\n",
                 crtl->args.pretend_args_size);
 
@@ -20206,7 +21076,7 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
       work_register = thumb_find_work_register (live_regs_mask);
 
-      if (ARM_EABI_UNWIND_TABLES)
+      if (arm_except_unwind_info (&global_options) == UI_TARGET)
        asm_fprintf (f, "\t.pad #16\n");
 
       asm_fprintf
@@ -21048,6 +21918,38 @@ arm_no_early_store_addr_dep (rtx producer, rtx consumer)
   return !reg_overlap_mentioned_p (value, addr);
 }
 
+/* Return nonzero if the CONSUMER instruction (a store) does need
+   PRODUCER's value to calculate the address.  */
+
+int
+arm_early_store_addr_dep (rtx producer, rtx consumer)
+{
+  return !arm_no_early_store_addr_dep (producer, consumer);
+}
+
+/* Return nonzero if the CONSUMER instruction (a load) does need
+   PRODUCER's value to calculate the address.  */
+
+int
+arm_early_load_addr_dep (rtx producer, rtx consumer)
+{
+  rtx value = PATTERN (producer);
+  rtx addr = PATTERN (consumer);
+
+  if (GET_CODE (value) == COND_EXEC)
+    value = COND_EXEC_CODE (value);
+  if (GET_CODE (value) == PARALLEL)
+    value = XVECEXP (value, 0, 0);
+  value = XEXP (value, 0);
+  if (GET_CODE (addr) == COND_EXEC)
+    addr = COND_EXEC_CODE (addr);
+  if (GET_CODE (addr) == PARALLEL)
+    addr = XVECEXP (addr, 0, 0);
+  addr = XEXP (addr, 1);
+
+  return reg_overlap_mentioned_p (value, addr);
+}
+
 /* Return nonzero if the CONSUMER instruction (an ALU op) does not
    have an early register shift value or amount dependency on the
    result of PRODUCER.  */
@@ -21426,6 +22328,66 @@ arm_vector_mode_supported_p (enum machine_mode mode)
   return false;
 }
 
+/* Use the option -mvectorize-with-neon-quad to override the use of doubleword
+   registers when autovectorizing for Neon, at least until multiple vector
+   widths are supported properly by the middle-end.  */
+
+static enum machine_mode
+arm_preferred_simd_mode (enum machine_mode mode)
+{
+  if (TARGET_NEON)
+    switch (mode)
+      {
+      case SFmode:
+       return TARGET_NEON_VECTORIZE_QUAD ? V4SFmode : V2SFmode;
+      case SImode:
+       return TARGET_NEON_VECTORIZE_QUAD ? V4SImode : V2SImode;
+      case HImode:
+       return TARGET_NEON_VECTORIZE_QUAD ? V8HImode : V4HImode;
+      case QImode:
+       return TARGET_NEON_VECTORIZE_QUAD ? V16QImode : V8QImode;
+      case DImode:
+       if (TARGET_NEON_VECTORIZE_QUAD)
+         return V2DImode;
+       break;
+
+      default:;
+      }
+
+  if (TARGET_REALLY_IWMMXT)
+    switch (mode)
+      {
+      case SImode:
+       return V2SImode;
+      case HImode:
+       return V4HImode;
+      case QImode:
+       return V8QImode;
+
+      default:;
+      }
+
+  return word_mode;
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P.
+   We need to define this for LO_REGS on Thumb-1.  Otherwise we can end up
+   using r0-r4 for function arguments, r7 for the stack frame and don't have
+   enough left over to do doubleword arithmetic.  For Thumb-2 all the
+   potentially problematic instructions accept high registers so this is not
+   necessary.  Care needs to be taken to avoid adding new Thumb-2 patterns
+   that require many low registers.  */
+static bool
+arm_class_likely_spilled_p (reg_class_t rclass)
+{
+  if ((TARGET_THUMB1 && rclass == LO_REGS)
+      || rclass  == CC_REG)
+    return true;
+
+  return false;
+}
+
 /* Implements target hook small_register_classes_for_mode_p.  */
 bool
 arm_small_register_classes_for_mode_p (enum machine_mode mode ATTRIBUTE_UNUSED)
@@ -21510,7 +22472,7 @@ arm_dwarf_register_span (rtx rtl)
   return p;
 }
 
-#ifdef TARGET_UNWIND_INFO
+#if ARM_UNWIND_INFO
 /* Emit unwind directives for a store-multiple instruction or stack pointer
    push during alignment.
    These should only ever be generated by the function prologue code, so
@@ -21724,7 +22686,7 @@ arm_unwind_emit (FILE * asm_out_file, rtx insn)
 {
   rtx pat;
 
-  if (!ARM_EABI_UNWIND_TABLES)
+  if (arm_except_unwind_info (&global_options) != UI_TARGET)
     return;
 
   if (!(flag_unwind_tables || crtl->uses_eh_lsda)
@@ -21772,9 +22734,54 @@ arm_output_ttype (rtx x)
     fputs ("(TARGET2)", asm_out_file);
   fputc ('\n', asm_out_file);
 
-  return TRUE;
+  return TRUE;
+}
+
+/* Implement TARGET_ASM_EMIT_EXCEPT_PERSONALITY.  */
+
+static void
+arm_asm_emit_except_personality (rtx personality)
+{
+  fputs ("\t.personality\t", asm_out_file);
+  output_addr_const (asm_out_file, personality);
+  fputc ('\n', asm_out_file);
+}
+
+/* Implement TARGET_ASM_INITIALIZE_SECTIONS.  */
+
+static void
+arm_asm_init_sections (void)
+{
+  exception_section = get_unnamed_section (0, output_section_asm_op,
+                                          "\t.handlerdata");
+}
+#endif /* ARM_UNWIND_INFO */
+
+/* Implement TARGET_EXCEPT_UNWIND_INFO.  */
+
+static enum unwind_info_type
+arm_except_unwind_info (struct gcc_options *opts)
+{
+  /* Honor the --enable-sjlj-exceptions configure switch.  */
+#ifdef CONFIG_SJLJ_EXCEPTIONS
+  if (CONFIG_SJLJ_EXCEPTIONS)
+    return UI_SJLJ;
+#endif
+
+  /* If not using ARM EABI unwind tables... */
+  if (ARM_UNWIND_INFO)
+    {
+      /* For simplicity elsewhere in this file, indicate that all unwind
+        info is disabled if we're not emitting unwind tables.  */
+      if (!opts->x_flag_exceptions && !opts->x_flag_unwind_tables)
+       return UI_NONE;
+      else
+       return UI_TARGET;
+    }
+
+  /* ... we use sjlj exceptions for backwards compatibility.  */
+  return UI_SJLJ;
 }
-#endif /* TARGET_UNWIND_INFO */
 
 
 /* Handle UNSPEC DWARF call frame instructions.  These are needed for dynamic
@@ -21806,7 +22813,7 @@ arm_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
 void
 arm_output_fn_unwind (FILE * f, bool prologue)
 {
-  if (!ARM_EABI_UNWIND_TABLES)
+  if (arm_except_unwind_info (&global_options) != UI_TARGET)
     return;
 
   if (prologue)
@@ -21886,7 +22893,9 @@ arm_output_dwarf_dtprel (FILE *file, int size, rtx x)
   fputs ("(tlsldo)", file);
 }
 
-bool
+/* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA.  */
+
+static bool
 arm_output_addr_const_extra (FILE *fp, rtx x)
 {
   if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
@@ -22026,8 +23035,10 @@ arm_issue_rate (void)
     {
     case cortexr4:
     case cortexr4f:
+    case cortexa5:
     case cortexa8:
     case cortexa9:
+    case fa726te:
       return 2;
 
     default:
@@ -22143,17 +23154,6 @@ arm_order_regs_for_local_alloc (void)
             sizeof (thumb_core_reg_alloc_order));
 }
 
-/* Set default optimization options.  */
-void
-arm_optimization_options (int level, int size ATTRIBUTE_UNUSED)
-{
-  /* Enable section anchors by default at -O1 or higher.
-     Use 2 to distinguish from an explicit -fsection-anchors
-     given on the command line.  */
-  if (level > 0)
-    flag_section_anchors = 2;
-}
-
 /* Implement TARGET_FRAME_POINTER_REQUIRED.  */
 
 bool
@@ -22172,4 +23172,593 @@ arm_have_conditional_execution (void)
   return !TARGET_THUMB1;
 }
 
+/* Legitimize a memory reference for sync primitive implemented using
+   ldrex / strex.  We currently force the form of the reference to be
+   indirect without offset.  We do not yet support the indirect offset
+   addressing supported by some ARM targets for these
+   instructions.  */
+static rtx
+arm_legitimize_sync_memory (rtx memory)
+{
+  rtx addr = force_reg (Pmode, XEXP (memory, 0));
+  rtx legitimate_memory = gen_rtx_MEM (GET_MODE (memory), addr);
+
+  set_mem_alias_set (legitimate_memory, ALIAS_SET_MEMORY_BARRIER);
+  MEM_VOLATILE_P (legitimate_memory) = MEM_VOLATILE_P (memory);
+  return legitimate_memory;
+}
+
+/* An instruction emitter. */
+typedef void (* emit_f) (int label, const char *, rtx *);
+
+/* An instruction emitter that emits via the conventional
+   output_asm_insn.  */
+static void
+arm_emit (int label ATTRIBUTE_UNUSED, const char *pattern, rtx *operands)
+{
+  output_asm_insn (pattern, operands);
+}
+
+/* Count the number of emitted synchronization instructions.  */
+static unsigned arm_insn_count;
+
+/* An emitter that counts emitted instructions but does not actually
+   emit instruction into the instruction stream.  */
+static void
+arm_count (int label,
+          const char *pattern ATTRIBUTE_UNUSED,
+          rtx *operands ATTRIBUTE_UNUSED)
+{
+  if (! label)
+    ++ arm_insn_count;
+}
+
+/* Construct a pattern using conventional output formatting and feed
+   it to output_asm_insn.  Provides a mechanism to construct the
+   output pattern on the fly.  Note the hard limit on the pattern
+   buffer size.  */
+static void ATTRIBUTE_PRINTF_4
+arm_output_asm_insn (emit_f emit, int label, rtx *operands,
+                    const char *pattern, ...)
+{
+  va_list ap;
+  char buffer[256];
+
+  va_start (ap, pattern);
+  vsprintf (buffer, pattern, ap);
+  va_end (ap);
+  emit (label, buffer, operands);
+}
+
+/* Emit the memory barrier instruction, if any, provided by this
+   target to a specified emitter.  */
+static void
+arm_process_output_memory_barrier (emit_f emit, rtx *operands)
+{
+  if (TARGET_HAVE_DMB)
+    {
+      /* Note we issue a system level barrier. We should consider
+         issuing a inner shareabilty zone barrier here instead, ie.
+         "DMB ISH".  */
+      emit (0, "dmb\tsy", operands);
+      return;
+    }
+
+  if (TARGET_HAVE_DMB_MCR)
+    {
+      emit (0, "mcr\tp15, 0, r0, c7, c10, 5", operands);
+      return;
+    }
+
+  gcc_unreachable ();
+}
+
+/* Emit the memory barrier instruction, if any, provided by this
+   target.  */
+const char *
+arm_output_memory_barrier (rtx *operands)
+{
+  arm_process_output_memory_barrier (arm_emit, operands);
+  return "";
+}
+
+/* Helper to figure out the instruction suffix required on ldrex/strex
+   for operations on an object of the specified mode.  */
+static const char *
+arm_ldrex_suffix (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case QImode: return "b";
+    case HImode: return "h";
+    case SImode: return "";
+    case DImode: return "d";
+    default:
+      gcc_unreachable ();
+    }
+  return "";
+}
+
+/* Emit an ldrex{b,h,d, } instruction appropriate for the specified
+   mode.  */
+static void
+arm_output_ldrex (emit_f emit,
+                 enum machine_mode mode,
+                 rtx target,
+                 rtx memory)
+{
+  const char *suffix = arm_ldrex_suffix (mode);
+  rtx operands[2];
+
+  operands[0] = target;
+  operands[1] = memory;
+  arm_output_asm_insn (emit, 0, operands, "ldrex%s\t%%0, %%C1", suffix);
+}
+
+/* Emit a strex{b,h,d, } instruction appropriate for the specified
+   mode.  */
+static void
+arm_output_strex (emit_f emit,
+                 enum machine_mode mode,
+                 const char *cc,
+                 rtx result,
+                 rtx value,
+                 rtx memory)
+{
+  const char *suffix = arm_ldrex_suffix (mode);
+  rtx operands[3];
+
+  operands[0] = result;
+  operands[1] = value;
+  operands[2] = memory;
+  arm_output_asm_insn (emit, 0, operands, "strex%s%s\t%%0, %%1, %%C2", suffix,
+                      cc);
+}
+
+/* Helper to emit a two operand instruction.  */
+static void
+arm_output_op2 (emit_f emit, const char *mnemonic, rtx d, rtx s)
+{
+  rtx operands[2];
+
+  operands[0] = d;
+  operands[1] = s;
+  arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1", mnemonic);
+}
+
+/* Helper to emit a three operand instruction.  */
+static void
+arm_output_op3 (emit_f emit, const char *mnemonic, rtx d, rtx a, rtx b)
+{
+  rtx operands[3];
+
+  operands[0] = d;
+  operands[1] = a;
+  operands[2] = b;
+  arm_output_asm_insn (emit, 0, operands, "%s\t%%0, %%1, %%2", mnemonic);
+}
+
+/* Emit a load store exclusive synchronization loop.
+
+   do
+     old_value = [mem]
+     if old_value != required_value
+       break;
+     t1 = sync_op (old_value, new_value)
+     [mem] = t1, t2 = [0|1]
+   while ! t2
+
+   Note:
+     t1 == t2 is not permitted
+     t1 == old_value is permitted
+
+   required_value:
+
+   RTX register or const_int representing the required old_value for
+   the modify to continue, if NULL no comparsion is performed.  */
+static void
+arm_output_sync_loop (emit_f emit,
+                     enum machine_mode mode,
+                     rtx old_value,
+                     rtx memory,
+                     rtx required_value,
+                     rtx new_value,
+                     rtx t1,
+                     rtx t2,
+                     enum attr_sync_op sync_op,
+                     int early_barrier_required)
+{
+  rtx operands[1];
+
+  gcc_assert (t1 != t2);
+
+  if (early_barrier_required)
+    arm_process_output_memory_barrier (emit, NULL);
+
+  arm_output_asm_insn (emit, 1, operands, "%sLSYT%%=:", LOCAL_LABEL_PREFIX);
+
+  arm_output_ldrex (emit, mode, old_value, memory);
+
+  if (required_value)
+    {
+      rtx operands[2];
+
+      operands[0] = old_value;
+      operands[1] = required_value;
+      arm_output_asm_insn (emit, 0, operands, "cmp\t%%0, %%1");
+      arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYB%%=", LOCAL_LABEL_PREFIX);
+    }
+
+  switch (sync_op)
+    {
+    case SYNC_OP_ADD:
+      arm_output_op3 (emit, "add", t1, old_value, new_value);
+      break;
+
+    case SYNC_OP_SUB:
+      arm_output_op3 (emit, "sub", t1, old_value, new_value);
+      break;
+
+    case SYNC_OP_IOR:
+      arm_output_op3 (emit, "orr", t1, old_value, new_value);
+      break;
+
+    case SYNC_OP_XOR:
+      arm_output_op3 (emit, "eor", t1, old_value, new_value);
+      break;
+
+    case SYNC_OP_AND:
+      arm_output_op3 (emit,"and", t1, old_value, new_value);
+      break;
+
+    case SYNC_OP_NAND:
+      arm_output_op3 (emit, "and", t1, old_value, new_value);
+      arm_output_op2 (emit, "mvn", t1, t1);
+      break;
+
+    case SYNC_OP_NONE:
+      t1 = new_value;
+      break;
+    }
+
+  if (t2)
+    {
+       arm_output_strex (emit, mode, "", t2, t1, memory);
+       operands[0] = t2;
+       arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
+       arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=",
+                           LOCAL_LABEL_PREFIX);
+    }
+  else
+    {
+      /* Use old_value for the return value because for some operations
+        the old_value can easily be restored.  This saves one register.  */
+      arm_output_strex (emit, mode, "", old_value, t1, memory);
+      operands[0] = old_value;
+      arm_output_asm_insn (emit, 0, operands, "teq\t%%0, #0");
+      arm_output_asm_insn (emit, 0, operands, "bne\t%sLSYT%%=",
+                          LOCAL_LABEL_PREFIX);
+
+      switch (sync_op)
+       {
+       case SYNC_OP_ADD:
+         arm_output_op3 (emit, "sub", old_value, t1, new_value);
+         break;
+
+       case SYNC_OP_SUB:
+         arm_output_op3 (emit, "add", old_value, t1, new_value);
+         break;
+
+       case SYNC_OP_XOR:
+         arm_output_op3 (emit, "eor", old_value, t1, new_value);
+         break;
+
+       case SYNC_OP_NONE:
+         arm_output_op2 (emit, "mov", old_value, required_value);
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
+    }
+
+  arm_process_output_memory_barrier (emit, NULL);
+  arm_output_asm_insn (emit, 1, operands, "%sLSYB%%=:", LOCAL_LABEL_PREFIX);
+}
+
+static rtx
+arm_get_sync_operand (rtx *operands, int index, rtx default_value)
+{
+  if (index > 0)
+    default_value = operands[index - 1];
+
+  return default_value;
+}
+
+#define FETCH_SYNC_OPERAND(NAME, DEFAULT) \
+  arm_get_sync_operand (operands, (int) get_attr_sync_##NAME (insn), DEFAULT);
+
+/* Extract the operands for a synchroniztion instruction from the
+   instructions attributes and emit the instruction.  */
+static void
+arm_process_output_sync_insn (emit_f emit, rtx insn, rtx *operands)
+{
+  rtx result, memory, required_value, new_value, t1, t2;
+  int early_barrier;
+  enum machine_mode mode;
+  enum attr_sync_op sync_op;
+
+  result = FETCH_SYNC_OPERAND(result, 0);
+  memory = FETCH_SYNC_OPERAND(memory, 0);
+  required_value = FETCH_SYNC_OPERAND(required_value, 0);
+  new_value = FETCH_SYNC_OPERAND(new_value, 0);
+  t1 = FETCH_SYNC_OPERAND(t1, 0);
+  t2 = FETCH_SYNC_OPERAND(t2, 0);
+  early_barrier =
+    get_attr_sync_release_barrier (insn) == SYNC_RELEASE_BARRIER_YES;
+  sync_op = get_attr_sync_op (insn);
+  mode = GET_MODE (memory);
+
+  arm_output_sync_loop (emit, mode, result, memory, required_value,
+                       new_value, t1, t2, sync_op, early_barrier);
+}
+
+/* Emit a synchronization instruction loop.  */
+const char *
+arm_output_sync_insn (rtx insn, rtx *operands)
+{
+  arm_process_output_sync_insn (arm_emit, insn, operands);
+  return "";
+}
+
+/* Count the number of machine instruction that will be emitted for a
+   synchronization instruction.  Note that the emitter used does not
+   emit instructions, it just counts instructions being carefull not
+   to count labels.  */
+unsigned int
+arm_sync_loop_insns (rtx insn, rtx *operands)
+{
+  arm_insn_count = 0;
+  arm_process_output_sync_insn (arm_count, insn, operands);
+  return arm_insn_count;
+}
+
+/* Helper to call a target sync instruction generator, dealing with
+   the variation in operands required by the different generators.  */
+static rtx
+arm_call_generator (struct arm_sync_generator *generator, rtx old_value,
+                   rtx memory, rtx required_value, rtx new_value)
+{
+  switch (generator->op)
+    {
+    case arm_sync_generator_omn:
+      gcc_assert (! required_value);
+      return generator->u.omn (old_value, memory, new_value);
+
+    case arm_sync_generator_omrn:
+      gcc_assert (required_value);
+      return generator->u.omrn (old_value, memory, required_value, new_value);
+    }
+
+  return NULL;
+}
+
+/* Expand a synchronization loop. The synchronization loop is expanded
+   as an opaque block of instructions in order to ensure that we do
+   not subsequently get extraneous memory accesses inserted within the
+   critical region. The exclusive access property of ldrex/strex is
+   only guaranteed in there are no intervening memory accesses. */
+void
+arm_expand_sync (enum machine_mode mode,
+                struct arm_sync_generator *generator,
+                rtx target, rtx memory, rtx required_value, rtx new_value)
+{
+  if (target == NULL)
+    target = gen_reg_rtx (mode);
+
+  memory = arm_legitimize_sync_memory (memory);
+  if (mode != SImode)
+    {
+      rtx load_temp = gen_reg_rtx (SImode);
+
+      if (required_value)
+       required_value = convert_modes (SImode, mode, required_value, true);
+
+      new_value = convert_modes (SImode, mode, new_value, true);
+      emit_insn (arm_call_generator (generator, load_temp, memory,
+                                    required_value, new_value));
+      emit_move_insn (target, gen_lowpart (mode, load_temp));
+    }
+  else
+    {
+      emit_insn (arm_call_generator (generator, target, memory, required_value,
+                                    new_value));
+    }
+}
+
+static unsigned int
+arm_autovectorize_vector_sizes (void)
+{
+  return TARGET_NEON_VECTORIZE_QUAD ? 16 | 8 : 0;
+}
+
+static bool
+arm_vector_alignment_reachable (const_tree type, bool is_packed)
+{
+  /* Vectors which aren't in packed structures will not be less aligned than
+     the natural alignment of their element type, so this is safe.  */
+  if (TARGET_NEON && !BYTES_BIG_ENDIAN)
+    return !is_packed;
+
+  return default_builtin_vector_alignment_reachable (type, is_packed);
+}
+
+static bool
+arm_builtin_support_vector_misalignment (enum machine_mode mode,
+                                        const_tree type, int misalignment,
+                                        bool is_packed)
+{
+  if (TARGET_NEON && !BYTES_BIG_ENDIAN)
+    {
+      HOST_WIDE_INT align = TYPE_ALIGN_UNIT (type);
+
+      if (is_packed)
+        return align == 1;
+
+      /* If the misalignment is unknown, we should be able to handle the access
+        so long as it is not to a member of a packed data structure.  */
+      if (misalignment == -1)
+        return true;
+
+      /* Return true if the misalignment is a multiple of the natural alignment
+         of the vector's element type.  This is probably always going to be
+        true in practice, since we've already established that this isn't a
+        packed access.  */
+      return ((misalignment % align) == 0);
+    }
+  
+  return default_builtin_support_vector_misalignment (mode, type, misalignment,
+                                                     is_packed);
+}
+
+static void
+arm_conditional_register_usage (void)
+{
+  int regno;
+
+  if (TARGET_SOFT_FLOAT || TARGET_THUMB1 || !TARGET_FPA)
+    {
+      for (regno = FIRST_FPA_REGNUM;
+          regno <= LAST_FPA_REGNUM; ++regno)
+       fixed_regs[regno] = call_used_regs[regno] = 1;
+    }
+
+  if (TARGET_THUMB1 && optimize_size)
+    {
+      /* When optimizing for size on Thumb-1, it's better not
+        to use the HI regs, because of the overhead of
+        stacking them.  */
+      for (regno = FIRST_HI_REGNUM;
+          regno <= LAST_HI_REGNUM; ++regno)
+       fixed_regs[regno] = call_used_regs[regno] = 1;
+    }
+
+  /* The link register can be clobbered by any branch insn,
+     but we have no way to track that at present, so mark
+     it as unavailable.  */
+  if (TARGET_THUMB1)
+    fixed_regs[LR_REGNUM] = call_used_regs[LR_REGNUM] = 1;
+
+  if (TARGET_32BIT && TARGET_HARD_FLOAT)
+    {
+      if (TARGET_MAVERICK)
+       {
+         for (regno = FIRST_FPA_REGNUM;
+              regno <= LAST_FPA_REGNUM; ++ regno)
+           fixed_regs[regno] = call_used_regs[regno] = 1;
+         for (regno = FIRST_CIRRUS_FP_REGNUM;
+              regno <= LAST_CIRRUS_FP_REGNUM; ++ regno)
+           {
+             fixed_regs[regno] = 0;
+             call_used_regs[regno] = regno < FIRST_CIRRUS_FP_REGNUM + 4;
+           }
+       }
+      if (TARGET_VFP)
+       {
+         /* VFPv3 registers are disabled when earlier VFP
+            versions are selected due to the definition of
+            LAST_VFP_REGNUM.  */
+         for (regno = FIRST_VFP_REGNUM;
+              regno <= LAST_VFP_REGNUM; ++ regno)
+           {
+             fixed_regs[regno] = 0;
+             call_used_regs[regno] = regno < FIRST_VFP_REGNUM + 16
+               || regno >= FIRST_VFP_REGNUM + 32;
+           }
+       }
+    }
+
+  if (TARGET_REALLY_IWMMXT)
+    {
+      regno = FIRST_IWMMXT_GR_REGNUM;
+      /* The 2002/10/09 revision of the XScale ABI has wCG0
+         and wCG1 as call-preserved registers.  The 2002/11/21
+         revision changed this so that all wCG registers are
+         scratch registers.  */
+      for (regno = FIRST_IWMMXT_GR_REGNUM;
+          regno <= LAST_IWMMXT_GR_REGNUM; ++ regno)
+       fixed_regs[regno] = 0;
+      /* The XScale ABI has wR0 - wR9 as scratch registers,
+        the rest as call-preserved registers.  */
+      for (regno = FIRST_IWMMXT_REGNUM;
+          regno <= LAST_IWMMXT_REGNUM; ++ regno)
+       {
+         fixed_regs[regno] = 0;
+         call_used_regs[regno] = regno < FIRST_IWMMXT_REGNUM + 10;
+       }
+    }
+
+  if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+    {
+      fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+      call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
+    }
+  else if (TARGET_APCS_STACK)
+    {
+      fixed_regs[10]     = 1;
+      call_used_regs[10] = 1;
+    }
+  /* -mcaller-super-interworking reserves r11 for calls to
+     _interwork_r11_call_via_rN().  Making the register global
+     is an easy way of ensuring that it remains valid for all
+     calls.  */
+  if (TARGET_APCS_FRAME || TARGET_CALLER_INTERWORKING
+      || TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME)
+    {
+      fixed_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1;
+      call_used_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1;
+      if (TARGET_CALLER_INTERWORKING)
+       global_regs[ARM_HARD_FRAME_POINTER_REGNUM] = 1;
+    }
+  SUBTARGET_CONDITIONAL_REGISTER_USAGE
+}
+
+static reg_class_t
+arm_preferred_rename_class (reg_class_t rclass)
+{
+  /* Thumb-2 instructions using LO_REGS may be smaller than instructions
+     using GENERIC_REGS.  During register rename pass, we prefer LO_REGS,
+     and code size can be reduced.  */
+  if (TARGET_THUMB2 && rclass == GENERAL_REGS)
+    return LO_REGS;
+  else
+    return NO_REGS;
+}
+
+/* Compute the atrribute "length" of insn "*push_multi".
+   So this function MUST be kept in sync with that insn pattern.  */
+int
+arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
+{
+  int i, regno, hi_reg;
+  int num_saves = XVECLEN (parallel_op, 0);
+
+  /* ARM mode.  */
+  if (TARGET_ARM)
+    return 4;
+
+  /* Thumb2 mode.  */
+  regno = REGNO (first_op);
+  hi_reg = (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
+  for (i = 1; i < num_saves && !hi_reg; i++)
+    {
+      regno = REGNO (XEXP (XVECEXP (parallel_op, 0, i), 0));
+      hi_reg |= (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
+    }
+
+  if (!hi_reg)
+    return 2;
+  return 4;
+}
+
 #include "gt-arm.h"