OSDN Git Service

* arm.c (thumb_base_register_rtx_p): Don't allow virtual registers
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / arm.c
index 928b169..66346ba 100644 (file)
@@ -1,29 +1,31 @@
 /* Output routines for GCC for ARM.
-   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
+   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    Free Software Foundation, Inc.
    Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl)
    and Martin Simmons (@harleqn.co.uk).
    More major hacks by Richard Earnshaw (rearnsha@arm.com).
 
-This file is part of GNU CC.
+   This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 2, or (at your
+   option) any later version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
-You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
     
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "obstack.h"
@@ -53,79 +55,101 @@ Boston, MA 02111-1307, USA.  */
 typedef struct minipool_node    Mnode;
 typedef struct minipool_fixup   Mfix;
 
-/* In order to improve the layout of the prototypes below
-   some short type abbreviations are defined here.  */
-#define Hint     HOST_WIDE_INT
-#define Mmode    enum machine_mode
-#define Ulong    unsigned long
-#define Ccstar   const char *
-
 const struct attribute_spec arm_attribute_table[];
 
 /* Forward function declarations.  */
-static void      arm_add_gc_roots              PARAMS ((void));
-static int       arm_gen_constant              PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
-static Ulong     bit_count                     PARAMS ((signed int));
-static int       const_ok_for_op               PARAMS ((Hint, enum rtx_code));
-static int       eliminate_lr2ip               PARAMS ((rtx *));
-static rtx      emit_multi_reg_push            PARAMS ((int));
-static rtx      emit_sfm                       PARAMS ((int, int));
+static void arm_add_gc_roots (void);
+static int arm_gen_constant (enum rtx_code, enum machine_mode, HOST_WIDE_INT,
+                            rtx, rtx, int, int);
+static unsigned bit_count (unsigned long);
+static int arm_address_register_rtx_p (rtx, int);
+static int arm_legitimate_index_p (enum machine_mode, rtx, int);
+static int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
+inline static int thumb_index_register_rtx_p (rtx, int);
+static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
+static rtx emit_multi_reg_push (int);
+static rtx emit_sfm (int, int);
 #ifndef AOF_ASSEMBLER
-static bool     arm_assemble_integer           PARAMS ((rtx, unsigned int, int));
+static bool arm_assemble_integer (rtx, unsigned int, int);
 #endif
-static Ccstar    fp_const_from_val             PARAMS ((REAL_VALUE_TYPE *));
-static arm_cc    get_arm_condition_code                PARAMS ((rtx));
-static void      init_fpa_table                        PARAMS ((void));
-static Hint      int_log2                      PARAMS ((Hint));
-static rtx       is_jump_table                         PARAMS ((rtx));
-static Ccstar    output_multi_immediate                PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));
-static void      print_multi_reg               PARAMS ((FILE *, Ccstar, int, int));
-static Mmode     select_dominance_cc_mode      PARAMS ((rtx, rtx, Hint));
-static Ccstar    shift_op                      PARAMS ((rtx, Hint *));
-static struct machine_function * arm_init_machine_status PARAMS ((void));
-static int       number_of_first_bit_set        PARAMS ((int));
-static void      replace_symbols_in_block       PARAMS ((tree, rtx, rtx));
-static void      thumb_exit                     PARAMS ((FILE *, int, rtx));
-static void      thumb_pushpop                  PARAMS ((FILE *, int, int));
-static Ccstar    thumb_condition_code           PARAMS ((rtx, int));
-static rtx      is_jump_table                  PARAMS ((rtx));
-static Hint     get_jump_table_size            PARAMS ((rtx));
-static Mnode *   move_minipool_fix_forward_ref  PARAMS ((Mnode *, Mnode *, Hint));
-static Mnode *   add_minipool_forward_ref      PARAMS ((Mfix *));
-static Mnode *   move_minipool_fix_backward_ref PARAMS ((Mnode *, Mnode *, Hint));
-static Mnode *   add_minipool_backward_ref      PARAMS ((Mfix *));
-static void     assign_minipool_offsets        PARAMS ((Mfix *));
-static void     arm_print_value                PARAMS ((FILE *, rtx));
-static void     dump_minipool                  PARAMS ((rtx));
-static int      arm_barrier_cost               PARAMS ((rtx));
-static Mfix *    create_fix_barrier            PARAMS ((Mfix *, Hint));
-static void     push_minipool_barrier          PARAMS ((rtx, Hint));
-static void     push_minipool_fix              PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
-static void     note_invalid_constants         PARAMS ((rtx, Hint));
-static int       current_file_function_operand PARAMS ((rtx));
-static Ulong    arm_compute_save_reg0_reg12_mask  PARAMS ((void));
-static Ulong     arm_compute_save_reg_mask     PARAMS ((void));
-static Ulong     arm_isr_value                         PARAMS ((tree));
-static Ulong     arm_compute_func_type         PARAMS ((void));
-static tree      arm_handle_fndecl_attribute    PARAMS ((tree *, tree, tree, int, bool *));
-static tree      arm_handle_isr_attribute       PARAMS ((tree *, tree, tree, int, bool *));
-static void     arm_output_function_epilogue   PARAMS ((FILE *, Hint));
-static void     arm_output_function_prologue   PARAMS ((FILE *, Hint));
-static void     thumb_output_function_prologue PARAMS ((FILE *, Hint));
-static int      arm_comp_type_attributes       PARAMS ((tree, tree));
-static void     arm_set_default_type_attributes  PARAMS ((tree));
-static int      arm_adjust_cost                PARAMS ((rtx, rtx, rtx, int));
+static const char *fp_const_from_val (REAL_VALUE_TYPE *);
+static arm_cc get_arm_condition_code (rtx);
+static void init_fpa_table (void);
+static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
+static rtx is_jump_table (rtx);
+static const char *output_multi_immediate (rtx *, const char *, const char *,
+                                          int, HOST_WIDE_INT);
+static void print_multi_reg (FILE *, const char *, int, int);
+static const char *shift_op (rtx, HOST_WIDE_INT *);
+static struct machine_function *arm_init_machine_status (void);
+static int number_of_first_bit_set (int);
+static void replace_symbols_in_block (tree, rtx, rtx);
+static void thumb_exit (FILE *, int, rtx);
+static void thumb_pushpop (FILE *, int, int);
+static rtx is_jump_table (rtx);
+static HOST_WIDE_INT get_jump_table_size (rtx);
+static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
+static Mnode *add_minipool_forward_ref (Mfix *);
+static Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
+static Mnode *add_minipool_backward_ref (Mfix *);
+static void assign_minipool_offsets (Mfix *);
+static void arm_print_value (FILE *, rtx);
+static void dump_minipool (rtx);
+static int arm_barrier_cost (rtx);
+static Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT);
+static void push_minipool_barrier (rtx, HOST_WIDE_INT);
+static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
+                              rtx);
+static void arm_reorg (void);
+static bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
+static int current_file_function_operand (rtx);
+static unsigned long arm_compute_save_reg0_reg12_mask (void);
+static unsigned long arm_compute_save_reg_mask (void);
+static unsigned long arm_isr_value (tree);
+static unsigned long arm_compute_func_type (void);
+static tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
+static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
+static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
+static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
+static void thumb_output_function_prologue (FILE *, HOST_WIDE_INT);
+static int arm_comp_type_attributes (tree, tree);
+static void arm_set_default_type_attributes (tree);
+static int arm_adjust_cost (rtx, rtx, rtx, int);
+static int arm_use_dfa_pipeline_interface (void);
+static int count_insns_for_constant (HOST_WIDE_INT, int);
+static int arm_get_strip_length (int);
+static bool arm_function_ok_for_sibcall (tree, tree);
+static void arm_internal_label (FILE *, const char *, unsigned long);
+static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
+                                tree);
+static int arm_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
+static bool arm_rtx_costs (rtx, int, int, int *);
+static int arm_address_cost (rtx);
+static bool arm_memory_load_p (rtx);
+static bool arm_cirrus_insn_p (rtx);
+static void cirrus_reorg (rtx);
+static void arm_init_builtins (void);
+static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static void arm_init_iwmmxt_builtins (void);
+static rtx safe_vector_operand (rtx, enum machine_mode);
+static rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
+static rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
+static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+
 #ifdef OBJECT_FORMAT_ELF
-static void     arm_elf_asm_named_section      PARAMS ((const char *, unsigned int));
+static void arm_elf_asm_named_section (const char *, unsigned int);
 #endif
 #ifndef ARM_PE
-static void     arm_encode_section_info        PARAMS ((tree, int));
+static void arm_encode_section_info (tree, rtx, int);
+#endif
+#ifdef AOF_ASSEMBLER
+static void aof_globalize_label (FILE *, const char *);
+static void aof_dump_imports (FILE *);
+static void aof_dump_pic_table (FILE *);
+static void aof_file_start (void);
+static void aof_file_end (void);
 #endif
 
-#undef Hint
-#undef Mmode
-#undef Ulong
-#undef Ccstar
 \f
 /* Initialize the GCC target structure.  */
 #ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
@@ -143,6 +167,12 @@ static void         arm_encode_section_info        PARAMS ((tree, int));
 #define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
 #undef  TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
+#undef TARGET_ASM_GLOBALIZE_LABEL
+#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START aof_file_start
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END aof_file_end
 #else
 #undef  TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP NULL
@@ -162,15 +192,12 @@ static void        arm_encode_section_info        PARAMS ((tree, int));
 #undef  TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
 #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
 
-#undef  TARGET_INIT_BUILTINS
-#define TARGET_INIT_BUILTINS arm_init_builtins
-
-#undef  TARGET_EXPAND_BUILTIN
-#define TARGET_EXPAND_BUILTIN arm_expand_builtin
-
 #undef  TARGET_SCHED_ADJUST_COST
 #define TARGET_SCHED_ADJUST_COST arm_adjust_cost
 
+#undef  TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE arm_use_dfa_pipeline_interface
+
 #undef TARGET_ENCODE_SECTION_INFO
 #ifdef ARM_PE
 #define TARGET_ENCODE_SECTION_INFO  arm_pe_encode_section_info
@@ -178,18 +205,39 @@ static void        arm_encode_section_info        PARAMS ((tree, int));
 #define TARGET_ENCODE_SECTION_INFO  arm_encode_section_info
 #endif
 
-#undef TARGET_STRIP_NAME_ENCODING
+#undef  TARGET_STRIP_NAME_ENCODING
 #define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
 
+#undef  TARGET_ASM_INTERNAL_LABEL
+#define TARGET_ASM_INTERNAL_LABEL arm_internal_label
+
+#undef  TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
+
+#undef  TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
+#undef  TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
+
+#undef  TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS arm_rtx_costs
+#undef  TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST arm_address_cost
+
+#undef  TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
+
+#undef  TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS  arm_init_builtins
+#undef  TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN arm_expand_builtin
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Obstack for minipool constant handling.  */
 static struct obstack minipool_obstack;
 static char *         minipool_startobj;
 
-#define obstack_chunk_alloc   xmalloc
-#define obstack_chunk_free    free
-
 /* The maximum number of insns skipped which
    will be conditionalised if possible.  */
 static int max_insns_skipped = 5;
@@ -204,10 +252,10 @@ int making_const_table;
 rtx arm_compare_op0, arm_compare_op1;
 
 /* What type of floating point are we tuning for?  */
-enum floating_point_type arm_fpu;
+enum fputype arm_fpu_tune;
 
 /* What type of floating point instructions are available?  */
-enum floating_point_type arm_fpu_arch;
+enum fputype arm_fpu_arch;
 
 /* What program mode is the cpu running in? 26-bit mode or 32-bit mode.  */
 enum prog_mode_type arm_prgmode;
@@ -229,18 +277,23 @@ int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
 #define FL_THUMB      (1 << 6)        /* Thumb aware */
 #define FL_LDSCHED    (1 << 7)       /* Load scheduling necessary */
 #define FL_STRONG     (1 << 8)       /* StrongARM */
-#define FL_ARCH5E     (1 << 9)        /* DSP extenstions to v5 */
+#define FL_ARCH5E     (1 << 9)        /* DSP extensions to v5 */
 #define FL_XSCALE     (1 << 10)              /* XScale */
+#define FL_CIRRUS     (1 << 11)              /* Cirrus/DSP.  */
+#define FL_IWMMXT     (1 << 29)              /* XScale v2 or "Intel Wireless MMX technology".  */
+#define FL_ARCH6J     (1 << 12)       /* Architecture rel 6.  Adds
+                                        media instructions.  */
+#define FL_VFPV2      (1 << 13)       /* Vector Floating Point V2.  */
 
 /* The bits in this mask specify which
    instructions we are allowed to generate.  */
-static int insn_flags = 0;
+static unsigned long insn_flags = 0;
 
 /* The bits in this mask specify which instruction scheduling options should
    be used.  Note - there is an overlap with the FL_FAST_MULT.  For some
    hardware we want to be able to generate the multiply instructions, but to
    tune as if they were not present in the architecture.  */
-static int tune_flags = 0;
+static unsigned long tune_flags = 0;
 
 /* The following are used in the arm.md file as equivalents to bits
    in the above two flag variables.  */
@@ -263,12 +316,21 @@ int arm_ld_sched = 0;
 /* Nonzero if this chip is a StrongARM.  */
 int arm_is_strong = 0;
 
+/* Nonzero if this chip supports Intel Wireless MMX technology.  */
+int arm_arch_iwmmxt = 0;
+
 /* Nonzero if this chip is an XScale.  */
-int arm_is_xscale = 0;
+int arm_arch_xscale = 0;
+
+/* Nonzero if tuning for XScale  */
+int arm_tune_xscale = 0;
 
 /* Nonzero if this chip is an ARM6 or an ARM7.  */
 int arm_is_6_or_7 = 0;
 
+/* Nonzero if this chip is a Cirrus/DSP.  */
+int arm_is_cirrus = 0;
+
 /* Nonzero if generating Thumb instructions.  */
 int thumb_code = 0;
 
@@ -312,7 +374,7 @@ static const char * const arm_condition_codes[] =
 struct processors
 {
   const char *const name;
-  const unsigned int flags;
+  const unsigned long flags;
 };
 
 /* Not all of these give usefully different compilation alternatives,
@@ -341,16 +403,17 @@ static const struct processors all_cores[] =
   {"arm700",   FL_CO_PROC | FL_MODE26 | FL_MODE32 },
   {"arm700i",  FL_CO_PROC | FL_MODE26 | FL_MODE32 },
   {"arm710",                FL_MODE26 | FL_MODE32 },
-  {"arm710t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
   {"arm720",                FL_MODE26 | FL_MODE32 },
-  {"arm720t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
-  {"arm740t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
   {"arm710c",               FL_MODE26 | FL_MODE32 },
   {"arm7100",               FL_MODE26 | FL_MODE32 },
   {"arm7500",               FL_MODE26 | FL_MODE32 },
-  /* Doesn't have an external co-proc, but does have embedded fpu.  */
+  /* Doesn't have an external co-proc, but does have embedded fpa.  */
   {"arm7500fe",        FL_CO_PROC | FL_MODE26 | FL_MODE32 },
+  /* V4 Architecture Processors */
   {"arm7tdmi", FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
+  {"arm710t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
+  {"arm720t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
+  {"arm740t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
   {"arm8",                  FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
   {"arm810",                FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
   {"arm9",                              FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
@@ -359,14 +422,21 @@ static const struct processors all_cores[] =
   {"arm940t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm9tdmi",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm9e",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
+  {"ep9312",                            FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED |             FL_CIRRUS },
   {"strongarm",                     FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm1110",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
+  /* V5 Architecture Processors */
   {"arm10tdmi",                                 FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
   {"arm1020t",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
+  {"arm926ejs",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E },
+  {"arm1026ejs",                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E },
   {"xscale",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
-  
+  {"iwmmxt",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
+  /* V6 Architecture Processors */
+  {"arm1136js",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
+  {"arm1136jfs",                         FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB                          | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J | FL_VFPV2 },
   {NULL, 0}
 };
 
@@ -385,10 +455,13 @@ static const struct processors all_architectures[] =
   { "armv5",     FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
   { "armv5t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
   { "armv5te",   FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
+  { "armv6j",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E | FL_ARCH6J },
+  { "ep9312",                            FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_LDSCHED | FL_CIRRUS },
+  {"iwmmxt",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE | FL_IWMMXT },
   { NULL, 0 }
 };
 
-/* This is a magic stucture.  The 'string' field is magically filled in
+/* This is a magic structure.  The 'string' field is magically filled in
    with a pointer to the value specified by the user on the command line
    assuming that the user has specified such a value.  */
 
@@ -400,17 +473,16 @@ struct arm_cpu_select arm_select[] =
   { NULL,      "-mtune=",      all_cores }
 };
 
-/* Return the number of bits set in value' */
-static unsigned long
-bit_count (value)
-     signed int value;
+/* Return the number of bits set in VALUE.  */
+static unsigned
+bit_count (unsigned long value)
 {
   unsigned long count = 0;
   
   while (value)
     {
-      value &= ~(value & -value);
-      ++count;
+      count++;
+      value &= value - 1;  /* Clear the least-significant set bit.  */
     }
 
   return count;
@@ -419,7 +491,7 @@ bit_count (value)
 /* Fix up any incompatible options that the user has specified.
    This has now turned into a maze.  */
 void
-arm_override_options ()
+arm_override_options (void)
 {
   unsigned i;
   
@@ -482,6 +554,12 @@ arm_override_options ()
        { TARGET_CPU_arm9,      "arm9" },
        { TARGET_CPU_strongarm, "strongarm" },
        { TARGET_CPU_xscale,    "xscale" },
+       { TARGET_CPU_ep9312,    "ep9312" },
+       { TARGET_CPU_iwmmxt,    "iwmmxt" },
+       { TARGET_CPU_arm926ej_s, "arm926ej-s" },
+       { TARGET_CPU_arm1026ej_s, "arm1026ej-s" },
+       { TARGET_CPU_arm1136j_s, "arm1136j_s" },
+       { TARGET_CPU_arm1136jf_s, "arm1136jf_s" },
        { TARGET_CPU_generic,   "arm" },
        { 0, 0 }
       };
@@ -537,7 +615,7 @@ arm_override_options ()
 
          if (sel->name == NULL)
            {
-             unsigned int        current_bit_count = 0;
+             unsigned current_bit_count = 0;
              const struct processors * best_fit = NULL;
              
              /* Ideally we would like to issue an error message here
@@ -556,7 +634,7 @@ arm_override_options ()
              for (sel = all_cores; sel->name != NULL; sel++)
                if ((sel->flags & sought) == sought)
                  {
-                   unsigned int count;
+                   unsigned count;
 
                    count = bit_count (sel->flags & insn_flags);
 
@@ -581,7 +659,7 @@ arm_override_options ()
      architecture has been selected.  */
   if (tune_flags == 0)
     tune_flags = insn_flags;
-  
+
   /* Make sure that the processor choice does not conflict with any of the
      other command line choices.  */
   if (TARGET_APCS_32 && !(insn_flags & FL_MODE32))
@@ -668,45 +746,67 @@ arm_override_options ()
   if (TARGET_APCS_FLOAT)
     warning ("passing floating point arguments in fp regs not yet supported");
   
-  /* Initialise boolean versions of the flags, for use in the arm.md file.  */
+  /* Initialize boolean versions of the flags, for use in the arm.md file.  */
   arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
   arm_arch4         = (insn_flags & FL_ARCH4) != 0;
   arm_arch5         = (insn_flags & FL_ARCH5) != 0;
   arm_arch5e        = (insn_flags & FL_ARCH5E) != 0;
-  arm_is_xscale     = (insn_flags & FL_XSCALE) != 0;
+  arm_arch_xscale     = (insn_flags & FL_XSCALE) != 0;
 
   arm_ld_sched      = (tune_flags & FL_LDSCHED) != 0;
   arm_is_strong     = (tune_flags & FL_STRONG) != 0;
   thumb_code       = (TARGET_ARM == 0);
   arm_is_6_or_7     = (((tune_flags & (FL_MODE26 | FL_MODE32))
                       && !(tune_flags & FL_ARCH4))) != 0;
+  arm_tune_xscale       = (tune_flags & FL_XSCALE) != 0;
+  arm_is_cirrus            = (tune_flags & FL_CIRRUS) != 0;
+  arm_arch_iwmmxt   = (insn_flags & FL_IWMMXT) != 0;
 
-  /* Default value for floating point code... if no co-processor
-     bus, then schedule for emulated floating point.  Otherwise,
-     assume the user has an FPA.
-     Note: this does not prevent use of floating point instructions,
-     -msoft-float does that.  */
-  arm_fpu = (tune_flags & FL_CO_PROC) ? FP_HARD : FP_SOFT3;
+  if (TARGET_IWMMXT && (! TARGET_ATPCS))
+    target_flags |= ARM_FLAG_ATPCS;    
+
+  if (arm_is_cirrus)
+    {
+      arm_fpu_tune = FPUTYPE_MAVERICK;
+
+      /* Ignore -mhard-float if -mcpu=ep9312.  */
+      if (TARGET_HARD_FLOAT)
+       target_flags ^= ARM_FLAG_SOFT_FLOAT;
+    }
+  else
+    /* Default value for floating point code... if no co-processor
+       bus, then schedule for emulated floating point.  Otherwise,
+       assume the user has an FPA.
+       Note: this does not prevent use of floating point instructions,
+       -msoft-float does that.  */
+    arm_fpu_tune = (tune_flags & FL_CO_PROC) ? FPUTYPE_FPA : FPUTYPE_FPA_EMU3;
   
   if (target_fp_name)
     {
       if (streq (target_fp_name, "2"))
-       arm_fpu_arch = FP_SOFT2;
+       arm_fpu_arch = FPUTYPE_FPA_EMU2;
       else if (streq (target_fp_name, "3"))
-       arm_fpu_arch = FP_SOFT3;
+       arm_fpu_arch = FPUTYPE_FPA_EMU3;
       else
        error ("invalid floating point emulation option: -mfpe-%s",
               target_fp_name);
     }
   else
-    arm_fpu_arch = FP_DEFAULT;
+    arm_fpu_arch = FPUTYPE_DEFAULT;
   
-  if (TARGET_FPE && arm_fpu != FP_HARD)
-    arm_fpu = FP_SOFT2;
+  if (TARGET_FPE)
+    {
+      if (arm_fpu_tune == FPUTYPE_FPA_EMU3)
+       arm_fpu_tune = FPUTYPE_FPA_EMU2;
+      else if (arm_fpu_tune == FPUTYPE_MAVERICK)
+       warning ("-mfpe switch not supported by ep9312 target cpu - ignored.");
+      else if (arm_fpu_tune != FPUTYPE_FPA)
+       arm_fpu_tune = FPUTYPE_FPA_EMU2;
+    }
   
   /* For arm2/3 there is no need to do any scheduling if there is only
      a floating point emulator, or we are doing software floating-point.  */
-  if ((TARGET_SOFT_FLOAT || arm_fpu != FP_HARD)
+  if ((TARGET_SOFT_FLOAT || arm_fpu_tune != FPUTYPE_FPA)
       && (tune_flags & FL_MODE32) == 0)
     flag_schedule_insns = flag_schedule_insns_after_reload = 0;
   
@@ -725,7 +825,7 @@ arm_override_options ()
   if (arm_pic_register_string != NULL)
     {
       int pic_register = decode_reg_name (arm_pic_register_string);
-      
+
       if (!flag_pic)
        warning ("-mpic-register= is useless without -fpic");
 
@@ -745,30 +845,44 @@ arm_override_options ()
       flag_schedule_insns = 0;
     }
 
-  /* If optimizing for space, don't synthesize constants.
-     For processors with load scheduling, it never costs more than 2 cycles
-     to load a constant, and the load scheduler may well reduce that to 1.  */
-  if (optimize_size || (tune_flags & FL_LDSCHED))
-    arm_constant_limit = 1;
-  
-  if (arm_is_xscale)
-    arm_constant_limit = 2;
-
-  /* If optimizing for size, bump the number of instructions that we
-     are prepared to conditionally execute (even on a StrongARM). 
-     Otherwise for the StrongARM, which has early execution of branches,
-     a sequence that is worth skipping is shorter.  */
   if (optimize_size)
-    max_insns_skipped = 6;
-  else if (arm_is_strong)
-    max_insns_skipped = 3;
+    {
+      /* There's some dispute as to whether this should be 1 or 2.  However,
+        experiments seem to show that in pathological cases a setting of
+        1 degrades less severely than a setting of 2.  This could change if
+        other parts of the compiler change their behavior.  */
+      arm_constant_limit = 1;
+
+      /* If optimizing for size, bump the number of instructions that we
+         are prepared to conditionally execute (even on a StrongARM). */
+      max_insns_skipped = 6;
+    }
+  else
+    {
+      /* For processors with load scheduling, it never costs more than
+         2 cycles to load a constant, and the load scheduler may well
+        reduce that to 1.  */
+      if (tune_flags & FL_LDSCHED)
+        arm_constant_limit = 1;
+
+      /* On XScale the longer latency of a load makes it more difficult
+         to achieve a good schedule, so it's faster to synthesize
+        constants that can be done in two insns. */
+      if (arm_tune_xscale)
+        arm_constant_limit = 2;
+
+      /* StrongARM has early execution of branches, so a sequence
+         that is worth skipping is shorter.  */
+      if (arm_is_strong)
+        max_insns_skipped = 3;
+    }
 
   /* Register global variables with the garbage collector.  */
   arm_add_gc_roots ();
 }
 
 static void
-arm_add_gc_roots ()
+arm_add_gc_roots (void)
 {
   gcc_obstack_init(&minipool_obstack);
   minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
@@ -805,8 +919,7 @@ static const isr_attribute_arg isr_attribute_args [] =
    function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
 
 static unsigned long
-arm_isr_value (argument)
-     tree argument;
+arm_isr_value (tree argument)
 {
   const isr_attribute_arg * ptr;
   const char *              arg;
@@ -823,18 +936,18 @@ arm_isr_value (argument)
   arg = TREE_STRING_POINTER (TREE_VALUE (argument));
 
   /* Check it against the list of known arguments.  */
-  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr ++)
+  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
     if (streq (arg, ptr->arg))
       return ptr->return_value;
 
-  /* An unrecognised interrupt type.  */
+  /* An unrecognized interrupt type.  */
   return ARM_FT_UNKNOWN;
 }
 
 /* Computes the type of the current function.  */
 
 static unsigned long
-arm_compute_func_type ()
+arm_compute_func_type (void)
 {
   unsigned long type = ARM_FT_UNKNOWN;
   tree a;
@@ -881,7 +994,7 @@ arm_compute_func_type ()
 /* Returns the type of the current function.  */
 
 unsigned long
-arm_current_func_type ()
+arm_current_func_type (void)
 {
   if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
     cfun->machine->func_type = arm_compute_func_type ();
@@ -889,68 +1002,129 @@ arm_current_func_type ()
   return cfun->machine->func_type;
 }
 \f
-/* Return 1 if it is possible to return using a single instruction.  */
+/* Return 1 if it is possible to return using a single instruction.  
+   If SIBLING is non-null, this is a test for a return before a sibling
+   call.  SIBLING is the call insn, so we can examine its register usage.  */
 
 int
-use_return_insn (iscond)
-     int iscond;
+use_return_insn (int iscond, rtx sibling)
 {
   int regno;
   unsigned int func_type;
+  unsigned long saved_int_regs;
+  unsigned HOST_WIDE_INT stack_adjust;
 
   /* Never use a return instruction before reload has run.  */
   if (!reload_completed)
     return 0;
-      
+
   func_type = arm_current_func_type ();
 
   /* Naked functions and volatile functions need special
      consideration.  */
   if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
     return 0;
-  
+
+  /* So do interrupt functions that use the frame pointer.  */
+  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
+    return 0;
+
+  stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
+
   /* As do variadic functions.  */
   if (current_function_pretend_args_size
       || cfun->machine->uses_anonymous_args
-      /* Of if the function calls __builtin_eh_return () */
+      /* Or if the function calls __builtin_eh_return () */
       || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
-      /* Or if there is no frame pointer and there is a stack adjustment.  */
-      || ((get_frame_size () + current_function_outgoing_args_size != 0)
-         && !frame_pointer_needed))
+      /* Or if the function calls alloca */
+      || current_function_calls_alloca
+      /* Or if there is a stack adjustment.  However, if the stack pointer
+        is saved on the stack, we can use a pre-incrementing stack load.  */
+      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
     return 0;
 
+  saved_int_regs = arm_compute_save_reg_mask ();
+
+  /* Unfortunately, the insn
+
+       ldmib sp, {..., sp, ...}
+
+     triggers a bug on most SA-110 based devices, such that the stack
+     pointer won't be correctly restored if the instruction takes a
+     page fault.  We work around this problem by popping r3 along with
+     the other registers, since that is never slower than executing
+     another instruction.  
+
+     We test for !arm_arch5 here, because code for any architecture
+     less than this could potentially be run on one of the buggy
+     chips.  */
+  if (stack_adjust == 4 && !arm_arch5)
+    {
+      /* Validate that r3 is a call-clobbered register (always true in
+        the default abi) ... */
+      if (!call_used_regs[3])
+       return 0;
+
+      /* ... that it isn't being used for a return value (always true
+        until we implement return-in-regs), or for a tail-call
+        argument ... */
+      if (sibling)
+       {
+         if (GET_CODE (sibling) != CALL_INSN)
+           abort ();
+
+         if (find_regno_fusage (sibling, USE, 3))
+           return 0;
+       }
+
+      /* ... and that there are no call-saved registers in r0-r2
+        (always true in the default ABI).  */
+      if (saved_int_regs & 0x7)
+       return 0;
+    }
+
   /* Can't be done if interworking with Thumb, and any registers have been
-     stacked.  Similarly, on StrongARM, conditional returns are expensive
-     if they aren't taken and registers have been stacked.  */
-  if (iscond && arm_is_strong && frame_pointer_needed)
+     stacked.  */
+  if (TARGET_INTERWORK && saved_int_regs != 0)
     return 0;
-  
-  if ((iscond && arm_is_strong)
-      || TARGET_INTERWORK)
+
+  /* On StrongARM, conditional returns are expensive if they aren't
+     taken and multiple registers have been stacked.  */
+  if (iscond && arm_is_strong)
     {
-      for (regno = 0; regno <= LAST_ARM_REGNUM; regno++)
-       if (regs_ever_live[regno] && !call_used_regs[regno])
-         return 0;
+      /* Conditional return when just the LR is stored is a simple 
+        conditional-load instruction, that's not expensive.  */
+      if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
+       return 0;
 
       if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
        return 0;
     }
-      
-  /* Can't be done if any of the FPU regs are pushed,
+
+  /* If there are saved registers but the LR isn't saved, then we need
+     two instructions for the return.  */
+  if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
+    return 0;
+
+  /* Can't be done if any of the FPA regs are pushed,
      since this also requires an insn.  */
   if (TARGET_HARD_FLOAT)
     for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
       if (regs_ever_live[regno] && !call_used_regs[regno])
        return 0;
 
+  if (TARGET_REALLY_IWMMXT)
+    for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
+      if (regs_ever_live[regno] && ! call_used_regs [regno])
+       return 0;
+
   return 1;
 }
 
 /* Return TRUE if int I is a valid immediate ARM constant.  */
 
 int
-const_ok_for_arm (i)
-     HOST_WIDE_INT i;
+const_ok_for_arm (HOST_WIDE_INT i)
 {
   unsigned HOST_WIDE_INT mask = ~(unsigned HOST_WIDE_INT)0xFF;
 
@@ -981,9 +1155,7 @@ const_ok_for_arm (i)
 
 /* Return true if I is a valid constant for the operation CODE.  */
 static int
-const_ok_for_op (i, code)
-     HOST_WIDE_INT i;
-     enum rtx_code code;
+const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
 {
   if (const_ok_for_arm (i))
     return 1;
@@ -1017,20 +1189,15 @@ const_ok_for_op (i, code)
    Return value is the number of insns emitted.  */
 
 int
-arm_split_constant (code, mode, val, target, source, subtargets)
-     enum rtx_code code;
-     enum machine_mode mode;
-     HOST_WIDE_INT val;
-     rtx target;
-     rtx source;
-     int subtargets;
+arm_split_constant (enum rtx_code code, enum machine_mode mode,
+                   HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
 {
   if (subtargets || code == SET
       || (GET_CODE (target) == REG && GET_CODE (source) == REG
          && REGNO (target) != REGNO (source)))
     {
       /* After arm_reorg has been called, we can't fix up expensive
-        constants by pushing them into memory so we must synthesise
+        constants by pushing them into memory so we must synthesize
         them in-line, regardless of the cost.  This is only likely to
         be more costly on chips that have load delay slots and we are
         compiling without running the scheduler (so no splitting
@@ -1101,14 +1268,9 @@ count_insns_for_constant (HOST_WIDE_INT remainder, int i)
    RTL generation.  */
 
 static int
-arm_gen_constant (code, mode, val, target, source, subtargets, generate)
-     enum rtx_code code;
-     enum machine_mode mode;
-     HOST_WIDE_INT val;
-     rtx target;
-     rtx source;
-     int subtargets;
-     int generate;
+arm_gen_constant (enum rtx_code code, enum machine_mode mode,
+                 HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
+                 int generate)
 {
   int can_invert = 0;
   int can_negate = 0;
@@ -1683,9 +1845,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
    immediate value easier to load.  */
 
 enum rtx_code
-arm_canonicalize_comparison (code, op1)
-     enum rtx_code code;
-     rtx * op1;
+arm_canonicalize_comparison (enum rtx_code code, rtx * op1)
 {
   unsigned HOST_WIDE_INT i = INTVAL (*op1);
 
@@ -1745,23 +1905,32 @@ arm_canonicalize_comparison (code, op1)
 /* Decide whether a type should be returned in memory (true)
    or in a register (false).  This is called by the macro
    RETURN_IN_MEMORY.  */
-
 int
-arm_return_in_memory (type)
-     tree type;
+arm_return_in_memory (tree type)
 {
+  HOST_WIDE_INT size;
+
   if (!AGGREGATE_TYPE_P (type))
     /* All simple types are returned in registers.  */
     return 0;
+
+  size = int_size_in_bytes (type);
+
+  if (TARGET_ATPCS)
+    {
+      /* ATPCS returns aggregate types in memory only if they are
+        larger than a word (or are variable size).  */
+      return (size < 0 || size > UNITS_PER_WORD);
+    }
   
-  /* For the arm-wince targets we choose to be compitable with Microsoft's
+  /* For the arm-wince targets we choose to be compatible with Microsoft's
      ARM and Thumb compilers, which always return aggregates in memory.  */
 #ifndef ARM_WINCE
   /* All structures/unions bigger than one word are returned in memory.
      Also catch the case where int_size_in_bytes returns -1.  In this case
-     the aggregate is either huge or of varaible size, and in either case
+     the aggregate is either huge or of variable size, and in either case
      we will want to return it via memory and not in a register.  */
-  if (((unsigned int) int_size_in_bytes (type)) > UNITS_PER_WORD)
+  if (size < 0 || size > UNITS_PER_WORD)
     return 1;
   
   if (TREE_CODE (type) == RECORD_TYPE)
@@ -1839,18 +2008,40 @@ arm_return_in_memory (type)
   return 1;
 }
 
+/* Indicate whether or not words of a double are in big-endian order. */
+
+int
+arm_float_words_big_endian (void)
+{
+  if (TARGET_CIRRUS)
+    return 0;
+
+  /* For FPA, float words are always big-endian.  For VFP, floats words
+     follow the memory system mode.  */
+
+  if (TARGET_HARD_FLOAT)
+    {
+      /* FIXME: TARGET_HARD_FLOAT currently implies FPA.  */
+      return 1;
+    }
+
+  if (TARGET_VFP)
+    return (TARGET_BIG_END ? 1 : 0);
+
+  return 1;
+}
+
 /* Initialize a variable CUM of type CUMULATIVE_ARGS
    for a call to a function whose data type is FNTYPE.
    For a library call, FNTYPE is NULL.  */
 void
-arm_init_cumulative_args (pcum, fntype, libname, indirect)
-     CUMULATIVE_ARGS * pcum;
-     tree fntype;
-     rtx libname  ATTRIBUTE_UNUSED;
-     int indirect ATTRIBUTE_UNUSED;
+arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, 
+                         rtx libname  ATTRIBUTE_UNUSED,
+                         tree fndecl ATTRIBUTE_UNUSED)
 {
   /* On the ARM, the offset starts at 0.  */
-  pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype))) ? 1 : 0);
+  pcum->nregs = ((fntype && aggregate_value_p (TREE_TYPE (fntype), fntype)) ? 1 : 0);
+  pcum->iwmmxt_nregs = 0;
   
   pcum->call_cookie = CALL_NORMAL;
 
@@ -1866,6 +2057,24 @@ arm_init_cumulative_args (pcum, fntype, libname, indirect)
       else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
        pcum->call_cookie = CALL_LONG;
     }
+
+  /* Varargs vectors are treated the same as long long.
+     named_count avoids having to change the way arm handles 'named' */
+  pcum->named_count = 0;
+  pcum->nargs = 0;
+
+  if (TARGET_REALLY_IWMMXT && fntype)
+    {
+      tree fn_arg;
+
+      for (fn_arg = TYPE_ARG_TYPES (fntype);
+          fn_arg;
+          fn_arg = TREE_CHAIN (fn_arg))
+       pcum->named_count += 1;
+
+      if (! pcum->named_count)
+       pcum->named_count = INT_MAX;
+    }
 }
 
 /* Determine where to put an argument to a function.
@@ -1882,12 +2091,33 @@ arm_init_cumulative_args (pcum, fntype, libname, indirect)
     (otherwise it is an extra parameter matching an ellipsis).  */
 
 rtx
-arm_function_arg (pcum, mode, type, named)
-     CUMULATIVE_ARGS * pcum;
-     enum machine_mode mode;
-     tree type ATTRIBUTE_UNUSED;
-     int named;
+arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
+                 tree type ATTRIBUTE_UNUSED, int named)
 {
+  if (TARGET_REALLY_IWMMXT)
+    {
+      if (VECTOR_MODE_SUPPORTED_P (mode))
+       {
+         /* varargs vectors are treated the same as long long.
+            named_count avoids having to change the way arm handles 'named' */
+         if (pcum->named_count <= pcum->nargs + 1)
+           {
+             if (pcum->nregs == 1)
+               pcum->nregs += 1;
+             if (pcum->nregs <= 2)
+               return gen_rtx_REG (mode, pcum->nregs);
+             else
+               return NULL_RTX;
+           }
+         else if (pcum->iwmmxt_nregs <= 9)
+           return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
+         else
+           return NULL_RTX;
+       }
+      else if ((mode == DImode || mode == DFmode) && pcum->nregs & 1)
+       pcum->nregs += 1;
+    }
+
   if (mode == VOIDmode)
     /* Compute operand 2 of the call insn.  */
     return GEN_INT (pcum->call_cookie);
@@ -1897,6 +2127,52 @@ arm_function_arg (pcum, mode, type, named)
   
   return gen_rtx_REG (mode, pcum->nregs);
 }
+
+/* Variable sized types are passed by reference.  This is a GCC
+   extension to the ARM ABI.  */
+
+int
+arm_function_arg_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                                   enum machine_mode mode ATTRIBUTE_UNUSED,
+                                   tree type, int named ATTRIBUTE_UNUSED)
+{
+  return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
+}
+
+/* Implement va_arg.  */
+
+rtx
+arm_va_arg (tree valist, tree type)
+{
+  /* Variable sized types are passed by reference.  */
+  if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+    {
+      rtx addr = std_expand_builtin_va_arg (valist, build_pointer_type (type));
+      return gen_rtx_MEM (ptr_mode, force_reg (Pmode, addr));
+    }
+
+  if (FUNCTION_ARG_BOUNDARY (TYPE_MODE (type), NULL) == IWMMXT_ALIGNMENT)
+    {
+      tree minus_eight;
+      tree t;
+
+      /* Maintain 64-bit alignment of the valist pointer by
+        constructing:   valist = ((valist + (8 - 1)) & -8).  */
+      minus_eight = build_int_2 (- (IWMMXT_ALIGNMENT / BITS_PER_UNIT), -1);
+      t = build_int_2 ((IWMMXT_ALIGNMENT / BITS_PER_UNIT) - 1, 0);
+      t = build (PLUS_EXPR,    TREE_TYPE (valist), valist, t);
+      t = build (BIT_AND_EXPR, TREE_TYPE (t), t, minus_eight);
+      t = build (MODIFY_EXPR,  TREE_TYPE (valist), valist, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      /* This is to stop the combine pass optimizing
+        away the alignment adjustment.  */
+      mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
+    }
+
+  return std_expand_builtin_va_arg (valist, type);
+}
 \f
 /* Encode the current state of the #pragma [no_]long_calls.  */
 typedef enum
@@ -1909,22 +2185,19 @@ typedef enum
 static arm_pragma_enum arm_pragma_long_calls = OFF;
 
 void
-arm_pr_long_calls (pfile)
-     cpp_reader * pfile ATTRIBUTE_UNUSED;
+arm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
 {
   arm_pragma_long_calls = LONG;
 }
 
 void
-arm_pr_no_long_calls (pfile)
-     cpp_reader * pfile ATTRIBUTE_UNUSED;
+arm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
 {
   arm_pragma_long_calls = SHORT;
 }
 
 void
-arm_pr_long_calls_off (pfile)
-     cpp_reader * pfile ATTRIBUTE_UNUSED;
+arm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
 {
   arm_pragma_long_calls = OFF;
 }
@@ -1963,14 +2236,9 @@ const struct attribute_spec arm_attribute_table[] =
 
 /* Handle an attribute requiring a FUNCTION_DECL;
    arguments as in struct attribute_spec.handler.  */
-
 static tree
-arm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
-     tree * node;
-     tree   name;
-     tree   args ATTRIBUTE_UNUSED;
-     int    flags ATTRIBUTE_UNUSED;
-     bool * no_add_attrs;
+arm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
+                            int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
 {
   if (TREE_CODE (*node) != FUNCTION_DECL)
     {
@@ -1984,14 +2252,9 @@ arm_handle_fndecl_attribute (node, name, args, flags, no_add_attrs)
 
 /* Handle an "interrupt" or "isr" attribute;
    arguments as in struct attribute_spec.handler.  */
-
 static tree
-arm_handle_isr_attribute (node, name, args, flags, no_add_attrs)
-     tree * node;
-     tree   name;
-     tree   args;
-     int    flags;
-     bool * no_add_attrs;
+arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
+                         bool *no_add_attrs)
 {
   if (DECL_P (*node))
     {
@@ -2049,11 +2312,8 @@ arm_handle_isr_attribute (node, name, args, flags, no_add_attrs)
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
-
 static int
-arm_comp_type_attributes (type1, type2)
-     tree type1;
-     tree type2;
+arm_comp_type_attributes (tree type1, tree type2)
 {
   int l1, l2, s1, s2;
   
@@ -2094,11 +2354,8 @@ arm_comp_type_attributes (type1, type2)
 
 /*  Encode long_call or short_call attribute by prefixing
     symbol name in DECL with a special character FLAG.  */
-
 void
-arm_encode_call_attribute (decl, flag)
-  tree decl;
-  int flag;
+arm_encode_call_attribute (tree decl, int flag)
 {
   const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
   int          len = strlen (str);
@@ -2119,10 +2376,8 @@ arm_encode_call_attribute (decl, flag)
 /*  Assigns default attributes to newly defined type.  This is used to
     set short_call/long_call attributes for function types of
     functions defined inside corresponding #pragma scopes.  */
-
 static void
-arm_set_default_type_attributes (type)
-  tree type;
+arm_set_default_type_attributes (tree type)
 {
   /* Add __attribute__ ((long_call)) to all functions, when
      inside #pragma long_calls or __attribute__ ((short_call)),
@@ -2145,12 +2400,10 @@ arm_set_default_type_attributes (type)
 }
 \f
 /* Return 1 if the operand is a SYMBOL_REF for a function known to be
-   defined within the current compilation unit.  If this caanot be
+   defined within the current compilation unit.  If this cannot be
    determined, then 0 is returned.  */
-
 static int
-current_file_function_operand (sym_ref)
-  rtx sym_ref;
+current_file_function_operand (rtx sym_ref)
 {
   /* This is a bit of a fib.  A function will have a short call flag
      applied to its name if it has the short call attribute, or it has
@@ -2169,7 +2422,7 @@ current_file_function_operand (sym_ref)
   return 0;
 }
 
-/* Return non-zero if a 32 bit "long_call" should be generated for
+/* Return nonzero if a 32 bit "long_call" should be generated for
    this call.  We generate a long_call if the function:
 
         a.  has an __attribute__((long call))
@@ -2190,12 +2443,8 @@ current_file_function_operand (sym_ref)
    "call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
    and "call_value" patterns.  This is because of the difference in the
    SYM_REFs passed by these patterns.  */
-
 int
-arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
-  rtx sym_ref;
-  int call_cookie;
-  int call_symbol;
+arm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
 {
   if (!call_symbol)
     {
@@ -2222,18 +2471,19 @@ arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
     || TARGET_LONG_CALLS;
 }
 
-/* Return non-zero if it is ok to make a tail-call to DECL.  */
-
-int
-arm_function_ok_for_sibcall (decl)
-     tree decl;
+/* Return nonzero if it is ok to make a tail-call to DECL.  */
+static bool
+arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
 
+  if (cfun->machine->sibcall_blocked)
+    return false;
+
   /* Never tailcall something for which we have no decl, or if we
      are in Thumb mode.  */
   if (decl == NULL || TARGET_THUMB)
-    return 0;
+    return false;
 
   /* Get the calling method.  */
   if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
@@ -2245,26 +2495,29 @@ arm_function_ok_for_sibcall (decl)
      a branch instruction.  However, if not compiling PIC, we know
      we can reach the symbol if it is in this compilation unit.  */
   if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
-    return 0;
+    return false;
 
   /* If we are interworking and the function is not declared static
      then we can't tail-call it unless we know that it exists in this 
      compilation unit (since it might be a Thumb routine).  */
   if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
-    return 0;
+    return false;
 
   /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
   if (IS_INTERRUPT (arm_current_func_type ()))
-    return 0;
+    return false;
 
   /* Everything else is ok.  */
-  return 1;
+  return true;
 }
 
 \f
+/* Addressing mode support functions.  */
+
+/* Return nonzero if X is a legitimate immediate operand when compiling
+   for PIC.  */
 int
-legitimate_pic_operand_p (x)
-     rtx x;
+legitimate_pic_operand_p (rtx x)
 {
   if (CONSTANT_P (x)
       && flag_pic
@@ -2278,10 +2531,7 @@ legitimate_pic_operand_p (x)
 }
 
 rtx
-legitimize_pic_address (orig, mode, reg)
-     rtx orig;
-     enum machine_mode mode;
-     rtx reg;
+legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 {
   if (GET_CODE (orig) == SYMBOL_REF
       || GET_CODE (orig) == LABEL_REF)
@@ -2319,7 +2569,7 @@ legitimize_pic_address (orig, mode, reg)
 
       if ((GET_CODE (orig) == LABEL_REF
           || (GET_CODE (orig) == SYMBOL_REF && 
-              ENCODED_SHORT_CALL_ATTR_P (XSTR (orig, 0))))
+              SYMBOL_REF_LOCAL_P (orig)))
          && NEED_GOT_RELOC)
        pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
       else
@@ -2368,14 +2618,14 @@ legitimize_pic_address (orig, mode, reg)
        {
          /* The base register doesn't really matter, we only want to
             test the index for the appropriate mode.  */
-         ARM_GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win);
-
-         if (!no_new_pseudos)
-           offset = force_reg (Pmode, offset);
-         else
-           abort ();
+         if (!arm_legitimate_index_p (mode, offset, 0))
+           {
+             if (!no_new_pseudos)
+               offset = force_reg (Pmode, offset);
+             else
+               abort ();
+           }
 
-       win:
          if (GET_CODE (offset) == CONST_INT)
            return plus_constant (base, INTVAL (offset));
        }
@@ -2399,10 +2649,8 @@ legitimize_pic_address (orig, mode, reg)
    generated insns at the start of the function);  false if called
    by an exception receiver that needs the PIC register reloaded
    (in which case the insns are just dumped at the current location).  */
-
 void
-arm_finalize_pic (prologue)
-     int prologue ATTRIBUTE_UNUSED;
+arm_finalize_pic (int prologue ATTRIBUTE_UNUSED)
 {
 #ifndef AOF_ASSEMBLER
   rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
@@ -2453,105 +2701,510 @@ arm_finalize_pic (prologue)
 #endif /* AOF_ASSEMBLER */
 }
 
-#define REG_OR_SUBREG_REG(X)                                           \
-  (GET_CODE (X) == REG                                                 \
-   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
+/* Return nonzero if X is valid as an ARM state addressing register.  */
+static int
+arm_address_register_rtx_p (rtx x, int strict_p)
+{
+  int regno;
 
-#define REG_OR_SUBREG_RTX(X)                   \
-   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
+  if (GET_CODE (x) != REG)
+    return 0;
 
-#ifndef COSTS_N_INSNS
-#define COSTS_N_INSNS(N) ((N) * 4 - 2)
-#endif
+  regno = REGNO (x);
+
+  if (strict_p)
+    return ARM_REGNO_OK_FOR_BASE_P (regno);
 
+  return (regno <= LAST_ARM_REGNUM
+         || regno >= FIRST_PSEUDO_REGISTER
+         || regno == FRAME_POINTER_REGNUM
+         || regno == ARG_POINTER_REGNUM);
+}
+
+/* Return nonzero if X is a valid ARM state address operand.  */
 int
-arm_rtx_costs (x, code, outer)
-     rtx x;
-     enum rtx_code code;
-     enum rtx_code outer;
+arm_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
 {
-  enum machine_mode mode = GET_MODE (x);
-  enum rtx_code subcode;
-  int extra_cost;
+  if (arm_address_register_rtx_p (x, strict_p))
+    return 1;
 
-  if (TARGET_THUMB)
+  else if (GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC)
+    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
+
+  else if ((GET_CODE (x) == POST_MODIFY || GET_CODE (x) == PRE_MODIFY)
+          && GET_MODE_SIZE (mode) <= 4
+          && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
+          && GET_CODE (XEXP (x, 1)) == PLUS
+          && XEXP (XEXP (x, 1), 0) == XEXP (x, 0))
+    return arm_legitimate_index_p (mode, XEXP (XEXP (x, 1), 1), strict_p);
+
+  /* After reload constants split into minipools will have addresses
+     from a LABEL_REF.  */
+  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
+          && (GET_CODE (x) == LABEL_REF
+              || (GET_CODE (x) == CONST
+                  && GET_CODE (XEXP (x, 0)) == PLUS
+                  && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
+                  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
+    return 1;
+
+  else if (mode == TImode)
+    return 0;
+
+  else if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
     {
-      switch (code)
+      if (GET_CODE (x) == PLUS
+         && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
+         && GET_CODE (XEXP (x, 1)) == CONST_INT)
        {
-       case ASHIFT:
-       case ASHIFTRT:
-       case LSHIFTRT:
-       case ROTATERT:  
-       case PLUS:
-       case MINUS:
-       case COMPARE:
-       case NEG:
-       case NOT:       
-         return COSTS_N_INSNS (1);
-         
-       case MULT:                                                      
-         if (GET_CODE (XEXP (x, 1)) == CONST_INT)                      
-           {                                                           
-             int cycles = 0;                                           
-             unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
-             
-             while (i)                                         
-               {                                                       
-                 i >>= 2;                                              
-                 cycles++;                                             
-               }                                                       
-             return COSTS_N_INSNS (2) + cycles;                        
-           }
-         return COSTS_N_INSNS (1) + 16;
-         
-       case SET:                                                       
-         return (COSTS_N_INSNS (1)                                     
-                 + 4 * ((GET_CODE (SET_SRC (x)) == MEM)                
-                        + GET_CODE (SET_DEST (x)) == MEM));
-         
-       case CONST_INT:                                         
-         if (outer == SET)                                             
-           {                                                   
-             if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)            
-               return 0;                                               
-             if (thumb_shiftable_const (INTVAL (x)))                   
-               return COSTS_N_INSNS (2);                               
-             return COSTS_N_INSNS (3);                         
-           }                                                           
-         else if (outer == PLUS                                        
-                  && INTVAL (x) < 256 && INTVAL (x) > -256)            
-           return 0;                                                   
-         else if (outer == COMPARE                                     
-                  && (unsigned HOST_WIDE_INT) INTVAL (x) < 256)        
-           return 0;                                                   
-         else if (outer == ASHIFT || outer == ASHIFTRT         
-                  || outer == LSHIFTRT)                                
-           return 0;                                                   
-         return COSTS_N_INSNS (2);
-         
-       case CONST:                                                     
-       case CONST_DOUBLE:                                              
-       case LABEL_REF:                                         
-       case SYMBOL_REF:                                                
-         return COSTS_N_INSNS (3);
-         
-       case UDIV:
-       case UMOD:
-       case DIV:
-       case MOD:
-         return 100;
+         HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
 
-       case TRUNCATE:
-         return 99;
+          if (val == 4 || val == -4 || val == -8)
+           return 1;
+       }
+    }
 
-       case AND:
-       case XOR:
-       case IOR: 
-         /* XXX guess. */
-         return 8;
+  else if (GET_CODE (x) == PLUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
 
-       case ADDRESSOF:
-       case MEM:
+      return ((arm_address_register_rtx_p (xop0, strict_p)
+              && arm_legitimate_index_p (mode, xop1, strict_p))
+             || (arm_address_register_rtx_p (xop1, strict_p)
+                 && arm_legitimate_index_p (mode, xop0, strict_p)));
+    }
+
+#if 0
+  /* Reload currently can't handle MINUS, so disable this for now */
+  else if (GET_CODE (x) == MINUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      return (arm_address_register_rtx_p (xop0, strict_p)
+             && arm_legitimate_index_p (mode, xop1, strict_p));
+    }
+#endif
+
+  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
+          && GET_CODE (x) == SYMBOL_REF
+          && CONSTANT_POOL_ADDRESS_P (x)
+          && ! (flag_pic
+                && symbol_mentioned_p (get_pool_constant (x))))
+    return 1;
+
+  else if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == POST_DEC)
+          && (GET_MODE_SIZE (mode) <= 4)
+          && arm_address_register_rtx_p (XEXP (x, 0), strict_p))
+    return 1;
+
+  return 0;
+}
+
+/* Return nonzero if INDEX is valid for an address index operand in
+   ARM state.  */
+static int
+arm_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
+{
+  HOST_WIDE_INT range;
+  enum rtx_code code = GET_CODE (index);
+
+  if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
+    return (code == CONST_INT && INTVAL (index) < 1024
+           && INTVAL (index) > -1024
+           && (INTVAL (index) & 3) == 0);
+
+  if (TARGET_CIRRUS
+      && (GET_MODE_CLASS (mode) == MODE_FLOAT || mode == DImode))
+    return (code == CONST_INT
+           && INTVAL (index) < 255
+           && INTVAL (index) > -255);
+
+  if (arm_address_register_rtx_p (index, strict_p)
+      && GET_MODE_SIZE (mode) <= 4)
+    return 1;
+
+  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
+    return (code == CONST_INT
+           && INTVAL (index) < 256
+           && INTVAL (index) > -256);
+
+  /* XXX What about ldrsb?  */
+  if (GET_MODE_SIZE (mode) <= 4  && code == MULT
+      && (!arm_arch4 || (mode) != HImode))
+    {
+      rtx xiop0 = XEXP (index, 0);
+      rtx xiop1 = XEXP (index, 1);
+
+      return ((arm_address_register_rtx_p (xiop0, strict_p)
+              && power_of_two_operand (xiop1, SImode))
+             || (arm_address_register_rtx_p (xiop1, strict_p)
+                 && power_of_two_operand (xiop0, SImode)));
+    }
+
+  if (GET_MODE_SIZE (mode) <= 4
+      && (code == LSHIFTRT || code == ASHIFTRT
+         || code == ASHIFT || code == ROTATERT)
+      && (!arm_arch4 || (mode) != HImode))
+    {
+      rtx op = XEXP (index, 1);
+
+      return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
+             && GET_CODE (op) == CONST_INT
+             && INTVAL (op) > 0
+             && INTVAL (op) <= 31);
+    }
+
+  /* XXX For ARM v4 we may be doing a sign-extend operation during the
+     load, but that has a restricted addressing range and we are unable
+     to tell here whether that is the case.  To be safe we restrict all
+     loads to that range.  */
+  range = ((mode) == HImode || (mode) == QImode)
+    ? (arm_arch4 ? 256 : 4095) : 4096;
+
+  return (code == CONST_INT
+         && INTVAL (index) < range
+         && INTVAL (index) > -range);
+}
+
+/* Return nonzero if X is valid as an Thumb state base register.  */
+static int
+thumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
+{
+  int regno;
+
+  if (GET_CODE (x) != REG)
+    return 0;
+
+  regno = REGNO (x);
+
+  if (strict_p)
+    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
+
+  return (regno <= LAST_LO_REGNUM
+         || regno > LAST_VIRTUAL_REGISTER
+         || regno == FRAME_POINTER_REGNUM
+         || (GET_MODE_SIZE (mode) >= 4
+             && (regno == STACK_POINTER_REGNUM
+                 || x >= FIRST_PSEUDO_REGISTER
+                 || x == hard_frame_pointer_rtx
+                 || x == arg_pointer_rtx)));
+}
+
+/* Return nonzero if x is a legitimate index register.  This is the case
+   for any base register that can access a QImode object.  */
+inline static int
+thumb_index_register_rtx_p (rtx x, int strict_p)
+{
+  return thumb_base_register_rtx_p (x, QImode, strict_p);
+}
+
+/* Return nonzero if x is a legitimate Thumb-state address.
+   The AP may be eliminated to either the SP or the FP, so we use the
+   least common denominator, e.g. SImode, and offsets from 0 to 64.
+
+   ??? Verify whether the above is the right approach.
+
+   ??? Also, the FP may be eliminated to the SP, so perhaps that
+   needs special handling also.
+
+   ??? Look at how the mips16 port solves this problem.  It probably uses
+   better ways to solve some of these problems.
+
+   Although it is not incorrect, we don't accept QImode and HImode
+   addresses based on the frame pointer or arg pointer until the
+   reload pass starts.  This is so that eliminating such addresses
+   into stack based ones won't produce impossible code.  */
+int
+thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
+{
+  /* ??? Not clear if this is right.  Experiment.  */
+  if (GET_MODE_SIZE (mode) < 4
+      && !(reload_in_progress || reload_completed)
+      && (reg_mentioned_p (frame_pointer_rtx, x)
+         || reg_mentioned_p (arg_pointer_rtx, x)
+         || reg_mentioned_p (virtual_incoming_args_rtx, x)
+         || reg_mentioned_p (virtual_outgoing_args_rtx, x)
+         || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
+         || reg_mentioned_p (virtual_stack_vars_rtx, x)))
+    return 0;
+
+  /* Accept any base register.  SP only in SImode or larger.  */
+  else if (thumb_base_register_rtx_p (x, mode, strict_p))
+    return 1;
+
+  /* This is PC relative data before arm_reorg runs.  */
+  else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
+          && GET_CODE (x) == SYMBOL_REF
+           && CONSTANT_POOL_ADDRESS_P (x) && ! flag_pic)
+    return 1;
+
+  /* This is PC relative data after arm_reorg runs.  */
+  else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
+          && (GET_CODE (x) == LABEL_REF
+              || (GET_CODE (x) == CONST
+                  && GET_CODE (XEXP (x, 0)) == PLUS
+                  && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
+                  && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
+    return 1;
+
+  /* Post-inc indexing only supported for SImode and larger.  */
+  else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
+          && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
+    return 1;
+
+  else if (GET_CODE (x) == PLUS)
+    {
+      /* REG+REG address can be any two index registers.  */
+      /* We disallow FRAME+REG addressing since we know that FRAME
+        will be replaced with STACK, and SP relative addressing only
+        permits SP+OFFSET.  */
+      if (GET_MODE_SIZE (mode) <= 4
+         && XEXP (x, 0) != frame_pointer_rtx
+         && XEXP (x, 1) != frame_pointer_rtx
+         && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
+         && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
+       return 1;
+
+      /* REG+const has 5-7 bit offset for non-SP registers.  */
+      else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
+               || XEXP (x, 0) == arg_pointer_rtx)
+              && GET_CODE (XEXP (x, 1)) == CONST_INT
+              && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
+       return 1;
+
+      /* REG+const has 10 bit offset for SP, but only SImode and
+        larger is supported.  */
+      /* ??? Should probably check for DI/DFmode overflow here
+        just like GO_IF_LEGITIMATE_OFFSET does.  */
+      else if (GET_CODE (XEXP (x, 0)) == REG
+              && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
+              && GET_MODE_SIZE (mode) >= 4
+              && GET_CODE (XEXP (x, 1)) == CONST_INT
+              && INTVAL (XEXP (x, 1)) >= 0
+              && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
+              && (INTVAL (XEXP (x, 1)) & 3) == 0)
+       return 1;
+
+      else if (GET_CODE (XEXP (x, 0)) == REG
+              && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
+              && GET_MODE_SIZE (mode) >= 4
+              && GET_CODE (XEXP (x, 1)) == CONST_INT
+              && (INTVAL (XEXP (x, 1)) & 3) == 0)
+       return 1;
+    }
+
+  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
+          && GET_CODE (x) == SYMBOL_REF
+          && CONSTANT_POOL_ADDRESS_P (x)
+          && !(flag_pic
+               && symbol_mentioned_p (get_pool_constant (x))))
+    return 1;
+
+  return 0;
+}
+
+/* Return nonzero if VAL can be used as an offset in a Thumb-state address
+   instruction of mode MODE.  */
+int
+thumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
+{
+  switch (GET_MODE_SIZE (mode))
+    {
+    case 1:
+      return val >= 0 && val < 32;
+
+    case 2:
+      return val >= 0 && val < 64 && (val & 1) == 0;
+
+    default:
+      return (val >= 0
+             && (val + GET_MODE_SIZE (mode)) <= 128
+             && (val & 3) == 0);
+    }
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+   to be legitimate.  If we find one, return the new, valid address.  */
+rtx
+arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
+{
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
+       xop0 = force_reg (SImode, xop0);
+
+      if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
+       xop1 = force_reg (SImode, xop1);
+
+      if (ARM_BASE_REGISTER_RTX_P (xop0)
+         && GET_CODE (xop1) == CONST_INT)
+       {
+         HOST_WIDE_INT n, low_n;
+         rtx base_reg, val;
+         n = INTVAL (xop1);
+
+         if (mode == DImode || (TARGET_SOFT_FLOAT && mode == DFmode))
+           {
+             low_n = n & 0x0f;
+             n &= ~0x0f;
+             if (low_n > 4)
+               {
+                 n += 16;
+                 low_n -= 16;
+               }
+           }
+         else
+           {
+             low_n = ((mode) == TImode ? 0
+                      : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
+             n -= low_n;
+           }
+
+         base_reg = gen_reg_rtx (SImode);
+         val = force_operand (gen_rtx_PLUS (SImode, xop0,
+                                            GEN_INT (n)), NULL_RTX);
+         emit_move_insn (base_reg, val);
+         x = (low_n == 0 ? base_reg
+              : gen_rtx_PLUS (SImode, base_reg, GEN_INT (low_n)));
+       }
+      else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
+       x = gen_rtx_PLUS (SImode, xop0, xop1);
+    }
+
+  /* XXX We don't allow MINUS any more -- see comment in
+     arm_legitimate_address_p ().  */
+  else if (GET_CODE (x) == MINUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      if (CONSTANT_P (xop0))
+       xop0 = force_reg (SImode, xop0);
+
+      if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
+       xop1 = force_reg (SImode, xop1);
+
+      if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
+       x = gen_rtx_MINUS (SImode, xop0, xop1);
+    }
+
+  if (flag_pic)
+    {
+      /* We need to find and carefully transform any SYMBOL and LABEL
+        references; so go back to the original address expression.  */
+      rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
+
+      if (new_x != orig_x)
+       x = new_x;
+    }
+
+  return x;
+}
+
+\f
+
+#define REG_OR_SUBREG_REG(X)                                           \
+  (GET_CODE (X) == REG                                                 \
+   || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
+
+#define REG_OR_SUBREG_RTX(X)                   \
+   (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
+
+#ifndef COSTS_N_INSNS
+#define COSTS_N_INSNS(N) ((N) * 4 - 2)
+#endif
+/* Worker routine for arm_rtx_costs.  */
+static inline int
+arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
+{
+  enum machine_mode mode = GET_MODE (x);
+  enum rtx_code subcode;
+  int extra_cost;
+
+  if (TARGET_THUMB)
+    {
+      switch (code)
+       {
+       case ASHIFT:
+       case ASHIFTRT:
+       case LSHIFTRT:
+       case ROTATERT:  
+       case PLUS:
+       case MINUS:
+       case COMPARE:
+       case NEG:
+       case NOT:       
+         return COSTS_N_INSNS (1);
+         
+       case MULT:                                                      
+         if (GET_CODE (XEXP (x, 1)) == CONST_INT)                      
+           {                                                           
+             int cycles = 0;                                           
+             unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
+             
+             while (i)                                         
+               {                                                       
+                 i >>= 2;                                              
+                 cycles++;                                             
+               }                                                       
+             return COSTS_N_INSNS (2) + cycles;                        
+           }
+         return COSTS_N_INSNS (1) + 16;
+         
+       case SET:                                                       
+         return (COSTS_N_INSNS (1)                                     
+                 + 4 * ((GET_CODE (SET_SRC (x)) == MEM)                
+                        + GET_CODE (SET_DEST (x)) == MEM));
+         
+       case CONST_INT:                                         
+         if (outer == SET)                                             
+           {                                                   
+             if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)            
+               return 0;                                               
+             if (thumb_shiftable_const (INTVAL (x)))                   
+               return COSTS_N_INSNS (2);                               
+             return COSTS_N_INSNS (3);                         
+           }                                                           
+         else if ((outer == PLUS || outer == COMPARE)
+                  && INTVAL (x) < 256 && INTVAL (x) > -256)            
+           return 0;
+         else if (outer == AND
+                  && INTVAL (x) < 256 && INTVAL (x) >= -256)
+           return COSTS_N_INSNS (1);
+         else if (outer == ASHIFT || outer == ASHIFTRT         
+                  || outer == LSHIFTRT)                                
+           return 0;                                                   
+         return COSTS_N_INSNS (2);
+         
+       case CONST:                                                     
+       case CONST_DOUBLE:                                              
+       case LABEL_REF:                                         
+       case SYMBOL_REF:                                                
+         return COSTS_N_INSNS (3);
+         
+       case UDIV:
+       case UMOD:
+       case DIV:
+       case MOD:
+         return 100;
+
+       case TRUNCATE:
+         return 99;
+
+       case AND:
+       case XOR:
+       case IOR: 
+         /* XXX guess. */
+         return 8;
+
+       case ADDRESSOF:
+       case MEM:
          /* XXX another guess.  */
          /* Memory costs quite a lot for the first word, but subsequent words
             load at the equivalent of a single insn each.  */
@@ -2586,16 +3239,6 @@ arm_rtx_costs (x, code, outer)
          
        default:
          return 99;
-#if 0    
-       case FFS:
-       case FLOAT:
-       case FIX:
-       case UNSIGNED_FIX:
-         /* XXX guess */
-         fprintf (stderr, "unexpected code for thumb in rtx_costs: %s\n",
-                  rtx_name[code]);
-         abort ();
-#endif
        }
     }
   
@@ -2610,7 +3253,9 @@ arm_rtx_costs (x, code, outer)
 
     case DIV:
     case MOD:
-      return 100;
+    case UDIV:
+    case UMOD:
+      return optimize_size ? COSTS_N_INSNS (2) : 100;
 
     case ROTATE:
       if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
@@ -2648,11 +3293,11 @@ arm_rtx_costs (x, code, outer)
       if (GET_MODE_CLASS (mode) == MODE_FLOAT)
        return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                      || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
-                         && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
+                         && const_double_rtx_ok_for_fpa (XEXP (x, 1))))
                     ? 0 : 8)
                + ((REG_OR_SUBREG_REG (XEXP (x, 0))
                    || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
-                       && const_double_rtx_ok_for_fpu (XEXP (x, 0))))
+                       && const_double_rtx_ok_for_fpa (XEXP (x, 0))))
                   ? 0 : 8));
 
       if (((GET_CODE (XEXP (x, 0)) == CONST_INT
@@ -2677,7 +3322,7 @@ arm_rtx_costs (x, code, outer)
        return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
                + ((REG_OR_SUBREG_REG (XEXP (x, 1))
                    || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
-                       && const_double_rtx_ok_for_fpu (XEXP (x, 1))))
+                       && const_double_rtx_ok_for_fpa (XEXP (x, 1))))
                   ? 0 : 8));
 
       /* Fall through */
@@ -2743,19 +3388,41 @@ arm_rtx_costs (x, code, outer)
        {
          unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
                                      & (unsigned HOST_WIDE_INT) 0xffffffff);
-         int add_cost = const_ok_for_arm (i) ? 4 : 8;
-         int j;
+         int cost, const_ok = const_ok_for_arm (i);
+         int j, booth_unit_size;
+
+         if (arm_tune_xscale)
+           {
+             unsigned HOST_WIDE_INT masked_const;
+
+             /* The cost will be related to two insns.
+                First a load of the constant (MOV or LDR), then a multiply. */
+             cost = 2;
+             if (! const_ok)
+               cost += 1;      /* LDR is probably more expensive because
+                                  of longer result latency. */
+             masked_const = i & 0xffff8000;
+             if (masked_const != 0 && masked_const != 0xffff8000)
+               {
+                 masked_const = i & 0xf8000000;
+                 if (masked_const == 0 || masked_const == 0xf8000000)
+                   cost += 1;
+                 else
+                   cost += 2;
+               }
+             return cost;
+           }
          
          /* Tune as appropriate.  */ 
-         int booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
-         
+         cost = const_ok ? 4 : 8;
+         booth_unit_size = ((tune_flags & FL_FAST_MULT) ? 8 : 2);
          for (j = 0; i && j < 32; j += booth_unit_size)
            {
              i >>= booth_unit_size;
-             add_cost += 2;
+             cost += 2;
            }
 
-         return add_cost;
+         return cost;
        }
 
       return (((tune_flags & FL_FAST_MULT) ? 8 : 30)
@@ -2813,6 +3480,13 @@ arm_rtx_costs (x, code, outer)
        case SImode:
          return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
 
+       case V8QImode:
+       case V4HImode:
+       case V2SImode:
+       case V4QImode:
+       case V2HImode:
+           return 1;
+
        default:
          break;
        }
@@ -2837,10 +3511,10 @@ arm_rtx_costs (x, code, outer)
       return 6;
       
     case CONST_DOUBLE:                                         
-      if (const_double_rtx_ok_for_fpu (x))                     
+      if (const_double_rtx_ok_for_fpa (x))                     
        return outer == SET ? 2 : -1;                   
       else if ((outer == COMPARE || outer == PLUS)     
-              && neg_const_double_rtx_ok_for_fpu (x))          
+              && neg_const_double_rtx_ok_for_fpa (x))          
        return -1;                                              
       return 7;
       
@@ -2849,21 +3523,82 @@ arm_rtx_costs (x, code, outer)
     }
 }
 
+static bool
+arm_rtx_costs (rtx x, int code, int outer_code, int *total)
+{
+  *total = arm_rtx_costs_1 (x, code, outer_code);
+  return true;
+}
+
+/* All address computations that can be done are free, but rtx cost returns
+   the same for practically all of them.  So we weight the different types
+   of address here in the order (most pref first):
+   PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */
+static inline int
+arm_arm_address_cost (rtx x)
+{
+  enum rtx_code c  = GET_CODE (x);
+
+  if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
+    return 0;
+  if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
+    return 10;
+
+  if (c == PLUS || c == MINUS)
+    {
+      char cl0 = GET_RTX_CLASS (GET_CODE (XEXP (x, 0)));
+      char cl1 = GET_RTX_CLASS (GET_CODE (XEXP (x, 1)));
+
+      if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+       return 2;
+
+      if (cl0 == '2' || cl0 == 'c' || cl1 == '2' || cl1 == 'c')
+       return 3;
+
+      return 4;
+    }
+
+  return 6;
+}
+
+static inline int
+arm_thumb_address_cost (rtx x)
+{
+  enum rtx_code c  = GET_CODE (x);
+
+  if (c == REG)
+    return 1;
+  if (c == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    return 1;
+
+  return 2;
+}
+
 static int
-arm_adjust_cost (insn, link, dep, cost)
-     rtx insn;
-     rtx link;
-     rtx dep;
-     int cost;
+arm_address_cost (rtx x)
+{
+  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
+}
+
+static int
+arm_use_dfa_pipeline_interface (void)
+{
+  return true;
+}
+
+static int
+arm_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_is_xscale
+  if (arm_tune_xscale
       && REG_NOTE_KIND (link) == 0
-      && recog_memoized (insn) < 0
-      && recog_memoized (dep) < 0)
+      && recog_memoized (insn) >= 0
+      && recog_memoized (dep) >= 0)
     {
       int shift_opnum = get_attr_shift (insn);
       enum attr_type attr_type = get_attr_type (dep);
@@ -2930,8 +3665,6 @@ arm_adjust_cost (insn, link, dep, cost)
   return cost;
 }
 
-/* This code has been fixed for cross compilation.  */
-
 static int fpa_consts_inited = 0;
 
 static const char * const strings_fpa[8] =
@@ -2943,7 +3676,7 @@ static const char * const strings_fpa[8] =
 static REAL_VALUE_TYPE values_fpa[8];
 
 static void
-init_fpa_table ()
+init_fpa_table (void)
 {
   int i;
   REAL_VALUE_TYPE r;
@@ -2957,11 +3690,9 @@ init_fpa_table ()
   fpa_consts_inited = 1;
 }
 
-/* Return TRUE if rtx X is a valid immediate FPU constant.  */
-
+/* Return TRUE if rtx X is a valid immediate FPA constant.  */
 int
-const_double_rtx_ok_for_fpu (x)
-     rtx x;
+const_double_rtx_ok_for_fpa (rtx x)
 {
   REAL_VALUE_TYPE r;
   int i;
@@ -2980,11 +3711,9 @@ const_double_rtx_ok_for_fpu (x)
   return 0;
 }
 
-/* Return TRUE if rtx X is a valid immediate FPU constant.  */
-
+/* Return TRUE if rtx X is a valid immediate FPA constant.  */
 int
-neg_const_double_rtx_ok_for_fpu (x)
-     rtx x;
+neg_const_double_rtx_ok_for_fpa (rtx x)
 {
   REAL_VALUE_TYPE r;
   int i;
@@ -3013,11 +3742,8 @@ neg_const_double_rtx_ok_for_fpu (x)
    code.  SUBREG(MEM) always needs a reload in the places where
    s_register_operand is used, and this seemed to lead to excessive
    reloading.  */
-
 int
-s_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+s_register_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
@@ -3034,11 +3760,8 @@ s_register_operand (op, mode)
 }
 
 /* A hard register operand (even before reload.  */
-
 int
-arm_hard_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arm_hard_register_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
@@ -3048,11 +3771,8 @@ arm_hard_register_operand (op, mode)
 }
     
 /* Only accept reg, subreg(reg), const_int.  */
-
 int
-reg_or_int_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+reg_or_int_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) == CONST_INT)
     return 1;
@@ -3071,11 +3791,8 @@ reg_or_int_operand (op, mode)
 }
 
 /* Return 1 if OP is an item in memory, given that we are in reload.  */
-
 int
-arm_reload_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+arm_reload_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   int regno = true_regnum (op);
 
@@ -3089,18 +3806,11 @@ arm_reload_memory_operand (op, mode)
    memory access (architecture V4).
    MODE is QImode if called when computing constraints, or VOIDmode when
    emitting patterns.  In this latter case we cannot use memory_operand()
-   because it will fail on badly formed MEMs, which is precisly what we are
+   because it will fail on badly formed MEMs, which is precisely what we are
    trying to catch.  */
-
 int
-bad_signed_byte_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+bad_signed_byte_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-#if 0
-  if ((mode == QImode && !memory_operand (op, mode)) || GET_CODE (op) != MEM)
-    return 0;
-#endif
   if (GET_CODE (op) != MEM)
     return 0;
 
@@ -3124,11 +3834,8 @@ bad_signed_byte_operand (op, mode)
 }
 
 /* Return TRUE for valid operands for the rhs of an ARM instruction.  */
-
 int
-arm_rhs_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arm_rhs_operand (rtx op, enum machine_mode mode)
 {
   return (s_register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op))));
@@ -3136,11 +3843,8 @@ arm_rhs_operand (op, mode)
 
 /* Return TRUE for valid operands for the
    rhs of an ARM instruction, or a load.  */
-
 int
-arm_rhsm_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arm_rhsm_operand (rtx op, enum machine_mode mode)
 {
   return (s_register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT && const_ok_for_arm (INTVAL (op)))
@@ -3149,11 +3853,8 @@ arm_rhsm_operand (op, mode)
 
 /* Return TRUE for valid operands for the rhs of an ARM instruction, or if a
    constant that is valid when negated.  */
-
 int
-arm_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arm_add_operand (rtx op, enum machine_mode mode)
 {
   if (TARGET_THUMB)
     return thumb_cmp_operand (op, mode);
@@ -3164,10 +3865,17 @@ arm_add_operand (op, mode)
                  || const_ok_for_arm (-INTVAL (op)))));
 }
 
+/* Return TRUE for valid ARM constants (or when valid if negated).  */
+int
+arm_addimm_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (op) == CONST_INT
+         && (const_ok_for_arm (INTVAL (op))
+             || const_ok_for_arm (-INTVAL (op))));
+}
+
 int
-arm_not_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+arm_not_operand (rtx op, enum machine_mode mode)
 {
   return (s_register_operand (op, mode)
          || (GET_CODE (op) == CONST_INT
@@ -3177,11 +3885,8 @@ arm_not_operand (op, mode)
 
 /* Return TRUE if the operand is a memory reference which contains an
    offsettable address.  */
-
 int
-offsettable_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+offsettable_memory_operand (rtx op, enum machine_mode mode)
 {
   if (mode == VOIDmode)
     mode = GET_MODE (op);
@@ -3194,11 +3899,8 @@ offsettable_memory_operand (op, mode)
 
 /* Return TRUE if the operand is a memory reference which is, or can be
    made word aligned by adjusting the offset.  */
-
 int
-alignable_memory_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+alignable_memory_operand (rtx op, enum machine_mode mode)
 {
   rtx reg;
 
@@ -3223,11 +3925,8 @@ alignable_memory_operand (op, mode)
 
 /* Similar to s_register_operand, but does not allow hard integer 
    registers.  */
-
 int
-f_register_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+f_register_operand (rtx op, enum machine_mode mode)
 {
   if (GET_MODE (op) != mode && mode != VOIDmode)
     return 0;
@@ -3239,15 +3938,12 @@ f_register_operand (op, mode)
      to be a register operand.  */
   return (GET_CODE (op) == REG
          && (REGNO (op) >= FIRST_PSEUDO_REGISTER
-             || REGNO_REG_CLASS (REGNO (op)) == FPU_REGS));
+             || REGNO_REG_CLASS (REGNO (op)) == FPA_REGS));
 }
 
-/* Return TRUE for valid operands for the rhs of an FPU instruction.  */
-
+/* Return TRUE for valid operands for the rhs of an FPA instruction.  */
 int
-fpu_rhs_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+fpa_rhs_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3256,15 +3952,13 @@ fpu_rhs_operand (op, mode)
     return FALSE;
 
   if (GET_CODE (op) == CONST_DOUBLE)
-    return const_double_rtx_ok_for_fpu (op);
+    return const_double_rtx_ok_for_fpa (op);
 
   return FALSE;
 }
 
 int
-fpu_add_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+fpa_add_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3273,18 +3967,263 @@ fpu_add_operand (op, mode)
     return FALSE;
 
   if (GET_CODE (op) == CONST_DOUBLE)
-    return (const_double_rtx_ok_for_fpu (op) 
-           || neg_const_double_rtx_ok_for_fpu (op));
+    return (const_double_rtx_ok_for_fpa (op) 
+           || neg_const_double_rtx_ok_for_fpa (op));
 
   return FALSE;
 }
 
-/* Return nonzero if OP is a constant power of two.  */
+/* Return nonzero if OP is a valid Cirrus memory address pattern.  */
+int
+cirrus_memory_offset (rtx op)
+{
+  /* Reject eliminable registers.  */
+  if (! (reload_in_progress || reload_completed)
+      && (   reg_mentioned_p (frame_pointer_rtx, op)
+         || reg_mentioned_p (arg_pointer_rtx, op)
+         || reg_mentioned_p (virtual_incoming_args_rtx, op)
+         || reg_mentioned_p (virtual_outgoing_args_rtx, op)
+         || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
+         || reg_mentioned_p (virtual_stack_vars_rtx, op)))
+    return 0;
+
+  if (GET_CODE (op) == MEM)
+    {
+      rtx ind;
+
+      ind = XEXP (op, 0);
+
+      /* Match: (mem (reg)).  */
+      if (GET_CODE (ind) == REG)
+       return 1;
+
+      /* Match:
+        (mem (plus (reg)
+                   (const))).  */
+      if (GET_CODE (ind) == PLUS
+         && GET_CODE (XEXP (ind, 0)) == REG
+         && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
+         && GET_CODE (XEXP (ind, 1)) == CONST_INT)
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Return nonzero if OP is a Cirrus or general register.  */
+int
+cirrus_register_operand (rtx op, enum machine_mode mode)
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  return (GET_CODE (op) == REG
+         && (REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS
+             || REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS));
+}
+
+/* Return nonzero if OP is a cirrus FP register.  */
+int
+cirrus_fp_register (rtx op, enum machine_mode mode)
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return FALSE;
+
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  return (GET_CODE (op) == REG
+         && (REGNO (op) >= FIRST_PSEUDO_REGISTER
+             || REGNO_REG_CLASS (REGNO (op)) == CIRRUS_REGS));
+}
+
+/* Return nonzero if OP is a 6bit constant (0..63).  */
+int
+cirrus_shift_const (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (op) == CONST_INT
+         && INTVAL (op) >= 0
+         && INTVAL (op) < 64);
+}
+
+/* Returns TRUE if INSN is an "LDR REG, ADDR" instruction.
+   Use by the Cirrus Maverick code which has to workaround
+   a hardware bug triggered by such instructions.  */
+static bool
+arm_memory_load_p (rtx insn)
+{
+  rtx body, lhs, rhs;;
+
+  if (insn == NULL_RTX || GET_CODE (insn) != INSN)
+    return false;
+
+  body = PATTERN (insn);
+
+  if (GET_CODE (body) != SET)
+    return false;
+
+  lhs = XEXP (body, 0);
+  rhs = XEXP (body, 1);
+
+  lhs = REG_OR_SUBREG_RTX (lhs);
+
+  /* If the destination is not a general purpose
+     register we do not have to worry.  */
+  if (GET_CODE (lhs) != REG
+      || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
+    return false;
+
+  /* As well as loads from memory we also have to react
+     to loads of invalid constants which will be turned
+     into loads from the minipool.  */
+  return (GET_CODE (rhs) == MEM
+         || GET_CODE (rhs) == SYMBOL_REF
+         || note_invalid_constants (insn, -1, false));
+}
+
+/* Return TRUE if INSN is a Cirrus instruction.  */
+static bool
+arm_cirrus_insn_p (rtx insn)
+{
+  enum attr_cirrus attr;
+
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!insn
+      || GET_CODE (insn) != INSN
+      || GET_CODE (PATTERN (insn)) == USE
+      || GET_CODE (PATTERN (insn)) == CLOBBER)
+    return 0;
+
+  attr = get_attr_cirrus (insn);
+
+  return attr != CIRRUS_NOT;
+}
+
+/* Cirrus reorg for invalid instruction combinations.  */
+static void
+cirrus_reorg (rtx first)
+{
+  enum attr_cirrus attr;
+  rtx body = PATTERN (first);
+  rtx t;
+  int nops;
+
+  /* Any branch must be followed by 2 non Cirrus instructions.  */
+  if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
+    {
+      nops = 0;
+      t = next_nonnote_insn (first);
+
+      if (arm_cirrus_insn_p (t))
+       ++ nops;
+
+      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
+       ++ nops;
+
+      while (nops --)
+       emit_insn_after (gen_nop (), first);
+
+      return;
+    }
+
+  /* (float (blah)) is in parallel with a clobber.  */
+  if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
+    body = XVECEXP (body, 0, 0);
+
+  if (GET_CODE (body) == SET)
+    {
+      rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
+
+      /* cfldrd, cfldr64, cfstrd, cfstr64 must
+        be followed by a non Cirrus insn.  */
+      if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
+       {
+         if (arm_cirrus_insn_p (next_nonnote_insn (first)))
+           emit_insn_after (gen_nop (), first);
+
+         return;
+       }
+      else if (arm_memory_load_p (first))
+       {
+         unsigned int arm_regno;
+
+         /* Any ldr/cfmvdlr, ldr/cfmvdhr, ldr/cfmvsr, ldr/cfmv64lr,
+            ldr/cfmv64hr combination where the Rd field is the same
+            in both instructions must be split with a non Cirrus
+            insn.  Example:
+
+            ldr r0, blah
+            nop
+            cfmvsr mvf0, r0.  */
+
+         /* Get Arm register number for ldr insn.  */
+         if (GET_CODE (lhs) == REG)
+           arm_regno = REGNO (lhs);
+         else if (GET_CODE (rhs) == REG)
+           arm_regno = REGNO (rhs);
+         else
+           abort ();
+
+         /* Next insn.  */
+         first = next_nonnote_insn (first);
+
+         if (! arm_cirrus_insn_p (first))
+           return;
+
+         body = PATTERN (first);
+
+          /* (float (blah)) is in parallel with a clobber.  */
+          if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
+           body = XVECEXP (body, 0, 0);
+
+         if (GET_CODE (body) == FLOAT)
+           body = XEXP (body, 0);
+
+         if (get_attr_cirrus (first) == CIRRUS_MOVE
+             && GET_CODE (XEXP (body, 1)) == REG
+             && arm_regno == REGNO (XEXP (body, 1)))
+           emit_insn_after (gen_nop (), first);
+
+         return;
+       }
+    }
+
+  /* get_attr aborts on USE and CLOBBER.  */
+  if (!first
+      || GET_CODE (first) != INSN
+      || GET_CODE (PATTERN (first)) == USE
+      || GET_CODE (PATTERN (first)) == CLOBBER)
+    return;
+
+  attr = get_attr_cirrus (first);
+
+  /* Any coprocessor compare instruction (cfcmps, cfcmpd, ...)
+     must be followed by a non-coprocessor instruction.  */
+  if (attr == CIRRUS_COMPARE)
+    {
+      nops = 0;
+
+      t = next_nonnote_insn (first);
+
+      if (arm_cirrus_insn_p (t))
+       ++ nops;
+
+      if (arm_cirrus_insn_p (next_nonnote_insn (t)))
+       ++ nops;
+
+      while (nops --)
+       emit_insn_after (gen_nop (), first);
+
+      return;
+    }
+}
 
+/* Return nonzero if OP is a constant power of two.  */
 int
-power_of_two_operand (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+power_of_two_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) == CONST_INT)
     {
@@ -3300,11 +4239,8 @@ power_of_two_operand (op, mode)
    Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
    Note that this disallows MEM(REG+REG), but allows
    MEM(PRE/POST_INC/DEC(REG)).  */
-
 int
-di_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+di_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3330,11 +4266,8 @@ di_operand (op, mode)
 }
 
 /* Like di_operand, but don't accept constants.  */
-
 int
-nonimmediate_di_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+nonimmediate_di_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3355,11 +4288,8 @@ nonimmediate_di_operand (op, mode)
    Either: REG, SUBREG, CONST_DOUBLE or MEM(DImode_address).
    Note that this disallows MEM(REG+REG), but allows
    MEM(PRE/POST_INC/DEC(REG)).  */
-
 int
-soft_df_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+soft_df_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3387,11 +4317,8 @@ soft_df_operand (op, mode)
 }
 
 /* Like soft_df_operand, but don't accept constants.  */
-
 int
-nonimmediate_soft_df_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+nonimmediate_soft_df_operand (rtx op, enum machine_mode mode)
 {
   if (s_register_operand (op, mode))
     return TRUE;
@@ -3408,11 +4335,8 @@ nonimmediate_soft_df_operand (op, mode)
 }
 
 /* Return TRUE for valid index operands.  */
-
 int
-index_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+index_operand (rtx op, enum machine_mode mode)
 {
   return (s_register_operand (op, mode)
          || (immediate_operand (op, mode)
@@ -3423,11 +4347,8 @@ index_operand (op, mode)
 /* Return TRUE for valid shifts by a constant. This also accepts any
    power of two on the (somewhat overly relaxed) assumption that the
    shift operator in this case was a mult.  */
-
 int
-const_shift_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+const_shift_operand (rtx op, enum machine_mode mode)
 {
   return (power_of_two_operand (op, mode)
          || (immediate_operand (op, mode)
@@ -3437,11 +4358,8 @@ const_shift_operand (op, mode)
 
 /* Return TRUE for arithmetic operators which can be combined with a multiply
    (shift).  */
-
 int
-shiftable_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+shiftable_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code;
 
@@ -3455,11 +4373,8 @@ shiftable_operator (x, mode)
 }
 
 /* Return TRUE for binary logical operators.  */
-
 int
-logical_binary_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+logical_binary_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code;
 
@@ -3472,11 +4387,8 @@ logical_binary_operator (x, mode)
 }
 
 /* Return TRUE for shift operators.  */
-
 int
-shift_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+shift_operator (rtx x,enum machine_mode mode)
 {
   enum rtx_code code;
 
@@ -3493,21 +4405,15 @@ shift_operator (x, mode)
 }
 
 /* Return TRUE if x is EQ or NE.  */
-
 int
-equality_operator (x, mode)
-     rtx x;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+equality_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return GET_CODE (x) == EQ || GET_CODE (x) == NE;
 }
 
 /* Return TRUE if x is a comparison operator other than LTGT or UNEQ.  */
-
 int
-arm_comparison_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+arm_comparison_operator (rtx x, enum machine_mode mode)
 {
   return (comparison_operator (x, mode)
          && GET_CODE (x) != LTGT
@@ -3515,11 +4421,8 @@ arm_comparison_operator (x, mode)
 }
 
 /* Return TRUE for SMIN SMAX UMIN UMAX operators.  */
-
 int
-minmax_operator (x, mode)
-     rtx x;
-     enum machine_mode mode;
+minmax_operator (rtx x, enum machine_mode mode)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -3531,11 +4434,8 @@ minmax_operator (x, mode)
 
 /* Return TRUE if this is the condition code register, if we aren't given
    a mode, accept any class CCmode register.  */
-
 int
-cc_register (x, mode)
-     rtx x;
-     enum machine_mode mode;
+cc_register (rtx x, enum machine_mode mode)
 {
   if (mode == VOIDmode)
     {
@@ -3556,11 +4456,8 @@ cc_register (x, mode)
 /* Return TRUE if this is the condition code register, if we aren't given
    a mode, accept any class CCmode register which indicates a dominance
    expression.  */
-
 int
-dominant_cc_register (x, mode)
-     rtx x;
-     enum machine_mode mode;
+dominant_cc_register (rtx x, enum machine_mode mode)
 {
   if (mode == VOIDmode)
     {
@@ -3570,7 +4467,7 @@ dominant_cc_register (x, mode)
        return FALSE;
     }
 
-  if (   mode != CC_DNEmode && mode != CC_DEQmode
+  if (mode != CC_DNEmode && mode != CC_DEQmode
       && mode != CC_DLEmode && mode != CC_DLTmode
       && mode != CC_DGEmode && mode != CC_DGTmode
       && mode != CC_DLEUmode && mode != CC_DLTUmode
@@ -3581,10 +4478,8 @@ dominant_cc_register (x, mode)
 }
 
 /* Return TRUE if X references a SYMBOL_REF.  */
-
 int
-symbol_mentioned_p (x)
-     rtx x;
+symbol_mentioned_p (rtx x)
 {
   const char * fmt;
   int i;
@@ -3612,10 +4507,8 @@ symbol_mentioned_p (x)
 }
 
 /* Return TRUE if X references a LABEL_REF.  */
-
 int
-label_mentioned_p (x)
-     rtx x;
+label_mentioned_p (rtx x)
 {
   const char * fmt;
   int i;
@@ -3642,8 +4535,7 @@ label_mentioned_p (x)
 }
 
 enum rtx_code
-minmax_code (x)
-     rtx x;
+minmax_code (rtx x)
 {
   enum rtx_code code = GET_CODE (x);
 
@@ -3660,10 +4552,8 @@ minmax_code (x)
 }
 
 /* Return 1 if memory locations are adjacent.  */
-
 int
-adjacent_mem_locations (a, b)
-     rtx a, b;
+adjacent_mem_locations (rtx a, rtx b)
 {
   if ((GET_CODE (XEXP (a, 0)) == REG
        || (GET_CODE (XEXP (a, 0)) == PLUS
@@ -3691,6 +4581,12 @@ adjacent_mem_locations (a, b)
       else
        reg1 = REGNO (XEXP (b, 0));
 
+      /* Don't accept any offset that will require multiple
+        instructions to handle, since this would cause the
+        arith_adjacentmem pattern to output an overlong sequence.  */
+      if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
+       return 0;
+      
       return (reg0 == reg1) && ((val1 - val0) == 4 || (val0 - val1) == 4);
     }
   return 0;
@@ -3698,11 +4594,8 @@ adjacent_mem_locations (a, b)
 
 /* Return 1 if OP is a load multiple operation.  It is known to be
    parallel and the first section will be tested.  */
-
 int
-load_multiple_operation (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+load_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT count = XVECLEN (op, 0);
   int dest_regno;
@@ -3761,11 +4654,8 @@ load_multiple_operation (op, mode)
 
 /* Return 1 if OP is a store multiple operation.  It is known to be
    parallel and the first section will be tested.  */
-
 int
-store_multiple_operation (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+store_multiple_operation (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT count = XVECLEN (op, 0);
   int src_regno;
@@ -3823,12 +4713,8 @@ store_multiple_operation (op, mode)
 }
 
 int
-load_multiple_sequence (operands, nops, regs, base, load_offset)
-     rtx * operands;
-     int nops;
-     int * regs;
-     int * base;
-     HOST_WIDE_INT * load_offset;
+load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
+                       HOST_WIDE_INT *load_offset)
 {
   int unsorted_regs[4];
   HOST_WIDE_INT unsorted_offsets[4];
@@ -3998,9 +4884,7 @@ load_multiple_sequence (operands, nops, regs, base, load_offset)
 }
 
 const char *
-emit_ldm_seq (operands, nops)
-     rtx * operands;
-     int nops;
+emit_ldm_seq (rtx *operands, int nops)
 {
   int regs[4];
   int base_reg;
@@ -4058,12 +4942,8 @@ emit_ldm_seq (operands, nops)
 }
 
 int
-store_multiple_sequence (operands, nops, regs, base, load_offset)
-     rtx * operands;
-     int nops;
-     int * regs;
-     int * base;
-     HOST_WIDE_INT * load_offset;
+store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
+                        HOST_WIDE_INT * load_offset)
 {
   int unsorted_regs[4];
   HOST_WIDE_INT unsorted_offsets[4];
@@ -4195,9 +5075,7 @@ store_multiple_sequence (operands, nops, regs, base, load_offset)
 }
 
 const char *
-emit_stm_seq (operands, nops)
-     rtx * operands;
-     int nops;
+emit_stm_seq (rtx *operands, int nops)
 {
   int regs[4];
   int base_reg;
@@ -4241,9 +5119,7 @@ emit_stm_seq (operands, nops)
 }
 
 int
-multi_register_push (op, mode)
-     rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+multi_register_push (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   if (GET_CODE (op) != PARALLEL
       || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
@@ -4257,16 +5133,9 @@ multi_register_push (op, mode)
 /* Routines for use in generating RTL.  */
 
 rtx
-arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
-                      in_struct_p, scalar_p)
-     int base_regno;
-     int count;
-     rtx from;
-     int up;
-     int write_back;
-     int unchanging_p;
-     int in_struct_p;
-     int scalar_p;
+arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
+                      int write_back, int unchanging_p, int in_struct_p,
+                      int scalar_p)
 {
   int i = 0, j;
   rtx result;
@@ -4301,7 +5170,7 @@ arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
 
      As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
      for counts of 3 or 4 regs.  */
-  if (arm_is_xscale && count <= 2 && ! optimize_size)
+  if (arm_tune_xscale && count <= 2 && ! optimize_size)
     {
       rtx seq;
       
@@ -4350,16 +5219,9 @@ arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
 }
 
 rtx
-arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
-                       in_struct_p, scalar_p)
-     int base_regno;
-     int count;
-     rtx to;
-     int up;
-     int write_back;
-     int unchanging_p;
-     int in_struct_p;
-     int scalar_p;
+arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
+                       int write_back, int unchanging_p, int in_struct_p,
+                       int scalar_p)
 {
   int i = 0, j;
   rtx result;
@@ -4368,7 +5230,7 @@ arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
 
   /* See arm_gen_load_multiple for discussion of
      the pros/cons of ldm/stm usage for XScale.  */
-  if (arm_is_xscale && count <= 2 && ! optimize_size)
+  if (arm_tune_xscale && count <= 2 && ! optimize_size)
     {
       rtx seq;
       
@@ -4418,8 +5280,7 @@ arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
 }
 
 int
-arm_gen_movstrqi (operands)
-     rtx * operands;
+arm_gen_movstrqi (rtx *operands)
 {
   HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
   int i;
@@ -4449,7 +5310,7 @@ arm_gen_movstrqi (operands)
   fin_dst = dst = copy_to_mode_reg (SImode, st_dst);
   fin_src = src = copy_to_mode_reg (SImode, st_src);
 
-  in_words_to_go = NUM_INTS (INTVAL (operands[2]));
+  in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
   out_words_to_go = INTVAL (operands[2]) / 4;
   last_bytes = INTVAL (operands[2]) & 3;
 
@@ -4602,8 +5463,7 @@ arm_gen_movstrqi (operands)
    known to be alignable and of the form reg, or plus (reg, const).  */
 
 rtx
-arm_gen_rotated_half_load (memref)
-     rtx memref;
+arm_gen_rotated_half_load (rtx memref)
 {
   HOST_WIDE_INT offset = 0;
   rtx base = XEXP (memref, 0);
@@ -4627,19 +5487,17 @@ arm_gen_rotated_half_load (memref)
   return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
 }
 
-/* Select a dominance comparison mode if possible.  We support three forms.
-   COND_OR == 0 => (X && Y) 
-   COND_OR == 1 => ((! X( || Y)
-   COND_OR == 2 => (X || Y) 
-   If we are unable to support a dominance comparsison we return CC mode.  
-   This will then fail to match for the RTL expressions that generate this
-   call.  */
-
-static enum machine_mode
-select_dominance_cc_mode (x, y, cond_or)
-     rtx x;
-     rtx y;
-     HOST_WIDE_INT cond_or;
+/* Select a dominance comparison mode if possible for a test of the general
+   form (OP (COND_OR (X) (Y)) (const_int 0)).  We support three forms.
+   COND_OR == DOM_CC_X_AND_Y => (X && Y) 
+   COND_OR == DOM_CC_NX_OR_Y => ((! X) || Y)
+   COND_OR == DOM_CC_X_OR_Y => (X || Y) 
+   In all cases OP will be either EQ or NE, but we don't need to know which
+   here.  If we are unable to support a dominance comparison we return 
+   CC mode.  This will then fail to match for the RTL expressions that
+   generate this call.  */
+enum machine_mode
+arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
 {
   enum rtx_code cond1, cond2;
   int swapped = 0;
@@ -4656,7 +5514,7 @@ select_dominance_cc_mode (x, y, cond_or)
   /* The if_then_else variant of this tests the second condition if the
      first passes, but is true if the first fails.  Reverse the first
      condition to get a true "inclusive-or" expression.  */
-  if (cond_or == 1)
+  if (cond_or == DOM_CC_NX_OR_Y)
     cond1 = reverse_condition (cond1);
 
   /* If the comparisons are not equal, and one doesn't dominate the other,
@@ -4676,7 +5534,7 @@ select_dominance_cc_mode (x, y, cond_or)
   switch (cond1)
     {
     case EQ:
-      if (cond2 == EQ || !cond_or)
+      if (cond2 == EQ || cond_or == DOM_CC_X_AND_Y)
        return CC_DEQmode;
 
       switch (cond2)
@@ -4691,7 +5549,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case LT:
-      if (cond2 == LT || !cond_or)
+      if (cond2 == LT || cond_or == DOM_CC_X_AND_Y)
        return CC_DLTmode;
       if (cond2 == LE)
        return CC_DLEmode;
@@ -4700,7 +5558,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case GT:
-      if (cond2 == GT || !cond_or)
+      if (cond2 == GT || cond_or == DOM_CC_X_AND_Y)
        return CC_DGTmode;
       if (cond2 == GE)
        return CC_DGEmode;
@@ -4709,7 +5567,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
       
     case LTU:
-      if (cond2 == LTU || !cond_or)
+      if (cond2 == LTU || cond_or == DOM_CC_X_AND_Y)
        return CC_DLTUmode;
       if (cond2 == LEU)
        return CC_DLEUmode;
@@ -4718,7 +5576,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case GTU:
-      if (cond2 == GTU || !cond_or)
+      if (cond2 == GTU || cond_or == DOM_CC_X_AND_Y)
        return CC_DGTUmode;
       if (cond2 == GEU)
        return CC_DGEUmode;
@@ -4751,10 +5609,7 @@ select_dominance_cc_mode (x, y, cond_or)
 }
 
 enum machine_mode
-arm_select_cc_mode (op, x, y)
-     enum rtx_code op;
-     rtx x;
-     rtx y;
+arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
 {
   /* All floating point compares return CCFP if it is an equality
      comparison, and CCFPE otherwise.  */
@@ -4778,6 +5633,8 @@ arm_select_cc_mode (op, x, y)
        case LE:
        case GT:
        case GE:
+         if (TARGET_CIRRUS)
+           return CCFPmode;
          return CCFPEmode;
 
        default:
@@ -4817,24 +5674,35 @@ arm_select_cc_mode (op, x, y)
          || XEXP (x, 2) == const1_rtx)
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
-    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 
-                                    INTVAL (XEXP (x, 2)));
+    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 
+                                        INTVAL (XEXP (x, 2)));
 
   /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
   if (GET_CODE (x) == AND
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
-    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 0);
+    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
+                                        DOM_CC_X_AND_Y);
 
   if (GET_CODE (x) == IOR
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
       && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
-    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 2);
+    return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
+                                        DOM_CC_X_OR_Y);
+
+  /* An operation (on Thumb) where we want to test for a single bit.
+     This is done by shifting that bit up into the top bit of a
+     scratch register; we can then branch on the sign bit.  */
+  if (TARGET_THUMB
+      && GET_MODE (x) == SImode
+      && (op == EQ || op == NE)
+      && (GET_CODE (x) == ZERO_EXTRACT))
+    return CC_Nmode;
 
   /* An operation that sets the condition codes as a side-effect, the
      V flag is not set correctly, so we can only use comparisons where
      this doesn't matter.  (For LT and GE we can use "mi" and "pl"
-     instead.  */
+     instead.)  */
   if (GET_MODE (x) == SImode
       && y == const0_rtx
       && (op == EQ || op == NE || op == LT || op == GE)
@@ -4844,7 +5712,8 @@ arm_select_cc_mode (op, x, y)
          || GET_CODE (x) == NOT || GET_CODE (x) == NEG
          || GET_CODE (x) == LSHIFTRT
          || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
-         || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT))
+         || GET_CODE (x) == ROTATERT
+         || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
     return CC_NOOVmode;
 
   if (GET_MODE (x) == QImode && (op == EQ || op == NE))
@@ -4861,11 +5730,8 @@ arm_select_cc_mode (op, x, y)
 /* X and Y are two things to compare using CODE.  Emit the compare insn and
    return the rtx for register 0 in the proper mode.  FP means this is a
    floating point compare: I don't think that it is needed on the arm.  */
-
 rtx
-arm_gen_compare_reg (code, x, y)
-     enum rtx_code code;
-     rtx x, y;
+arm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
 {
   enum machine_mode mode = SELECT_CC_MODE (code, x, y);
   rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
@@ -4876,9 +5742,20 @@ arm_gen_compare_reg (code, x, y)
   return cc_reg;
 }
 
+/* Generate a sequence of insns that will generate the correct return
+   address mask depending on the physical architecture that the program
+   is running on.  */
+rtx
+arm_gen_return_addr_mask (void)
+{
+  rtx reg = gen_reg_rtx (Pmode);
+
+  emit_insn (gen_return_addr_mask (reg));
+  return reg;
+}
+
 void
-arm_reload_in_hi (operands)
-     rtx * operands;
+arm_reload_in_hi (rtx *operands)
 {
   rtx ref = operands[1];
   rtx base, scratch;
@@ -4956,7 +5833,14 @@ arm_reload_in_hi (operands)
        }
     }
 
-  scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
+  /* Operands[2] may overlap operands[0] (though it won't overlap
+     operands[1]), that's why we asked for a DImode reg -- so we can
+     use the bit that does not overlap.  */
+  if (REGNO (operands[2]) == REGNO (operands[0]))
+    scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
+  else
+    scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
+
   emit_insn (gen_zero_extendqisi2 (scratch,
                                   gen_rtx_MEM (QImode,
                                                plus_constant (base,
@@ -4982,16 +5866,14 @@ arm_reload_in_hi (operands)
                                                         0))));
 }
 
-/* Handle storing a half-word to memory during reload by synthesising as two
+/* Handle storing a half-word to memory during reload by synthesizing as two
    byte stores.  Take care not to clobber the input values until after we
    have moved them somewhere safe.  This code assumes that if the DImode
    scratch in operands[2] overlaps either the input value or output address
    in some way, then that value must die in this insn (we absolutely need
    two scratch registers for some corner cases).  */
-
 void
-arm_reload_out_hi (operands)
-     rtx * operands;
+arm_reload_out_hi (rtx *operands)
 {
   rtx ref = operands[0];
   rtx outval = operands[1];
@@ -5149,11 +6031,8 @@ arm_reload_out_hi (operands)
 }
 \f
 /* Print a symbolic form of X to the debug file, F.  */
-
 static void
-arm_print_value (f, x)
-     FILE * f;
-     rtx x;
+arm_print_value (FILE *f, rtx x)
 {
   switch (GET_CODE (x))
     {
@@ -5165,6 +6044,21 @@ arm_print_value (f, x)
       fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
       return;
 
+    case CONST_VECTOR:
+      {
+       int i;
+
+       fprintf (f, "<");
+       for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
+         {
+           fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
+           if (i < (CONST_VECTOR_NUNITS (x) - 1))
+             fputc (',', f);
+         }
+       fprintf (f, ">");
+      }
+      return;
+
     case CONST_STRING:
       fprintf (f, "\"%s\"", XSTR (x, 0));
       return;
@@ -5285,6 +6179,8 @@ struct minipool_node
   rtx value;
   /* The mode of value.  */
   enum machine_mode mode;
+  /* The size of the value.  With iWMMXt enabled
+     sizes > 4 also imply an alignment of 8-bytes.  */
   int fix_size;
 };
 
@@ -5318,10 +6214,8 @@ Mfix *           minipool_barrier;
 
 /* Determines if INSN is the start of a jump table.  Returns the end
    of the TABLE or NULL_RTX.  */
-
 static rtx
-is_jump_table (insn)
-     rtx insn;
+is_jump_table (rtx insn)
 {
   rtx table;
   
@@ -5343,8 +6237,7 @@ is_jump_table (insn)
 #endif
 
 static HOST_WIDE_INT
-get_jump_table_size (insn)
-     rtx insn;
+get_jump_table_size (rtx insn)
 {
   /* ADDR_VECs only take room if read-only data does into the text
      section.  */
@@ -5365,13 +6258,10 @@ get_jump_table_size (insn)
 
 /* Move a minipool fix MP from its current location to before MAX_MP.
    If MAX_MP is NULL, then MP doesn't need moving, but the addressing
-   contrains may need updating.  */
-
+   constraints may need updating.  */
 static Mnode *
-move_minipool_fix_forward_ref (mp, max_mp, max_address)
-     Mnode *       mp;
-     Mnode *       max_mp;
-     HOST_WIDE_INT max_address;
+move_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
+                              HOST_WIDE_INT max_address)
 {
   /* This should never be true and the code below assumes these are
      different.  */
@@ -5426,10 +6316,8 @@ move_minipool_fix_forward_ref (mp, max_mp, max_address)
 
 /* Add a constant to the minipool for a forward reference.  Returns the
    node added or NULL if the constant will not fit in this pool.  */
-
 static Mnode *
-add_minipool_forward_ref (fix)
-     Mfix * fix;
+add_minipool_forward_ref (Mfix *fix)
 {
   /* If set, max_mp is the first pool_entry that has a lower
      constraint than the one we are trying to add.  */
@@ -5468,13 +6356,26 @@ add_minipool_forward_ref (fix)
       if (max_mp == NULL
          && mp->max_address > max_address)
        max_mp = mp;
+
+      /* If we are inserting an 8-bytes aligned quantity and
+        we have not already found an insertion point, then
+        make sure that all such 8-byte aligned quantities are
+        placed at the start of the pool.  */
+      if (TARGET_REALLY_IWMMXT
+         && max_mp == NULL
+         && fix->fix_size == 8
+         && mp->fix_size != 8)
+       {
+         max_mp = mp;
+         max_address = mp->max_address;
+       }
     }
 
   /* The value is not currently in the minipool, so we need to create
      a new entry for it.  If MAX_MP is NULL, the entry will be put on
      the end of the list since the placement is less constrained than
      any existing entry.  Otherwise, we insert the new fix before
-     MAX_MP and, if neceesary, adjust the constraints on the other
+     MAX_MP and, if necessary, adjust the constraints on the other
      entries.  */
   mp = xmalloc (sizeof (* mp));
   mp->fix_size = fix->fix_size;
@@ -5532,10 +6433,8 @@ add_minipool_forward_ref (fix)
 }
 
 static Mnode *
-move_minipool_fix_backward_ref (mp, min_mp, min_address)
-     Mnode *        mp;
-     Mnode *        min_mp;
-     HOST_WIDE_INT  min_address;
+move_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
+                               HOST_WIDE_INT  min_address)
 {
   HOST_WIDE_INT offset;
 
@@ -5595,17 +6494,15 @@ move_minipool_fix_backward_ref (mp, min_mp, min_address)
    somewhat confusing because the calculated offsets for each fix do
    not take into account the size of the pool (which is still under
    construction.  */
-
 static Mnode *
-add_minipool_backward_ref (fix)
-     Mfix * fix;
+add_minipool_backward_ref (Mfix *fix)
 {
   /* If set, min_mp is the last pool_entry that has a lower constraint
      than the one we are trying to add.  */
-  Mnode *        min_mp = NULL;
+  Mnode *min_mp = NULL;
   /* This can be negative, since it is only a constraint.  */
   HOST_WIDE_INT  min_address = fix->address - fix->backwards;
-  Mnode *        mp;
+  Mnode *mp;
 
   /* If we can't reach the current pool from this insn, or if we can't
      insert this entry at the end of the pool without pushing other
@@ -5645,7 +6542,14 @@ add_minipool_backward_ref (fix)
        {
          /* Note the insertion point if necessary.  */
          if (mp->min_address < min_address)
-           min_mp = mp;
+           {
+             /* For now, we do not allow the insertion of 8-byte alignment
+                requiring nodes anywhere but at the start of the pool.  */
+             if (TARGET_REALLY_IWMMXT && fix->fix_size == 8 && mp->fix_size != 8)
+               return NULL;
+             else
+               min_mp = mp;
+           }
          else if (mp->max_address
                   < minipool_barrier->address + mp->offset + fix->fix_size)
            {
@@ -5656,6 +6560,18 @@ add_minipool_backward_ref (fix)
              min_mp = mp;
              min_address = mp->min_address + fix->fix_size;
            }
+         /* If we are inserting an 8-bytes aligned quantity and
+            we have not already found an insertion point, then
+            make sure that all such 8-byte aligned quantities are
+            placed at the start of the pool.  */
+         else if (TARGET_REALLY_IWMMXT
+                  && min_mp == NULL
+                  && fix->fix_size == 8
+                  && mp->fix_size < 8)
+           {
+             min_mp = mp;
+             min_address = mp->min_address + fix->fix_size;
+           }
        }
     }
 
@@ -5722,11 +6638,10 @@ add_minipool_backward_ref (fix)
 }
 
 static void
-assign_minipool_offsets (barrier)
-     Mfix * barrier;
+assign_minipool_offsets (Mfix *barrier)
 {
   HOST_WIDE_INT offset = 0;
-  Mnode * mp;
+  Mnode *mp;
 
   minipool_barrier = barrier;
 
@@ -5741,19 +6656,27 @@ assign_minipool_offsets (barrier)
 
 /* Output the literal table */
 static void
-dump_minipool (scan)
-     rtx scan;
+dump_minipool (rtx scan)
 {
   Mnode * mp;
   Mnode * nmp;
+  int align64 = 0;
+
+  if (TARGET_REALLY_IWMMXT)
+    for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
+      if (mp->refcount > 0 && mp->fix_size == 8)
+       {
+         align64 = 1;
+         break;
+       }
 
   if (rtl_dump_file)
     fprintf (rtl_dump_file,
-            ";; Emitting minipool after insn %u; address %ld\n",
-            INSN_UID (scan), (unsigned long) minipool_barrier->address);
+            ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
+            INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
 
   scan = emit_label_after (gen_label_rtx (), scan);
-  scan = emit_insn_after (gen_align_4 (), scan);
+  scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
   scan = emit_label_after (minipool_vector_label, scan);
 
   for (mp = minipool_vector_head; mp != NULL; mp = nmp)
@@ -5812,10 +6735,8 @@ dump_minipool (scan)
 }
 
 /* Return the cost of forcibly inserting a barrier after INSN.  */
-
 static int
-arm_barrier_cost (insn)
-     rtx insn;
+arm_barrier_cost (rtx insn)
 {
   /* Basing the location of the pool on the loop depth is preferable,
      but at the moment, the basic block information seems to be
@@ -5849,11 +6770,8 @@ arm_barrier_cost (insn)
    (FIX->address,MAX_ADDRESS) to forcibly insert a minipool barrier.
    Create the barrier by inserting a jump and add a new fix entry for
    it.  */
-
 static Mfix *
-create_fix_barrier (fix, max_address)
-     Mfix * fix;
-     HOST_WIDE_INT max_address;
+create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
 {
   HOST_WIDE_INT count = 0;
   rtx barrier;
@@ -5935,9 +6853,7 @@ create_fix_barrier (fix, max_address)
 /* Record that there is a natural barrier in the insn stream at
    ADDRESS.  */
 static void
-push_minipool_barrier (insn, address)
-     rtx insn;
-     HOST_WIDE_INT address;
+push_minipool_barrier (rtx insn, HOST_WIDE_INT address)
 {
   Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
@@ -5959,17 +6875,13 @@ push_minipool_barrier (insn, address)
    fixing; VALUE is the constant that must be loaded, which is of type
    MODE.  */
 static void
-push_minipool_fix (insn, address, loc, mode, value)
-     rtx insn;
-     HOST_WIDE_INT address;
-     rtx * loc;
-     enum machine_mode mode;
-     rtx value;
+push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
+                  enum machine_mode mode, rtx value)
 {
   Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
 #ifdef AOF_ASSEMBLER
-  /* PIC symbol refereneces need to be converted into offsets into the
+  /* PIC symbol references need to be converted into offsets into the
      based area.  */
   /* XXX This shouldn't be done here.  */
   if (flag_pic && GET_CODE (value) == SYMBOL_REF)
@@ -5992,6 +6904,13 @@ push_minipool_fix (insn, address, loc, mode, value)
   if (fix->forwards == 0 && fix->backwards == 0)
     abort ();
 
+  /* With iWMMXt enabled, the pool is aligned to an 8-byte boundary.
+     So there might be an empty word before the start of the pool.
+     Hence we reduce the forward range by 4 to allow for this
+     possibility.  */
+  if (TARGET_REALLY_IWMMXT && fix->fix_size == 8)
+    fix->forwards -= 4;
+
   if (rtl_dump_file)
     {
       fprintf (rtl_dump_file,
@@ -6014,13 +6933,15 @@ push_minipool_fix (insn, address, loc, mode, value)
   minipool_fix_tail = fix;
 }
 
-/* Scan INSN and note any of its operands that need fixing.  */
-
-static void
-note_invalid_constants (insn, address)
-     rtx insn;
-     HOST_WIDE_INT address;
+/* Scan INSN and note any of its operands that need fixing.
+   If DO_PUSHES is false we do not actually push any of the fixups
+   needed.  The function returns TRUE is any fixups were needed/pushed.
+   This is used by arm_memory_load_p() which needs to know about loads
+   of constants that will be converted into minipool loads.  */
+static bool
+note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
 {
+  bool result = false;
   int opno;
 
   extract_insn (insn);
@@ -6028,8 +6949,10 @@ note_invalid_constants (insn, address)
   if (!constrain_operands (1))
     fatal_insn_not_found (insn);
 
-  /* Fill in recog_op_alt with information about the constraints of this
-     insn.  */
+  if (recog_data.n_alternatives == 0)
+    return false;
+
+  /* Fill in recog_op_alt with information about the constraints of this insn.  */
   preprocess_constraints ();
 
   for (opno = 0; opno < recog_data.n_operands; opno++)
@@ -6047,32 +6970,47 @@ note_invalid_constants (insn, address)
          rtx op = recog_data.operand[opno];
 
          if (CONSTANT_P (op))
-           push_minipool_fix (insn, address, recog_data.operand_loc[opno],
-                              recog_data.operand_mode[opno], op);
-#if 0
-         /* RWE: Now we look correctly at the operands for the insn,
-            this shouldn't be needed any more.  */
-#ifndef AOF_ASSEMBLER
-         /* XXX Is this still needed?  */
-         else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_PIC_SYM)
-           push_minipool_fix (insn, address, recog_data.operand_loc[opno],
-                              recog_data.operand_mode[opno],
-                              XVECEXP (op, 0, 0));
-#endif
-#endif
+           {
+             if (do_pushes)
+               push_minipool_fix (insn, address, recog_data.operand_loc[opno],
+                                  recog_data.operand_mode[opno], op);
+             result = true;
+           }
          else if (GET_CODE (op) == MEM
                   && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
                   && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
-           push_minipool_fix (insn, address, recog_data.operand_loc[opno],
-                              recog_data.operand_mode[opno],
-                              get_pool_constant (XEXP (op, 0)));
+           {
+             if (do_pushes)
+               {
+                 rtx cop = avoid_constant_pool_reference (op);
+
+                 /* Casting the address of something to a mode narrower
+                    than a word can cause avoid_constant_pool_reference()
+                    to return the pool reference itself.  That's no good to
+                    us here.  Lets just hope that we can use the 
+                    constant pool value directly.  */
+                 if (op == cop)
+                   cop = get_pool_constant (XEXP (op, 0));
+
+                 push_minipool_fix (insn, address,
+                                    recog_data.operand_loc[opno],
+                                    recog_data.operand_mode[opno], cop);
+               }
+
+             result = true;
+           }
        }
     }
+
+  return result;
 }
 
-void
-arm_reorg (first)
-     rtx first;
+/* Gcc puts the pool in the wrong place for ARM, since we can only
+   load addresses a limited distance around the pc.  We do some
+   special munging to move the constant pool values to the correct
+   point in the code.  */
+static void
+arm_reorg (void)
 {
   rtx insn;
   HOST_WIDE_INT address = 0;
@@ -6082,20 +7020,26 @@ arm_reorg (first)
 
   /* The first insn must always be a note, or the code below won't
      scan it properly.  */
-  if (GET_CODE (first) != NOTE)
+  insn = get_insns ();
+  if (GET_CODE (insn) != NOTE)
     abort ();
 
   /* Scan all the insns and record the operands that will need fixing.  */
-  for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
+  for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
     {
+      if (TARGET_CIRRUS_FIX_INVALID_INSNS
+          && (arm_cirrus_insn_p (insn)
+             || GET_CODE (insn) == JUMP_INSN
+             || arm_memory_load_p (insn)))
+       cirrus_reorg (insn);
+
       if (GET_CODE (insn) == BARRIER)
        push_minipool_barrier (insn, address);
-      else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
-              || GET_CODE (insn) == JUMP_INSN)
+      else if (INSN_P (insn))
        {
          rtx table;
 
-         note_invalid_constants (insn, address);
+         note_invalid_constants (insn, address, true);
          address += get_attr_length (insn);
 
          /* If the insn is a vector jump, add the size of the table
@@ -6229,10 +7173,8 @@ arm_reorg (first)
 /* If the rtx is the correct value then return the string of the number.
    In this way we can ensure that valid double constants are generated even
    when cross compiling.  */
-
 const char *
-fp_immediate_constant (x)
-     rtx x;
+fp_immediate_constant (rtx x)
 {
   REAL_VALUE_TYPE r;
   int i;
@@ -6249,10 +7191,8 @@ fp_immediate_constant (x)
 }
 
 /* As for fp_immediate_constant, but value is passed directly, not in rtx.  */
-
 static const char *
-fp_const_from_val (r)
-     REAL_VALUE_TYPE * r;
+fp_const_from_val (REAL_VALUE_TYPE *r)
 {
   int i;
 
@@ -6270,13 +7210,8 @@ fp_const_from_val (r)
    MASK is the ARM register set mask of which only bits 0-15 are important.
    REG is the base register, either the frame pointer or the stack pointer,
    INSTR is the possibly suffixed load or store instruction.  */
-
 static void
-print_multi_reg (stream, instr, reg, mask)
-     FILE * stream;
-     const char * instr;
-     int reg;
-     int mask;
+print_multi_reg (FILE *stream, const char *instr, int reg, int mask)
 {
   int i;
   int not_first = FALSE;
@@ -6295,14 +7230,25 @@ print_multi_reg (stream, instr, reg, mask)
        not_first = TRUE;
       }
 
-  fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
+  fprintf (stream, "}");
+
+  /* Add a ^ character for the 26-bit ABI, but only if we were loading
+     the PC.  Otherwise we would generate an UNPREDICTABLE instruction.
+     Strictly speaking the instruction would be unpredicatble only if
+     we were writing back the base register as well, but since we never
+     want to generate an LDM type 2 instruction (register bank switching)
+     which is what you get if the PC is not being loaded, we do not need
+     to check for writeback.  */
+  if (! TARGET_APCS_32
+      && ((mask & (1 << PC_REGNUM)) != 0))
+    fprintf (stream, "^");
+  
+  fprintf (stream, "\n");
 }
 
 /* Output a 'call' insn.  */
-
 const char *
-output_call (operands)
-     rtx * operands;
+output_call (rtx *operands)
 {
   /* Handle calls to lr using ip (which may be clobbered in subr anyway).  */
 
@@ -6322,57 +7268,25 @@ output_call (operands)
   return "";
 }
 
-static int
-eliminate_lr2ip (x)
-     rtx * x;
-{
-  int something_changed = 0;
-  rtx x0 = * x;
-  int code = GET_CODE (x0);
-  int i, j;
-  const char * fmt;
-  
-  switch (code)
-    {
-    case REG:
-      if (REGNO (x0) == LR_REGNUM)
-        {
-         *x = gen_rtx_REG (SImode, IP_REGNUM);
-         return 1;
-        }
-      return 0;
-    default:
-      /* Scan through the sub-elements and change any references there.  */
-      fmt = GET_RTX_FORMAT (code);
-      
-      for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
-       if (fmt[i] == 'e')
-         something_changed |= eliminate_lr2ip (&XEXP (x0, i));
-       else if (fmt[i] == 'E')
-         for (j = 0; j < XVECLEN (x0, i); j++)
-           something_changed |= eliminate_lr2ip (&XVECEXP (x0, i, j));
-      
-      return something_changed;
-    }
-}
-  
 /* Output a 'call' insn that is a reference in memory.  */
-
 const char *
-output_call_mem (operands)
-     rtx * operands;
+output_call_mem (rtx *operands)
 {
-  operands[0] = copy_rtx (operands[0]); /* Be ultra careful.  */
-  /* Handle calls using lr by using ip (which may be clobbered in subr anyway).  */
-  if (eliminate_lr2ip (&operands[0]))
-    output_asm_insn ("mov%?\t%|ip, %|lr", operands);
-
   if (TARGET_INTERWORK)
     {
       output_asm_insn ("ldr%?\t%|ip, %0", operands);
       output_asm_insn ("mov%?\t%|lr, %|pc", operands);
       output_asm_insn ("bx%?\t%|ip", operands);
     }
+  else if (regno_use_in (LR_REGNUM, operands[0]))
+    {
+      /* LR is used in the memory address.  We load the address in the
+        first instruction.  It's safe to use IP as the target of the
+        load since the call will kill it anyway.  */
+      output_asm_insn ("ldr%?\t%|ip, %0", operands);
+      output_asm_insn ("mov%?\t%|lr, %|pc", operands);
+      output_asm_insn ("mov%?\t%|pc, %|ip", operands);
+    }
   else
     {
       output_asm_insn ("mov%?\t%|lr, %|pc", operands);
@@ -6383,13 +7297,11 @@ output_call_mem (operands)
 }
 
 
-/* Output a move from arm registers to an fpu registers.
-   OPERANDS[0] is an fpu register.
+/* Output a move from arm registers to an fpa registers.
+   OPERANDS[0] is an fpa register.
    OPERANDS[1] is the first registers of an arm register pair.  */
-
 const char *
-output_mov_long_double_fpu_from_arm (operands)
-     rtx * operands;
+output_mov_long_double_fpa_from_arm (rtx *operands)
 {
   int arm_reg0 = REGNO (operands[1]);
   rtx ops[3];
@@ -6407,13 +7319,11 @@ output_mov_long_double_fpu_from_arm (operands)
   return "";
 }
 
-/* Output a move from an fpu register to arm registers.
+/* Output a move from an fpa register to arm registers.
    OPERANDS[0] is the first registers of an arm register pair.
-   OPERANDS[1] is an fpu register.  */
-
+   OPERANDS[1] is an fpa register.  */
 const char *
-output_mov_long_double_arm_from_fpu (operands)
-     rtx * operands;
+output_mov_long_double_arm_from_fpa (rtx *operands)
 {
   int arm_reg0 = REGNO (operands[0]);
   rtx ops[3];
@@ -6433,10 +7343,8 @@ output_mov_long_double_arm_from_fpu (operands)
 /* Output a move from arm registers to arm registers of a long double
    OPERANDS[0] is the destination.
    OPERANDS[1] is the source.  */
-
 const char *
-output_mov_long_double_arm_from_arm (operands)
-     rtx * operands;
+output_mov_long_double_arm_from_arm (rtx *operands)
 {
   /* We have to be careful here because the two might overlap.  */
   int dest_start = REGNO (operands[0]);
@@ -6467,13 +7375,11 @@ output_mov_long_double_arm_from_arm (operands)
 }
 
 
-/* Output a move from arm registers to an fpu registers.
-   OPERANDS[0] is an fpu register.
+/* Output a move from arm registers to an fpa registers.
+   OPERANDS[0] is an fpa register.
    OPERANDS[1] is the first registers of an arm register pair.  */
-
 const char *
-output_mov_double_fpu_from_arm (operands)
-     rtx * operands;
+output_mov_double_fpa_from_arm (rtx *operands)
 {
   int arm_reg0 = REGNO (operands[1]);
   rtx ops[2];
@@ -6488,13 +7394,11 @@ output_mov_double_fpu_from_arm (operands)
   return "";
 }
 
-/* Output a move from an fpu register to arm registers.
+/* Output a move from an fpa register to arm registers.
    OPERANDS[0] is the first registers of an arm register pair.
-   OPERANDS[1] is an fpu register.  */
-
+   OPERANDS[1] is an fpa register.  */
 const char *
-output_mov_double_arm_from_fpu (operands)
-     rtx * operands;
+output_mov_double_arm_from_fpa (rtx *operands)
 {
   int arm_reg0 = REGNO (operands[0]);
   rtx ops[2];
@@ -6512,10 +7416,8 @@ output_mov_double_arm_from_fpu (operands)
 /* 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.  */
-
 const char *
-output_move_double (operands)
-     rtx * operands;
+output_move_double (rtx *operands)
 {
   enum rtx_code code0 = GET_CODE (operands[0]);
   enum rtx_code code1 = GET_CODE (operands[1]);
@@ -6539,6 +7441,105 @@ output_move_double (operands)
          else
            output_asm_insn ("mov%?\t%R0, %R1\n\tmov%?\t%Q0, %Q1", operands);
        }
+      else if (code1 == CONST_VECTOR)
+       {
+         HOST_WIDE_INT hint = 0;
+
+         switch (GET_MODE (operands[1]))
+           {
+           case V2SImode:
+             otherops[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 1)));
+             operands[1] = GEN_INT (INTVAL (CONST_VECTOR_ELT (operands[1], 0)));
+             break;
+
+           case V4HImode:
+             if (BYTES_BIG_ENDIAN)
+               {
+                 hint = INTVAL (CONST_VECTOR_ELT (operands[1], 2));
+                 hint <<= 16;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
+               }
+             else
+               {
+                 hint = INTVAL (CONST_VECTOR_ELT (operands[1], 3));
+                 hint <<= 16;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
+               }
+
+             otherops[1] = GEN_INT (hint);
+             hint = 0;
+
+             if (BYTES_BIG_ENDIAN)
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
+                 hint <<= 16;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
+               }
+             else
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
+                 hint <<= 16;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
+               }
+
+             operands[1] = GEN_INT (hint);
+             break;
+
+           case V8QImode:
+             if (BYTES_BIG_ENDIAN)
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
+               }
+             else
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 7));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 6));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 5));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 4));
+               }
+
+             otherops[1] = GEN_INT (hint);
+             hint = 0;
+
+             if (BYTES_BIG_ENDIAN)
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
+               }
+             else
+               {
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 3));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 2));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 1));
+                 hint <<= 8;
+                 hint |= INTVAL (CONST_VECTOR_ELT (operands[1], 0));
+               }
+
+             operands[1] = GEN_INT (hint);
+             break;
+             
+           default:
+             abort ();
+           }
+         output_mov_immediate (operands);
+         output_mov_immediate (otherops);
+       }
       else if (code1 == CONST_DOUBLE)
        {
          if (GET_MODE (operands[1]) == DFmode)
@@ -6638,7 +7639,7 @@ output_move_double (operands)
                    {
                      if (GET_CODE (otherops[2]) == CONST_INT)
                        {
-                         switch (INTVAL (otherops[2]))
+                         switch ((int) INTVAL (otherops[2]))
                            {
                            case -8:
                              output_asm_insn ("ldm%?db\t%1, %M0", otherops);
@@ -6666,7 +7667,7 @@ output_move_double (operands)
                 }
               else
                 {
-                 otherops[1] = adjust_address (operands[1], VOIDmode, 4);
+                 otherops[1] = adjust_address (operands[1], SImode, 4);
                  /* Take care of overlapping base/data reg.  */
                  if (reg_mentioned_p (operands[0], operands[1]))
                    {
@@ -6714,7 +7715,7 @@ output_move_double (operands)
        case PLUS:
          if (GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == CONST_INT)
            {
-             switch (INTVAL (XEXP (XEXP (operands[0], 0), 1)))
+             switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
                {
                case -8:
                  output_asm_insn ("stm%?db\t%m0, %M1", operands);
@@ -6732,7 +7733,7 @@ output_move_double (operands)
          /* Fall through */
 
         default:
-         otherops[0] = adjust_address (operands[0], VOIDmode, 4);
+         otherops[0] = adjust_address (operands[0], SImode, 4);
          otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
          output_asm_insn ("str%?\t%1, %0", operands);
          output_asm_insn ("str%?\t%1, %0", otherops);
@@ -6748,10 +7749,8 @@ output_move_double (operands)
 
 /* Output an arbitrary MOV reg, #n.
    OPERANDS[0] is a register.  OPERANDS[1] is a const_int.  */
-
 const char *
-output_mov_immediate (operands)
-     rtx * operands;
+output_mov_immediate (rtx *operands)
 {
   HOST_WIDE_INT n = INTVAL (operands[1]);
 
@@ -6771,9 +7770,9 @@ output_mov_immediate (operands)
       int i;
 
       /* If all else fails, make it out of ORRs or BICs as appropriate.  */
-      for (i = 0; i < 32; i ++)
+      for (i = 0; i < 32; i++)
        if (n & 1 << i)
-         n_ones ++;
+         n_ones++;
 
       if (n_ones > 16)  /* Shorter to use MVN with BIC in this case.  */
        output_multi_immediate (operands, "mvn%?\t%0, %1", "bic%?\t%0, %0, %1", 1, ~ n);
@@ -6786,10 +7785,8 @@ output_mov_immediate (operands)
 
 /* 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 *
-output_add_immediate (operands)
-     rtx * operands;
+output_add_immediate (rtx *operands)
 {
   HOST_WIDE_INT n = INTVAL (operands[2]);
 
@@ -6814,14 +7811,9 @@ output_add_immediate (operands)
    INSTR2 is the output pattern to use for subsequent constants.
    IMMED_OP is the index of the constant slot in OPERANDS.
    N is the constant value.  */
-
 static const char *
-output_multi_immediate (operands, instr1, instr2, immed_op, n)
-     rtx * operands;
-     const char * instr1;
-     const char * instr2;
-     int immed_op;
-     HOST_WIDE_INT n;
+output_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
+                       int immed_op, HOST_WIDE_INT n)
 {
 #if HOST_BITS_PER_WIDE_INT > 32
   n &= 0xffffffff;
@@ -6858,11 +7850,8 @@ output_multi_immediate (operands, instr1, instr2, immed_op, n)
    The returned result should not be overwritten.  OP is the rtx of the
    operation.  SHIFT_FIRST_ARG is TRUE if the first argument of the operator
    was shifted.  */
-
 const char *
-arithmetic_instr (op, shift_first_arg)
-     rtx op;
-     int shift_first_arg;
+arithmetic_instr (rtx op, int shift_first_arg)
 {
   switch (GET_CODE (op))
     {
@@ -6891,11 +7880,8 @@ arithmetic_instr (op, shift_first_arg)
    OP is the rtx code of the shift.
    On exit, *AMOUNTP will be -1 if the shift is by a register, or a constant
    shift.  */
-
 static const char *
-shift_op (op, amountp)
-     rtx op;
-     HOST_WIDE_INT *amountp;
+shift_op (rtx op, HOST_WIDE_INT *amountp)
 {
   const char * mnem;
   enum rtx_code code = GET_CODE (op);
@@ -6968,8 +7954,7 @@ shift_op (op, amountp)
 /* Obtain the shift from the POWER of two.  */
 
 static HOST_WIDE_INT
-int_log2 (power)
-     HOST_WIDE_INT power;
+int_log2 (HOST_WIDE_INT power)
 {
   HOST_WIDE_INT shift = 0;
 
@@ -6977,7 +7962,7 @@ int_log2 (power)
     {
       if (shift > 31)
        abort ();
-      shift ++;
+      shift++;
     }
 
   return shift;
@@ -6988,10 +7973,7 @@ int_log2 (power)
 #define MAX_ASCII_LEN 51
 
 void
-output_ascii_pseudo_op (stream, p, len)
-     FILE * stream;
-     const unsigned char * p;
-     int len;
+output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
 {
   int i;
   int len_so_far = 0;
@@ -7068,9 +8050,8 @@ output_ascii_pseudo_op (stream, p, len)
 /* Compute the register sabe mask for registers 0 through 12
    inclusive.  This code is used by both arm_compute_save_reg_mask
    and arm_compute_initial_elimination_offset.  */
-
 static unsigned long
-arm_compute_save_reg0_reg12_mask ()
+arm_compute_save_reg0_reg12_mask (void)
 {
   unsigned long func_type = arm_current_func_type ();
   unsigned int save_reg_mask = 0;
@@ -7130,7 +8111,7 @@ arm_compute_save_reg0_reg12_mask ()
    saved on the stack for the current function.  */
 
 static unsigned long
-arm_compute_save_reg_mask ()
+arm_compute_save_reg_mask (void)
 {
   unsigned int save_reg_mask = 0;
   unsigned long func_type = arm_current_func_type ();
@@ -7162,7 +8143,7 @@ arm_compute_save_reg_mask ()
      it.  If we are pushing other registers onto the stack however, we
      can save an instruction in the epilogue by pushing the link register
      now and then popping it back into the PC.  This incurs extra memory
-     accesses though, so we only do it when optimising for size, and only
+     accesses though, so we only do it when optimizing for size, and only
      if we know that we will not need a fancy return sequence.  */
   if (regs_ever_live [LR_REGNUM]
          || (save_reg_mask
@@ -7173,24 +8154,48 @@ arm_compute_save_reg_mask ()
   if (cfun->machine->lr_save_eliminated)
     save_reg_mask &= ~ (1 << LR_REGNUM);
 
+  if (TARGET_REALLY_IWMMXT
+      && ((bit_count (save_reg_mask)
+          + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
+    {
+      unsigned int reg;
+
+      /* The total number of registers that are going to be pushed
+        onto the stack is odd.  We need to ensure that the stack
+        is 64-bit aligned before we start to save iWMMXt registers,
+        and also before we start to create locals.  (A local variable
+        might be a double or long long which we will load/store using
+        an iWMMXt instruction).  Therefore we need to push another
+        ARM register, so that the stack will be 64-bit aligned.  We
+        try to avoid using the arg registers (r0 -r3) as they might be
+        used to pass values in a tail call.  */
+      for (reg = 4; reg <= 12; reg++)
+       if ((save_reg_mask & (1 << reg)) == 0)
+         break;
+
+      if (reg <= 12)
+       save_reg_mask |= (1 << reg);
+      else
+       {
+         cfun->machine->sibcall_blocked = 1;
+         save_reg_mask |= (1 << 3);
+       }
+    }
+
   return save_reg_mask;
 }
 
-/* Generate a function exit sequence.  If REALLY_RETURN is true, then do
+/* Generate a function exit sequence.  If REALLY_RETURN is false, then do
    everything bar the final return instruction.  */
-
 const char *
-output_return_instruction (operand, really_return, reverse)
-     rtx operand;
-     int really_return;
-     int reverse;
+output_return_instruction (rtx operand, int really_return, int reverse)
 {
   char conditional[10];
   char instr[100];
   int reg;
   unsigned long live_regs_mask;
   unsigned long func_type;
-  
+
   func_type = arm_current_func_type ();
 
   if (IS_NAKED (func_type))
@@ -7198,8 +8203,9 @@ output_return_instruction (operand, really_return, reverse)
 
   if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
     {
-      /* If this function was declared non-returning, and we have found a tail 
-        call, then we have to trust that the called function won't return.  */
+      /* If this function was declared non-returning, and we have
+        found a tail call, then we have to trust that the called
+        function won't return.  */
       if (really_return)
        {
          rtx ops[2];
@@ -7271,9 +8277,29 @@ output_return_instruction (operand, really_return, reverse)
          char *p;
          int first = 1;
 
-         /* Generate the load multiple instruction to restore the registers.  */
-         if (frame_pointer_needed)
-           sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
+         /* Generate the load multiple instruction to restore the
+            registers.  Note we can get here, even if
+            frame_pointer_needed is true, but only if sp already
+            points to the base of the saved core registers.  */
+         if (live_regs_mask & (1 << SP_REGNUM))
+           {
+             unsigned HOST_WIDE_INT stack_adjust =
+               arm_get_frame_size () + current_function_outgoing_args_size;
+             
+             if (stack_adjust != 0 && stack_adjust != 4)
+               abort ();
+
+             if (stack_adjust && arm_arch5)
+               sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
+             else
+               {
+                 /* If we can't use ldmib (SA110 bug), then try to pop r3
+                    instead.  */
+                 if (stack_adjust)
+                   live_regs_mask |= 1 << 3;
+                 sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
+               }
+           }
          else
            sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
 
@@ -7299,20 +8325,22 @@ output_return_instruction (operand, really_return, reverse)
          
          if (live_regs_mask & (1 << LR_REGNUM))
            {
-             int l = strlen (return_reg);
-
-             if (! first)
-               {
-                 memcpy (p, ", ", 2);
-                 p += 2;
-               }
-
-             memcpy (p, "%|", 2);
-             memcpy (p + 2, return_reg, l);
-             strcpy (p + 2 + l, ((TARGET_APCS_32 
-                                  && !IS_INTERRUPT (func_type)) 
-                                 || !really_return) 
-                     ? "}" : "}^");
+             sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
+             /* Decide if we need to add the ^ symbol to the end of the
+                register list.  This causes the saved condition codes
+                register to be copied into the current condition codes
+                register.  We do the copy if we are conforming to the 32-bit
+                ABI and this is an interrupt function, or if we are
+                conforming to the 26-bit ABI.  There is a special case for
+                the 26-bit ABI however, which is if we are writing back the
+                stack pointer but not loading the PC.  In this case adding
+                the ^ symbol would create a type 2 LDM instruction, where
+                writeback is UNPREDICTABLE.  We are safe in leaving the ^
+                character off in this case however, since the actual return
+                instruction will be a MOVS which will restore the CPSR.  */
+             if ((TARGET_APCS_32 && IS_INTERRUPT (func_type))
+                 || (! TARGET_APCS_32 && really_return))
+               strcat (p, "^");
            }
          else
            strcpy (p, "}");
@@ -7331,7 +8359,7 @@ output_return_instruction (operand, really_return, reverse)
          really_return = 0;
        }
     }
-  
+
   if (really_return)
     {
       switch ((int) ARM_FUNC_TYPE (func_type))
@@ -7392,18 +8420,15 @@ output_return_instruction (operand, really_return, reverse)
    a leaf function.  These function types will not contain a stack
    backtrace structure, therefore it is not possible to determine the
    function name.  */
-
 void
-arm_poke_function_name (stream, name)
-   FILE * stream;
-   const char * name;
+arm_poke_function_name (FILE *stream, const char *name)
 {
   unsigned long alignlength;
   unsigned long length;
   rtx           x;
 
   length      = strlen (name) + 1;
-  alignlength = ROUND_UP (length);
+  alignlength = ROUND_UP_WORD (length);
   
   ASM_OUTPUT_ASCII (stream, name, length);
   ASM_OUTPUT_ALIGN (stream, 2);
@@ -7413,11 +8438,8 @@ arm_poke_function_name (stream, name)
 
 /* Place some comments into the assembler stream
    describing the current function.  */
-
 static void
-arm_output_function_prologue (f, frame_size)
-     FILE * f;
-     HOST_WIDE_INT frame_size;
+arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
@@ -7464,7 +8486,7 @@ arm_output_function_prologue (f, frame_size)
   if (IS_NESTED (func_type))
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
     
-  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
+  asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
               current_function_args_size,
               current_function_pretend_args_size, frame_size);
 
@@ -7484,8 +8506,7 @@ arm_output_function_prologue (f, frame_size)
 }
 
 const char *
-arm_output_epilogue (really_return)
-     int really_return;
+arm_output_epilogue (rtx sibling)
 {
   int reg;
   unsigned long saved_regs_mask;
@@ -7494,13 +8515,15 @@ arm_output_epilogue (really_return)
      frame that is $fp + 4 for a non-variadic function.  */
   int floats_offset = 0;
   rtx operands[3];
-  int frame_size = get_frame_size ();
+  int frame_size = arm_get_frame_size ();
   FILE * f = asm_out_file;
   rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
+  unsigned int lrm_count = 0;
+  int really_return = (sibling == NULL);
 
   /* If we have already generated the return instruction
      then it is futile to generate anything else.  */
-  if (use_return_insn (FALSE) && return_used_this_function)
+  if (use_return_insn (FALSE, sibling) && return_used_this_function)
     return "";
 
   func_type = arm_current_func_type ();
@@ -7528,12 +8551,15 @@ arm_output_epilogue (really_return)
     abort ();
   
   saved_regs_mask = arm_compute_save_reg_mask ();
-  
+
+  if (TARGET_IWMMXT)
+    lrm_count = bit_count (saved_regs_mask);
+
   /* XXX We should adjust floats_offset for any anonymous args, and then
      re-adjust vfp_offset below to compensate.  */
 
   /* Compute how far away the floats will be.  */
-  for (reg = 0; reg <= LAST_ARM_REGNUM; reg ++)
+  for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
     if (saved_regs_mask & (1 << reg))
       floats_offset += 4;
   
@@ -7541,7 +8567,7 @@ arm_output_epilogue (really_return)
     {
       int vfp_offset = 4;
 
-      if (arm_fpu_arch == FP_SOFT2)
+      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
        {
          for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
            if (regs_ever_live[reg] && !call_used_regs[reg])
@@ -7586,6 +8612,26 @@ arm_output_epilogue (really_return)
                         FP_REGNUM, floats_offset - vfp_offset);
        }
 
+      if (TARGET_IWMMXT)
+       {
+         /* The frame pointer is guaranteed to be non-double-word aligned.
+            This is because it is set to (old_stack_pointer - 4) and the
+            old_stack_pointer was double word aligned.  Thus the offset to
+            the iWMMXt registers to be loaded must also be non-double-word
+            sized, so that the resultant address *is* double-word aligned.
+            We can ignore floats_offset since that was already included in
+            the live_regs_mask.  */
+         lrm_count += (lrm_count % 2 ? 2 : 1);
+             
+         for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+           if (regs_ever_live[reg] && !call_used_regs[reg])
+             {
+               asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n", 
+                            reg, FP_REGNUM, lrm_count * 4);
+               lrm_count += 2; 
+             }
+       }
+
       /* saved_regs_mask should contain the IP, which at the time of stack
         frame generation actually contains the old stack pointer.  So a
         quick way to unwind the stack is just pop the IP register directly
@@ -7605,13 +8651,27 @@ arm_output_epilogue (really_return)
        saved_regs_mask &= ~ (1 << LR_REGNUM);
       else
        saved_regs_mask &= ~ (1 << PC_REGNUM);
-      
-      print_multi_reg (f, "ldmea\t%r", FP_REGNUM, saved_regs_mask);
+
+      /* We must use SP as the base register, because SP is one of the
+         registers being restored.  If an interrupt or page fault
+         happens in the ldm instruction, the SP might or might not
+         have been restored.  That would be bad, as then SP will no
+         longer indicate the safe area of stack, and we can get stack
+         corruption.  Using SP as the base register means that it will
+         be reset correctly to the original value, should an interrupt
+         occur.  If the stack pointer already points at the right
+         place, then omit the subtraction.  */
+      if (((frame_size + current_function_outgoing_args_size + floats_offset)
+          != 4 * (1 + (int) bit_count (saved_regs_mask)))
+         || current_function_calls_alloca)
+       asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
+                    4 * bit_count (saved_regs_mask));
+      print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
 
       if (IS_INTERRUPT (func_type))
        /* Interrupt handlers will have pushed the
           IP onto the stack, so restore it now.  */
-       print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, 1 << IP_REGNUM);
+       print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
     }
   else
     {
@@ -7624,7 +8684,7 @@ arm_output_epilogue (really_return)
          output_add_immediate (operands);
        }
 
-      if (arm_fpu_arch == FP_SOFT2)
+      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
        {
          for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
            if (regs_ever_live[reg] && !call_used_regs[reg])
@@ -7663,6 +8723,11 @@ arm_output_epilogue (really_return)
                         start_reg, reg - start_reg, SP_REGNUM);
        }
 
+      if (TARGET_IWMMXT)
+       for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+         if (regs_ever_live[reg] && !call_used_regs[reg])
+           asm_fprintf (f, "\twldrd\t%r, [%r, #+8]!\n", reg, SP_REGNUM);
+
       /* If we can, restore the LR into the PC.  */
       if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
          && really_return
@@ -7685,7 +8750,16 @@ arm_output_epilogue (really_return)
            asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
        }
       else if (saved_regs_mask)
-       print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+       {
+         if (saved_regs_mask & (1 << SP_REGNUM))
+           /* Note - write back to the stack register is not enabled
+              (ie "ldmfd sp!...").  We know that the stack pointer is
+              in the list of registers and if we add writeback the
+              instruction becomes UNPREDICTABLE.  */
+           print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
+         else
+           print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+       }
 
       if (current_function_pretend_args_size)
        {
@@ -7696,13 +8770,6 @@ arm_output_epilogue (really_return)
        }
     }
 
-#if 0
-  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER)
-    /* Adjust the stack to remove the exception handler stuff.  */
-    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                REGNO (eh_ofs));
-#endif
-
   if (! really_return
     || (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
        && current_function_pretend_args_size == 0
@@ -7733,7 +8800,7 @@ arm_output_epilogue (really_return)
 
     default:
       if (frame_pointer_needed)
-       /* If we used the frame pointer then the return adddress
+       /* If we used the frame pointer then the return address
           will have been loaded off the stack directly into the
           PC, so there is no need to issue a MOV instruction
           here.  */
@@ -7754,9 +8821,8 @@ arm_output_epilogue (really_return)
 }
 
 static void
-arm_output_function_epilogue (file, frame_size)
-     FILE *file ATTRIBUTE_UNUSED;
-     HOST_WIDE_INT frame_size;
+arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
+                             HOST_WIDE_INT frame_size)
 {
   if (TARGET_THUMB)
     {
@@ -7767,7 +8833,10 @@ arm_output_function_epilogue (file, frame_size)
     }
   else
     {
-      if (use_return_insn (FALSE)
+      /* We need to take into account any stack-frame rounding.  */
+      frame_size = arm_get_frame_size ();
+
+      if (use_return_insn (FALSE, NULL)
          && return_used_this_function
          && (frame_size + current_function_outgoing_args_size) != 0
          && !frame_pointer_needed)
@@ -7782,10 +8851,8 @@ arm_output_function_epilogue (file, frame_size)
    Unfortunately, since this insn does not reflect very well the actual
    semantics of the operation, we need to annotate the insn for the benefit
    of DWARF2 frame unwind information.  */
-
 static rtx
-emit_multi_reg_push (mask)
-     int mask;
+emit_multi_reg_push (int mask)
 {
   int num_regs = 0;
   int num_dwarf_regs;
@@ -7808,7 +8875,7 @@ emit_multi_reg_push (mask)
     num_dwarf_regs--;
 
   /* For the body of the insn we are going to generate an UNSPEC in
-     parallel with several USEs.  This allows the insn to be recognised
+     parallel with several USEs.  This allows the insn to be recognized
      by the push_multi pattern in the arm.md file.  The insn looks
      something like this:
 
@@ -7911,9 +8978,7 @@ emit_multi_reg_push (mask)
 }
 
 static rtx
-emit_sfm (base_reg, count)
-     int base_reg;
-     int count;
+emit_sfm (int base_reg, int count)
 {
   rtx par;
   rtx dwarf;
@@ -7993,23 +9058,20 @@ emit_sfm (base_reg, count)
    current stack pointer -> |    | /
                               --
 
-  For a given funciton some or all of these stack compomnents
+  For a given function some or all of these stack components
   may not be needed, giving rise to the possibility of
   eliminating some of the registers.
 
-  The values returned by this function must reflect the behaviour
+  The values returned by this function must reflect the behavior
   of arm_expand_prologue() and arm_compute_save_reg_mask().
 
   The sign of the number returned reflects the direction of stack
   growth, so the values are positive for all eliminations except
   from the soft frame pointer to the hard frame pointer.  */
-                           
 unsigned int
-arm_compute_initial_elimination_offset (from, to)
-     unsigned int from;
-     unsigned int to;
+arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
 {
-  unsigned int local_vars    = (get_frame_size () + 3) & ~3;
+  unsigned int local_vars    = arm_get_frame_size ();
   unsigned int outgoing_args = current_function_outgoing_args_size;
   unsigned int stack_frame;
   unsigned int call_saved_registers;
@@ -8027,30 +9089,32 @@ arm_compute_initial_elimination_offset (from, to)
 
       /* Make sure that we compute which registers will be saved
         on the stack using the same algorithm that is used by
-        arm_compute_save_reg_mask().  */
-      reg_mask = arm_compute_save_reg0_reg12_mask ();
+        the prologue creation code.  */
+      reg_mask = arm_compute_save_reg_mask ();
 
       /* Now count the number of bits set in save_reg_mask.
-        For each set bit we need 4 bytes of stack space.  */
-      while (reg_mask)
-       {
-         call_saved_registers += 4;
-         reg_mask = reg_mask & ~ (reg_mask & - reg_mask);
-       }
-
-      if (regs_ever_live[LR_REGNUM]
-         /* If a stack frame is going to be created, the LR will
-            be saved as part of that, so we do not need to allow
-            for it here.  */
-         && ! frame_pointer_needed)
-       call_saved_registers += 4;
+        If we have already counted the registers in the stack
+        frame, do not count them again.  Non call-saved registers
+        might be saved in the call-save area of the stack, if
+        doing so will preserve the stack's alignment.  Hence we
+        must count them here.  For each set bit we need 4 bytes
+        of stack space.  */
+      if (frame_pointer_needed)
+       reg_mask &= 0x07ff;
+      call_saved_registers += 4 * bit_count (reg_mask);
 
       /* If the hard floating point registers are going to be
         used then they must be saved on the stack as well.
          Each register occupies 12 bytes of stack space.  */
-      for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg ++)
+      for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
        if (regs_ever_live[reg] && ! call_used_regs[reg])
          call_saved_registers += 12;
+
+      if (TARGET_REALLY_IWMMXT)
+       /* Check for the call-saved iWMMXt registers.  */
+       for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+         if (regs_ever_live[reg] && ! call_used_regs [reg])
+           call_saved_registers += 8;
     }
 
   /* The stack frame contains 4 registers - the old frame pointer,
@@ -8130,10 +9194,89 @@ arm_compute_initial_elimination_offset (from, to)
     }
 }
 
-/* Generate the prologue instructions for entry into an ARM function.  */
+/* Calculate the size of the stack frame, taking into account any
+   padding that is required to ensure stack-alignment.  */
+HOST_WIDE_INT
+arm_get_frame_size (void)
+{
+  int regno;
+
+  int base_size = ROUND_UP_WORD (get_frame_size ());
+  int entry_size = 0;
+  unsigned long func_type = arm_current_func_type ();
+  int leaf;
+
+  if (! TARGET_ARM)
+    abort();
+
+  if (! TARGET_ATPCS)
+    return base_size;
+
+  /* We need to know if we are a leaf function.  Unfortunately, it
+     is possible to be called after start_sequence has been called,
+     which causes get_insns to return the insns for the sequence,
+     not the function, which will cause leaf_function_p to return
+     the incorrect result.
+
+     To work around this, we cache the computed frame size.  This
+     works because we will only be calling RTL expanders that need
+     to know about leaf functions once reload has completed, and the
+     frame size cannot be changed after that time, so we can safely
+     use the cached value.  */
+
+  if (reload_completed)
+    return cfun->machine->frame_size;
+
+  leaf = leaf_function_p ();
+
+  /* A leaf function does not need any stack alignment if it has nothing
+     on the stack.  */
+  if (leaf && base_size == 0)
+    {
+      cfun->machine->frame_size = 0;
+      return 0;
+    }
+
+  /* We know that SP will be word aligned on entry, and we must
+     preserve that condition at any subroutine call.  But those are
+     the only constraints.  */
+
+  /* Space for variadic functions.  */
+  if (current_function_pretend_args_size)
+    entry_size += current_function_pretend_args_size;
+
+  /* Space for saved registers.  */
+  entry_size += bit_count (arm_compute_save_reg_mask ()) * 4;
+
+  /* Space for saved FPA registers.  */
+  if (! IS_VOLATILE (func_type))
+    {
+      for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
+      if (regs_ever_live[regno] && ! call_used_regs[regno])
+       entry_size += 12;
+    }
+
+  if (TARGET_REALLY_IWMMXT)
+    {
+      /* Check for the call-saved iWMMXt registers.  */
+      for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
+       if (regs_ever_live [regno] && ! call_used_regs [regno])
+         entry_size += 8;
+    }
+
+  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
+    base_size += 4;
+  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
+    abort ();
 
+  cfun->machine->frame_size = base_size;
+
+  return base_size;
+}
+
+/* Generate the prologue instructions for entry into an ARM function.  */
 void
-arm_expand_prologue ()
+arm_expand_prologue (void)
 {
   int reg;
   rtx amount;
@@ -8272,18 +9415,19 @@ arm_expand_prologue ()
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  /* If this is an interrupt service routine, and the link register is
-     going to be pushed, subtracting four now will mean that the
-     function return can be done with a single instruction.  */
+  /* If this is an interrupt service routine, and the link register
+     is going to be pushed, and we are not creating a stack frame,
+     (which would involve an extra push of IP and a pop in the epilogue)
+     subtracting four from LR now will mean that the function return
+     can be done with a single instruction.  */
   if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
-      && (live_regs_mask & (1 << LR_REGNUM)) != 0)
-    {
-      emit_insn (gen_rtx_SET (SImode, 
-                             gen_rtx_REG (SImode, LR_REGNUM),
-                             gen_rtx_PLUS (SImode,
-                                   gen_rtx_REG (SImode, LR_REGNUM),
-                                   GEN_INT (-4))));
-    }
+      && (live_regs_mask & (1 << LR_REGNUM)) != 0
+      && ! frame_pointer_needed)
+    emit_insn (gen_rtx_SET (SImode, 
+                           gen_rtx_REG (SImode, LR_REGNUM),
+                           gen_rtx_PLUS (SImode,
+                                         gen_rtx_REG (SImode, LR_REGNUM),
+                                         GEN_INT (-4))));
 
   if (live_regs_mask)
     {
@@ -8291,12 +9435,24 @@ arm_expand_prologue ()
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
+  if (TARGET_IWMMXT)
+    for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
+      if (regs_ever_live[reg] && ! call_used_regs [reg])
+       {
+         insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
+         insn = gen_rtx_MEM (V2SImode, insn);
+         insn = emit_insn (gen_rtx_SET (VOIDmode, insn,
+                                        gen_rtx_REG (V2SImode, reg)));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+
   if (! IS_VOLATILE (func_type))
     {
-      /* Save any floating point call-saved registers used by this function.  */
-      if (arm_fpu_arch == FP_SOFT2)
+      /* Save any floating point call-saved registers used by this
+        function.  */
+      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
        {
-         for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
+         for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
            if (regs_ever_live[reg] && !call_used_regs[reg])
              {
                insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
@@ -8310,7 +9466,7 @@ arm_expand_prologue ()
        {
          int start_reg = LAST_ARM_FP_REGNUM;
 
-         for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
+         for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
            {
              if (regs_ever_live[reg] && !call_used_regs[reg])
                {
@@ -8355,7 +9511,8 @@ arm_expand_prologue ()
            insn = gen_rtx_REG (SImode, 3);
          else /* if (current_function_pretend_args_size == 0) */
            {
-             insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
+             insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx,
+                                  GEN_INT (4));
              insn = gen_rtx_MEM (SImode, insn);
            }
 
@@ -8365,7 +9522,7 @@ arm_expand_prologue ()
        }
     }
 
-  amount = GEN_INT (-(get_frame_size ()
+  amount = GEN_INT (-(arm_get_frame_size ()
                      + current_function_outgoing_args_size));
 
   if (amount != const0_rtx)
@@ -8418,12 +9575,8 @@ arm_expand_prologue ()
    before output.
    If CODE is 'B' then output a bitwise inverted value of X (a const int).
    If X is a REG and CODE is `M', output a ldm/stm style multi-reg.  */
-
 void
-arm_print_operand (stream, x, code)
-     FILE * stream;
-     rtx x;
-     int code;
+arm_print_operand (FILE *stream, rtx x, int code)
 {
   switch (code)
     {
@@ -8486,6 +9639,16 @@ arm_print_operand (stream, x, code)
       fprintf (stream, "%s", arithmetic_instr (x, 1));
       return;
 
+    /* Truncate Cirrus shift counts.  */
+    case 's':
+      if (GET_CODE (x) == CONST_INT)
+       {
+         fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
+         return;
+       }
+      arm_print_operand (stream, x, 0);
+      return;
+
     case 'I':
       fprintf (stream, "%s", arithmetic_instr (x, 0));
       return;
@@ -8501,10 +9664,7 @@ arm_print_operand (stream, x, code)
            if (val == -1)
              arm_print_operand (stream, XEXP (x, 1), 0);
            else
-             {
-               fputc ('#', stream);
-               fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
-             }
+             fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
          }
       }
       return;
@@ -8513,13 +9673,13 @@ arm_print_operand (stream, x, code)
         
         In a pair of registers containing a DI or DF value the 'Q'
         operand returns the register number of the register containing
-        the least signficant part of the value.  The 'R' operand returns
+        the least significant part of the value.  The 'R' operand returns
         the register number of the register containing the most
         significant part of the value.
         
         The 'H' operand returns the higher of the two register numbers.
         On a run where WORDS_BIG_ENDIAN is true the 'H' operand is the
-        same as the 'Q' operand, since the most signficant part of the
+        same as the 'Q' operand, since the most significant part of the
         value is held in the lower number register.  The reverse is true
         on systems where WORDS_BIG_ENDIAN is false.
         
@@ -8563,7 +9723,7 @@ arm_print_operand (stream, x, code)
     case 'M':
       asm_fprintf (stream, "{%r-%r}",
                   REGNO (x),
-                  REGNO (x) + NUM_REGS (GET_MODE (x)) - 1);
+                  REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
       return;
 
     case 'd':
@@ -8571,11 +9731,8 @@ arm_print_operand (stream, x, code)
       if (x == const_true_rtx)
        return;
       
-      if (TARGET_ARM)
-        fputs (arm_condition_codes[get_arm_condition_code (x)],
-              stream);
-      else
-       fputs (thumb_condition_code (x, 0), stream);
+      fputs (arm_condition_codes[get_arm_condition_code (x)],
+            stream);
       return;
 
     case 'D':
@@ -8584,12 +9741,76 @@ arm_print_operand (stream, x, code)
       if (x == const_true_rtx)
        abort ();
 
-      if (TARGET_ARM)
-       fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
-                                 (get_arm_condition_code (x))],
-              stream);
+      fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
+                                (get_arm_condition_code (x))],
+            stream);
+      return;
+
+    /* Cirrus registers can be accessed in a variety of ways:
+         single floating point (f)
+        double floating point (d)
+        32bit integer         (fx)
+        64bit integer         (dx).  */
+    case 'W':                  /* Cirrus register in F mode.  */
+    case 'X':                  /* Cirrus register in D mode.  */
+    case 'Y':                  /* Cirrus register in FX mode.  */
+    case 'Z':                  /* Cirrus register in DX mode.  */
+      if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+       abort ();
+
+      fprintf (stream, "mv%s%s",
+              code == 'W' ? "f"
+              : code == 'X' ? "d"
+              : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
+
+      return;
+
+    /* Print cirrus register in the mode specified by the register's mode.  */
+    case 'V':
+      {
+       int mode = GET_MODE (x);
+
+       if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
+         abort ();
+
+       fprintf (stream, "mv%s%s",
+                mode == DFmode ? "d"
+                : mode == SImode ? "fx"
+                : mode == DImode ? "dx"
+                : "f", reg_names[REGNO (x)] + 2);
+
+       return;
+      }
+
+    case 'U':
+      if (GET_CODE (x) != REG
+         || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
+         || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
+       /* Bad value for wCG register number.  */
+       abort ();
+      else
+       fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
+      return;
+
+      /* Print an iWMMXt control register name.  */
+    case 'w':
+      if (GET_CODE (x) != CONST_INT
+         || INTVAL (x) < 0
+         || INTVAL (x) >= 16)
+       /* Bad value for wC register number.  */
+       abort ();
       else
-       fputs (thumb_condition_code (x, 1), stream);
+       {
+         static const char * wc_reg_names [16] =
+           {
+             "wCID",  "wCon",  "wCSSF", "wCASF",
+             "wC4",   "wC5",   "wC6",   "wC7",
+             "wCGR0", "wCGR1", "wCGR2", "wCGR3",
+             "wC12",  "wC13",  "wC14",  "wC15"
+           };
+         
+         fprintf (stream, wc_reg_names [INTVAL (x)]);
+       }
       return;
 
     default:
@@ -8618,12 +9839,8 @@ arm_print_operand (stream, x, code)
 #ifndef AOF_ASSEMBLER
 /* Target hook for assembling integer objects.  The ARM version needs to
    handle word-sized values specially.  */
-
 static bool
-arm_assemble_integer (x, size, aligned_p)
-     rtx x;
-     unsigned int size;
-     int aligned_p;
+arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
   if (size == UNITS_PER_WORD && aligned_p)
     {
@@ -8635,9 +9852,9 @@ arm_assemble_integer (x, size, aligned_p)
       if (NEED_GOT_RELOC && flag_pic && making_const_table &&
          (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
        {
-         if (GET_CODE (x) == SYMBOL_REF 
+         if (GET_CODE (x) == SYMBOL_REF
              && (CONSTANT_POOL_ADDRESS_P (x)
-                 || ENCODED_SHORT_CALL_ATTR_P (XSTR (x, 0))))
+                 || SYMBOL_REF_LOCAL_P (x)))
            fputs ("(GOTOFF)", asm_out_file);
          else if (GET_CODE (x) == LABEL_REF)
            fputs ("(GOTOFF)", asm_out_file);
@@ -8648,6 +9865,36 @@ arm_assemble_integer (x, size, aligned_p)
       return true;
     }
 
+  if (VECTOR_MODE_SUPPORTED_P (GET_MODE (x)))
+    {
+      int i, units;
+
+      if (GET_CODE (x) != CONST_VECTOR)
+       abort ();
+
+      units = CONST_VECTOR_NUNITS (x);
+
+      switch (GET_MODE (x))
+       {
+       case V2SImode: size = 4; break;
+       case V4HImode: size = 2; break;
+       case V8QImode: size = 1; break;
+       default:
+         abort ();
+       }
+
+      for (i = 0; i < units; i++)
+       {
+         rtx elt;
+
+         elt = CONST_VECTOR_ELT (x, i);
+         assemble_integer
+           (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
+       }
+
+      return true;
+    }
+
   return default_assemble_integer (x, size, aligned_p);
 }
 #endif
@@ -8669,7 +9916,7 @@ arm_assemble_integer (x, size, aligned_p)
    0 -> 2 final_prescan_insn if the `target' is an unconditional branch
    1 -> 3 ASM_OUTPUT_OPCODE after not having output the conditional branch
    2 -> 4 ASM_OUTPUT_OPCODE after not having output the conditional branch
-   3 -> 0 ASM_OUTPUT_INTERNAL_LABEL if the `target' label is reached
+   3 -> 0 (*targetm.asm_out.internal_label) if the `target' label is reached
           (the target label has CODE_LABEL_NUMBER equal to arm_target_label).
    4 -> 0 final_prescan_insn if the `target' unconditional branch is reached
           (the target insn is arm_target_insn).
@@ -8686,10 +9933,8 @@ arm_assemble_integer (x, size, aligned_p)
 /* Returns the index of the ARM condition code string in
    `arm_condition_codes'.  COMPARISON should be an rtx like
    `(eq (...) (...))'.  */
-
 static enum arm_cond_code
-get_arm_condition_code (comparison)
-     rtx comparison;
+get_arm_condition_code (rtx comparison)
 {
   enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
   int code;
@@ -8738,6 +9983,14 @@ get_arm_condition_code (comparison)
        default: abort ();
        }
 
+    case CC_Nmode:
+      switch (comp_code)
+       {
+       case NE: return ARM_MI;
+       case EQ: return ARM_PL;
+       default: abort ();
+       }
+
     case CCFPEmode:
     case CCFPmode:
       /* These encodings assume that AC=1 in the FPA system control
@@ -8809,10 +10062,8 @@ get_arm_condition_code (comparison)
   abort ();
 }
 
-
 void
-arm_final_prescan_insn (insn)
-     rtx insn;
+arm_final_prescan_insn (rtx insn)
 {
   /* BODY will hold the body of INSN.  */
   rtx body = PATTERN (insn);
@@ -8896,15 +10147,6 @@ arm_final_prescan_insn (insn)
   if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
     body = XVECEXP (body, 0, 0);
 
-#if 0  
-  /* If this is a conditional return then we don't want to know */
-  if (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
-      && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE
-      && (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN
-          || GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN))
-    return;
-#endif
-
   if (reverse
       || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
          && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
@@ -9032,7 +10274,8 @@ arm_final_prescan_insn (insn)
              /* If this is an unconditional branch to the same label, succeed.
                 If it is to another label, do nothing.  If it is conditional,
                 fail.  */
-             /* XXX Probably, the tests for SET and the PC are unnecessary.  */
+             /* XXX Probably, the tests for SET and the PC are
+                unnecessary.  */
 
              scanbody = PATTERN (this_insn);
              if (GET_CODE (scanbody) == SET
@@ -9050,7 +10293,7 @@ arm_final_prescan_insn (insn)
              /* Fail if a conditional return is undesirable (eg on a
                 StrongARM), but still allow this if optimizing for size.  */
              else if (GET_CODE (scanbody) == RETURN
-                      && !use_return_insn (TRUE)
+                      && !use_return_insn (TRUE, NULL)
                       && !optimize_size)
                fail = TRUE;
              else if (GET_CODE (scanbody) == RETURN
@@ -9083,6 +10326,18 @@ arm_final_prescan_insn (insn)
                    || GET_CODE (scanbody) == PARALLEL)
                  || get_attr_conds (this_insn) != CONDS_NOCOND)
                fail = TRUE;
+
+             /* A conditional cirrus instruction must be followed by
+                a non Cirrus instruction.  However, since we
+                conditionalize instructions in this function and by
+                the time we get here we can't add instructions
+                (nops), because shorten_branches() has already been
+                called, we will disable conditionalizing Cirrus
+                instructions to be safe.  */
+             if (GET_CODE (scanbody) != USE
+                 && GET_CODE (scanbody) != CLOBBER
+                 && get_attr_cirrus (this_insn) != CIRRUS_NOT)
+               fail = TRUE;
              break;
 
            default:
@@ -9149,11 +10404,8 @@ arm_final_prescan_insn (insn)
 
 /* Returns true if REGNO is a valid register
    for holding a quantity of tyoe MODE.  */
-
 int
-arm_hard_regno_mode_ok (regno, mode)
-     unsigned int regno;
-     enum machine_mode mode;
+arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
 {
   if (GET_MODE_CLASS (mode) == MODE_CC)
     return regno == CC_REGNUM;
@@ -9164,10 +10416,24 @@ arm_hard_regno_mode_ok (regno, mode)
        register available to hold the upper part of the value.
        We probably we ought to ensure that the register is the
        start of an even numbered register pair.  */
-    return (NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
+    return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
+
+  if (IS_CIRRUS_REGNUM (regno))
+    /* We have outlawed SI values in Cirrus registers because they
+       reside in the lower 32 bits, but SF values reside in the
+       upper 32 bits.  This causes gcc all sorts of grief.  We can't
+       even split the registers into pairs because Cirrus SI values
+       get sign extended to 64bits-- aldyh.  */
+    return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
+
+  if (IS_IWMMXT_GR_REGNUM (regno))
+    return mode == SImode;
+
+  if (IS_IWMMXT_REGNUM (regno))
+    return VALID_IWMMXT_REG_MODE (mode);
 
   if (regno <= LAST_ARM_REGNUM)
-    /* We allow any value to be stored in the general regisetrs.  */
+    /* We allow any value to be stored in the general registers.  */
     return 1;
 
   if (   regno == FRAME_POINTER_REGNUM
@@ -9175,7 +10441,7 @@ arm_hard_regno_mode_ok (regno, mode)
     /* We only allow integers in the fake hard registers.  */
     return GET_MODE_CLASS (mode) == MODE_INT;
 
-  /* The only registers left are the FPU registers
+  /* The only registers left are the FPA registers
      which we only allow to hold FP values.  */
   return GET_MODE_CLASS (mode) == MODE_FLOAT
     && regno >= FIRST_ARM_FP_REGNUM
@@ -9183,8 +10449,7 @@ arm_hard_regno_mode_ok (regno, mode)
 }
 
 int
-arm_regno_class (regno)
-     int regno;
+arm_regno_class (int regno)
 {
   if (TARGET_THUMB)
     {
@@ -9205,16 +10470,22 @@ arm_regno_class (regno)
   if (regno == CC_REGNUM)
     return NO_REGS;
 
-  return FPU_REGS;
+  if (IS_CIRRUS_REGNUM (regno))
+    return CIRRUS_REGS;
+
+  if (IS_IWMMXT_REGNUM (regno))
+    return IWMMXT_REGS;
+
+  if (IS_IWMMXT_GR_REGNUM (regno))
+    return IWMMXT_GR_REGS;
+
+  return FPA_REGS;
 }
 
 /* Handle a special case when computing the offset
    of an argument from the frame pointer.  */
-
 int
-arm_debugger_arg_offset (value, addr)
-     int value;
-     rtx addr;
+arm_debugger_arg_offset (int value, rtx addr)
 {
   rtx insn;
 
@@ -9244,7 +10515,7 @@ arm_debugger_arg_offset (value, addr)
      held in the register into an offset from the frame pointer.
      We do this by searching through the insns for the function
      looking to see where this register gets its value.  If the
-     register is initialised from the frame pointer plus an offset
+     register is initialized from the frame pointer plus an offset
      then we are in luck and we can continue, otherwise we give up.
      
      This code is exercised by producing debugging information
@@ -9293,30 +10564,568 @@ arm_debugger_arg_offset (value, addr)
 
   return value;
 }
+\f
+#define def_mbuiltin(MASK, NAME, TYPE, CODE)                           \
+  do                                                                   \
+    {                                                                  \
+      if ((MASK) & insn_flags)                                         \
+        builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE);       \
+    }                                                                  \
+  while (0)
+
+struct builtin_description
+{
+  const unsigned int       mask;
+  const enum insn_code     icode;
+  const char * const       name;
+  const enum arm_builtins  code;
+  const enum rtx_code      comparison;
+  const unsigned int       flag;
+};
+
+static const struct builtin_description bdesc_2arg[] =
+{
+#define IWMMXT_BUILTIN(code, string, builtin) \
+  { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
+    ARM_BUILTIN_##builtin, 0, 0 },
+
+  IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
+  IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
+  IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
+  IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
+  IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
+  IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
+  IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
+  IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
+  IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
+  IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
+  IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
+  IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
+  IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
+  IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
+  IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
+  IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
+  IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
+  IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
+  IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
+  IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsh", WMULSH)
+  IWMMXT_BUILTIN (umulv4hi3_highpart, "wmuluh", WMULUH)
+  IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
+  IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
+  IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
+  IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
+  IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
+  IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
+  IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
+  IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
+  IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
+  IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
+  IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
+  IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
+  IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
+  IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
+  IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
+  IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
+  IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
+  IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
+  IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
+  IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
+  IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
+  IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
+  IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
+  IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
+  IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
+  IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
+  IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
+  IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
+  IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
+  IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
+  IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
+  IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
+  IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
+
+#define IWMMXT_BUILTIN2(code, builtin) \
+  { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
+  
+  IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
+  IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
+  IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
+  IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
+  IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
+  IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
+  IWMMXT_BUILTIN2 (ashlv4hi3_di,    WSLLH)
+  IWMMXT_BUILTIN2 (ashlv4hi3,       WSLLHI)
+  IWMMXT_BUILTIN2 (ashlv2si3_di,    WSLLW)
+  IWMMXT_BUILTIN2 (ashlv2si3,       WSLLWI)
+  IWMMXT_BUILTIN2 (ashldi3_di,      WSLLD)
+  IWMMXT_BUILTIN2 (ashldi3_iwmmxt,  WSLLDI)
+  IWMMXT_BUILTIN2 (lshrv4hi3_di,    WSRLH)
+  IWMMXT_BUILTIN2 (lshrv4hi3,       WSRLHI)
+  IWMMXT_BUILTIN2 (lshrv2si3_di,    WSRLW)
+  IWMMXT_BUILTIN2 (lshrv2si3,       WSRLWI)
+  IWMMXT_BUILTIN2 (lshrdi3_di,      WSRLD)
+  IWMMXT_BUILTIN2 (lshrdi3,         WSRLDI)
+  IWMMXT_BUILTIN2 (ashrv4hi3_di,    WSRAH)
+  IWMMXT_BUILTIN2 (ashrv4hi3,       WSRAHI)
+  IWMMXT_BUILTIN2 (ashrv2si3_di,    WSRAW)
+  IWMMXT_BUILTIN2 (ashrv2si3,       WSRAWI)
+  IWMMXT_BUILTIN2 (ashrdi3_di,      WSRAD)
+  IWMMXT_BUILTIN2 (ashrdi3,         WSRADI)
+  IWMMXT_BUILTIN2 (rorv4hi3_di,     WRORH)
+  IWMMXT_BUILTIN2 (rorv4hi3,        WRORHI)
+  IWMMXT_BUILTIN2 (rorv2si3_di,     WRORW)
+  IWMMXT_BUILTIN2 (rorv2si3,        WRORWI)
+  IWMMXT_BUILTIN2 (rordi3_di,       WRORD)
+  IWMMXT_BUILTIN2 (rordi3,          WRORDI)
+  IWMMXT_BUILTIN2 (iwmmxt_wmacuz,   WMACUZ)
+  IWMMXT_BUILTIN2 (iwmmxt_wmacsz,   WMACSZ)
+};
+
+static const struct builtin_description bdesc_1arg[] =
+{
+  IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
+  IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
+  IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
+  IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
+  IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
+  IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
+  IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
+  IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
+  IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
+  IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
+};
+
+/* Set up all the iWMMXt builtins.  This is
+   not called if TARGET_IWMMXT is zero.  */
+
+static void
+arm_init_iwmmxt_builtins (void)
+{
+  const struct builtin_description * d;
+  size_t i;
+  tree endlink = void_list_node;
+
+  tree int_ftype_int
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, integer_type_node, endlink));
+  tree v8qi_ftype_v8qi_v8qi_int
+    = build_function_type (V8QI_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     tree_cons (NULL_TREE, V8QI_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
+  tree v4hi_ftype_v4hi_int
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree v2si_ftype_v2si_int
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree v2si_ftype_di_di
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, long_long_integer_type_node,
+                                     tree_cons (NULL_TREE, long_long_integer_type_node,
+                                                endlink)));
+  tree di_ftype_di_int
+    = build_function_type (long_long_integer_type_node,
+                          tree_cons (NULL_TREE, long_long_integer_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree di_ftype_di_int_int
+    = build_function_type (long_long_integer_type_node,
+                          tree_cons (NULL_TREE, long_long_integer_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
+  tree int_ftype_v8qi
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     endlink));
+  tree int_ftype_v4hi
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     endlink));
+  tree int_ftype_v2si
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     endlink));
+  tree int_ftype_v8qi_int
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree int_ftype_v4hi_int
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree int_ftype_v2si_int
+    = build_function_type (integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree v8qi_ftype_v8qi_int_int
+    = build_function_type (V8QI_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
+  tree v4hi_ftype_v4hi_int_int
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
+  tree v2si_ftype_v2si_int_int
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           integer_type_node,
+                                                           endlink))));
+  /* Miscellaneous.  */
+  tree v8qi_ftype_v4hi_v4hi
+    = build_function_type (V8QI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, V4HI_type_node,
+                                                endlink)));
+  tree v4hi_ftype_v2si_v2si
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, V2SI_type_node,
+                                                endlink)));
+  tree v2si_ftype_v4hi_v4hi
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, V4HI_type_node,
+                                                endlink)));
+  tree v2si_ftype_v8qi_v8qi
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     tree_cons (NULL_TREE, V8QI_type_node,
+                                                endlink)));
+  tree v4hi_ftype_v4hi_di
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE,
+                                                long_long_integer_type_node,
+                                                endlink)));
+  tree v2si_ftype_v2si_di
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE,
+                                                long_long_integer_type_node,
+                                                endlink)));
+  tree void_ftype_int_int
+    = build_function_type (void_type_node,
+                          tree_cons (NULL_TREE, integer_type_node,
+                                     tree_cons (NULL_TREE, integer_type_node,
+                                                endlink)));
+  tree di_ftype_void
+    = build_function_type (long_long_unsigned_type_node, endlink);
+  tree di_ftype_v8qi
+    = build_function_type (long_long_integer_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     endlink));
+  tree di_ftype_v4hi
+    = build_function_type (long_long_integer_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     endlink));
+  tree di_ftype_v2si
+    = build_function_type (long_long_integer_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     endlink));
+  tree v2si_ftype_v4hi
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     endlink));
+  tree v4hi_ftype_v8qi
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     endlink));
+
+  tree di_ftype_di_v4hi_v4hi
+    = build_function_type (long_long_unsigned_type_node,
+                          tree_cons (NULL_TREE,
+                                     long_long_unsigned_type_node,
+                                     tree_cons (NULL_TREE, V4HI_type_node,
+                                                tree_cons (NULL_TREE,
+                                                           V4HI_type_node,
+                                                           endlink))));
+
+  tree di_ftype_v4hi_v4hi
+    = build_function_type (long_long_unsigned_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, V4HI_type_node,
+                                                endlink)));
+
+  /* Normal vector binops.  */
+  tree v8qi_ftype_v8qi_v8qi
+    = build_function_type (V8QI_type_node,
+                          tree_cons (NULL_TREE, V8QI_type_node,
+                                     tree_cons (NULL_TREE, V8QI_type_node,
+                                                endlink)));
+  tree v4hi_ftype_v4hi_v4hi
+    = build_function_type (V4HI_type_node,
+                          tree_cons (NULL_TREE, V4HI_type_node,
+                                     tree_cons (NULL_TREE, V4HI_type_node,
+                                                endlink)));
+  tree v2si_ftype_v2si_v2si
+    = build_function_type (V2SI_type_node,
+                          tree_cons (NULL_TREE, V2SI_type_node,
+                                     tree_cons (NULL_TREE, V2SI_type_node,
+                                                endlink)));
+  tree di_ftype_di_di
+    = build_function_type (long_long_unsigned_type_node,
+                          tree_cons (NULL_TREE, long_long_unsigned_type_node,
+                                     tree_cons (NULL_TREE,
+                                                long_long_unsigned_type_node,
+                                                endlink)));
+
+  /* Add all builtins that are more or less simple operations on two
+     operands.  */
+  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+    {
+      /* Use one of the operands; the target can have a different mode for
+        mask-generating compares.  */
+      enum machine_mode mode;
+      tree type;
+
+      if (d->name == 0)
+       continue;
+
+      mode = insn_data[d->icode].operand[1].mode;
+
+      switch (mode)
+       {
+       case V8QImode:
+         type = v8qi_ftype_v8qi_v8qi;
+         break;
+       case V4HImode:
+         type = v4hi_ftype_v4hi_v4hi;
+         break;
+       case V2SImode:
+         type = v2si_ftype_v2si_v2si;
+         break;
+       case DImode:
+         type = di_ftype_di_di;
+         break;
+
+       default:
+         abort ();
+       }
+
+      def_mbuiltin (d->mask, d->name, type, d->code);
+    }
+
+  /* Add the remaining MMX insns with somewhat more complicated types.  */
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
+
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
+  def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
+}
+
+static void
+arm_init_builtins (void)
+{
+  if (TARGET_REALLY_IWMMXT)
+    arm_init_iwmmxt_builtins ();
+}
+
+/* Errors in the source file can cause expand_expr to return const0_rtx
+   where we expect a vector.  To avoid crashing, use one of the vector
+   clear instructions.  */
+
+static rtx
+safe_vector_operand (rtx x, enum machine_mode mode)
+{
+  if (x != const0_rtx)
+    return x;
+  x = gen_reg_rtx (mode);
+
+  emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
+                              : gen_rtx_SUBREG (DImode, x, 0)));
+  return x;
+}
+
+/* Subroutine of arm_expand_builtin to take care of binop insns.  */
+
+static rtx
+arm_expand_binop_builtin (enum insn_code icode,
+                         tree arglist, rtx target)
+{
+  rtx pat;
+  tree arg0 = TREE_VALUE (arglist);
+  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  rtx op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+  enum machine_mode mode1 = insn_data[icode].operand[2].mode;
+
+  if (VECTOR_MODE_P (mode0))
+    op0 = safe_vector_operand (op0, mode0);
+  if (VECTOR_MODE_P (mode1))
+    op1 = safe_vector_operand (op1, mode1);
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+
+  /* In case the insn wants input operands in modes different from
+     the result, abort.  */
+  if (GET_MODE (op0) != mode0 || GET_MODE (op1) != mode1)
+    abort ();
 
-#define def_builtin(NAME, TYPE, CODE) \
-  builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL, NULL_TREE)
+  if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+    op0 = copy_to_mode_reg (mode0, op0);
+  if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+    op1 = copy_to_mode_reg (mode1, op1);
 
-void
-arm_init_builtins ()
-{
-  tree endlink = void_list_node;
-  tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
-  tree pchar_type_node = build_pointer_type (char_type_node);
+  pat = GEN_FCN (icode) (target, op0, op1);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
+}
 
-  tree int_ftype_int, void_ftype_pchar;
+/* Subroutine of arm_expand_builtin to take care of unop insns.  */
 
-  /* void func (char *) */
-  void_ftype_pchar
-    = build_function_type_list (void_type_node, pchar_type_node, NULL_TREE);
+static rtx
+arm_expand_unop_builtin (enum insn_code icode,
+                        tree arglist, rtx target, int do_load)
+{
+  rtx pat;
+  tree arg0 = TREE_VALUE (arglist);
+  rtx op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+  enum machine_mode tmode = insn_data[icode].operand[0].mode;
+  enum machine_mode mode0 = insn_data[icode].operand[1].mode;
+
+  if (! target
+      || GET_MODE (target) != tmode
+      || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+    target = gen_reg_rtx (tmode);
+  if (do_load)
+    op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
+  else
+    {
+      if (VECTOR_MODE_P (mode0))
+       op0 = safe_vector_operand (op0, mode0);
 
-  /* int func (int) */
-  int_ftype_int
-    = build_function_type (integer_type_node, int_endlink);
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
+    }
 
-  /* Initialize arm V5 builtins.  */
-  if (arm_arch5)
-    def_builtin ("__builtin_clz", int_ftype_int, ARM_BUILTIN_CLZ);
+  pat = GEN_FCN (icode) (target, op0);
+  if (! pat)
+    return 0;
+  emit_insn (pat);
+  return target;
 }
 
 /* Expand an expression EXP that calls a built-in function,
@@ -9325,47 +11134,223 @@ arm_init_builtins ()
    SUBTARGET may be used as the target for computing one of EXP's operands.
    IGNORE is nonzero if the value is to be ignored.  */
 
-rtx
-arm_expand_builtin (exp, target, subtarget, mode, ignore)
-     tree exp;
-     rtx target;
-     rtx subtarget ATTRIBUTE_UNUSED;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
-     int ignore ATTRIBUTE_UNUSED;
-{
-  enum insn_code icode;
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
-  tree arg0;
-  rtx op0, pat;
-  enum machine_mode tmode, mode0;
-  int fcode = DECL_FUNCTION_CODE (fndecl);
+static rtx
+arm_expand_builtin (tree exp,
+                   rtx target,
+                   rtx subtarget ATTRIBUTE_UNUSED,
+                   enum machine_mode mode ATTRIBUTE_UNUSED,
+                   int ignore ATTRIBUTE_UNUSED)
+{
+  const struct builtin_description * d;
+  enum insn_code    icode;
+  tree              fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree              arglist = TREE_OPERAND (exp, 1);
+  tree              arg0;
+  tree              arg1;
+  tree              arg2;
+  rtx               op0;
+  rtx               op1;
+  rtx               op2;
+  rtx               pat;
+  int               fcode = DECL_FUNCTION_CODE (fndecl);
+  size_t            i;
+  enum machine_mode tmode;
+  enum machine_mode mode0;
+  enum machine_mode mode1;
+  enum machine_mode mode2;
 
   switch (fcode)
     {
-    default:
-      break;
-      
-    case ARM_BUILTIN_CLZ:
-      icode = CODE_FOR_clz;
+    case ARM_BUILTIN_TEXTRMSB:
+    case ARM_BUILTIN_TEXTRMUB:
+    case ARM_BUILTIN_TEXTRMSH:
+    case ARM_BUILTIN_TEXTRMUH:
+    case ARM_BUILTIN_TEXTRMSW:
+    case ARM_BUILTIN_TEXTRMUW:
+      icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
+              : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
+              : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
+              : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
+              : CODE_FOR_iwmmxt_textrmw);
+
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+      tmode = insn_data[icode].operand[0].mode;
+      mode0 = insn_data[icode].operand[1].mode;
+      mode1 = insn_data[icode].operand[2].mode;
+
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
+      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+       {
+         /* @@@ better error message */
+         error ("selector must be an immediate");
+         return gen_reg_rtx (tmode);
+       }
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+      pat = GEN_FCN (icode) (target, op0, op1);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+
+    case ARM_BUILTIN_TINSRB:
+    case ARM_BUILTIN_TINSRH:
+    case ARM_BUILTIN_TINSRW:
+      icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
+              : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
+              : CODE_FOR_iwmmxt_tinsrw);
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+      op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
+      tmode = insn_data[icode].operand[0].mode;
+      mode0 = insn_data[icode].operand[1].mode;
+      mode1 = insn_data[icode].operand[2].mode;
+      mode2 = insn_data[icode].operand[3].mode;
+
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
+      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+       op1 = copy_to_mode_reg (mode1, op1);
+      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
+       {
+         /* @@@ better error message */
+         error ("selector must be an immediate");
+         return const0_rtx;
+       }
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+      pat = GEN_FCN (icode) (target, op0, op1, op2);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+
+    case ARM_BUILTIN_SETWCX:
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+      emit_insn (gen_iwmmxt_tmcr (op0, op1));
+      return 0;
+
+    case ARM_BUILTIN_GETWCX:
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      target = gen_reg_rtx (SImode);
+      emit_insn (gen_iwmmxt_tmrc (target, op0));
+      return target;
+
+    case ARM_BUILTIN_WSHUFH:
+      icode = CODE_FOR_iwmmxt_wshufh;
       arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
       op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+      tmode = insn_data[icode].operand[0].mode;
+      mode1 = insn_data[icode].operand[1].mode;
+      mode2 = insn_data[icode].operand[2].mode;
+
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
+       op0 = copy_to_mode_reg (mode1, op0);
+      if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
+       {
+         /* @@@ better error message */
+         error ("mask must be an immediate");
+         return const0_rtx;
+       }
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+      pat = GEN_FCN (icode) (target, op0, op1);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+
+    case ARM_BUILTIN_WSADB:
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
+    case ARM_BUILTIN_WSADH:
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
+    case ARM_BUILTIN_WSADBZ:
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
+    case ARM_BUILTIN_WSADHZ:
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
+
+      /* Several three-argument builtins.  */
+    case ARM_BUILTIN_WMACS:
+    case ARM_BUILTIN_WMACU:
+    case ARM_BUILTIN_WALIGN:
+    case ARM_BUILTIN_TMIA:
+    case ARM_BUILTIN_TMIAPH:
+    case ARM_BUILTIN_TMIATT:
+    case ARM_BUILTIN_TMIATB:
+    case ARM_BUILTIN_TMIABT:
+    case ARM_BUILTIN_TMIABB:
+      icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
+              : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
+              : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
+              : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
+              : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
+              : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
+              : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
+              : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
+              : CODE_FOR_iwmmxt_walign);
+      arg0 = TREE_VALUE (arglist);
+      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      op1 = expand_expr (arg1, NULL_RTX, VOIDmode, 0);
+      op2 = expand_expr (arg2, NULL_RTX, VOIDmode, 0);
       tmode = insn_data[icode].operand[0].mode;
       mode0 = insn_data[icode].operand[1].mode;
+      mode1 = insn_data[icode].operand[2].mode;
+      mode2 = insn_data[icode].operand[3].mode;
 
       if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
        op0 = copy_to_mode_reg (mode0, op0);
+      if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
+       op1 = copy_to_mode_reg (mode1, op1);
+      if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
+       op2 = copy_to_mode_reg (mode2, op2);
       if (target == 0
          || GET_MODE (target) != tmode
          || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
        target = gen_reg_rtx (tmode);
-      pat = GEN_FCN (icode) (target, op0);
+      pat = GEN_FCN (icode) (target, op0, op1, op2);
       if (! pat)
        return 0;
       emit_insn (pat);
       return target;
+      
+    case ARM_BUILTIN_WZERO:
+      target = gen_reg_rtx (DImode);
+      emit_insn (gen_iwmmxt_clrdi (target));
+      return target;
+
+    default:
+      break;
     }
-  
+
+  for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
+    if (d->code == (const enum arm_builtins) fcode)
+      return arm_expand_binop_builtin (d->icode, arglist, target);
+
+  for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
+    if (d->code == (const enum arm_builtins) fcode)
+      return arm_expand_unop_builtin (d->icode, arglist, target, 0);
+
   /* @@@ Should really do something sensible here.  */
   return NULL_RTX;
 }
@@ -9374,12 +11359,8 @@ arm_expand_builtin (exp, target, subtarget, mode, ignore)
    checking to see if any of the variables created in that
    function match the RTX called 'orig'.  If they do then
    replace them with the RTX called 'new'.  */
-
 static void
-replace_symbols_in_block (block, orig, new)
-     tree block;
-     rtx orig;
-     rtx new;
+replace_symbols_in_block (tree block, rtx orig, rtx new)
 {
   for (; block; block = BLOCK_CHAIN (block))
     {
@@ -9408,12 +11389,8 @@ replace_symbols_in_block (block, orig, new)
 /* Return the number (counting from 0) of
    the least significant set bit in MASK.  */
 
-#ifdef __GNUC__
-inline
-#endif
-static int
-number_of_first_bit_set (mask)
-     int mask;
+inline static int
+number_of_first_bit_set (int mask)
 {
   int bit;
 
@@ -9429,10 +11406,7 @@ number_of_first_bit_set (mask)
    If 'reg_containing_return_addr' is -1, then the return address is
    actually on the stack, at the stack pointer.  */
 static void
-thumb_exit (f, reg_containing_return_addr, eh_ofs)
-     FILE * f;
-     int    reg_containing_return_addr;
-     rtx    eh_ofs;
+thumb_exit (FILE *f, int reg_containing_return_addr, rtx eh_ofs)
 {
   unsigned regs_available_for_popping;
   unsigned regs_to_pop;
@@ -9599,7 +11573,7 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
        number_of_first_bit_set (regs_available_for_popping);
 
       /* Remove this register for the mask of available registers, so that
-         the return address will not be corrupted by futher pops.  */
+         the return address will not be corrupted by further pops.  */
       regs_available_for_popping &= ~(1 << reg_containing_return_addr);
     }
 
@@ -9719,12 +11693,8 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
 }
 
 /* Emit code to push or pop registers to or from the stack.  */
-
 static void
-thumb_pushpop (f, mask, push)
-     FILE * f;
-     int mask;
-     int push;
+thumb_pushpop (FILE *f, int mask, int push)
 {
   int regno;
   int lo_mask = mask & 0xFF;
@@ -9785,8 +11755,7 @@ thumb_pushpop (f, mask, push)
 }
 \f
 void
-thumb_final_prescan_insn (insn)
-     rtx insn;
+thumb_final_prescan_insn (rtx insn)
 {
   if (flag_print_asm_name)
     asm_fprintf (asm_out_file, "%@ 0x%04x\n",
@@ -9794,8 +11763,7 @@ thumb_final_prescan_insn (insn)
 }
 
 int
-thumb_shiftable_const (val)
-     unsigned HOST_WIDE_INT val;
+thumb_shiftable_const (unsigned HOST_WIDE_INT val)
 {
   unsigned HOST_WIDE_INT mask = 0xff;
   int i;
@@ -9810,9 +11778,8 @@ thumb_shiftable_const (val)
   return 0;
 }
 
-/* Returns non-zero if the current function contains,
+/* Returns nonzero if the current function contains,
    or might contain a far jump.  */
-
 int
 thumb_far_jump_used_p (int in_prologue)
 {
@@ -9869,7 +11836,7 @@ thumb_far_jump_used_p (int in_prologue)
          && get_attr_far_jump (insn) == FAR_JUMP_YES
          )
        {
-         /* Record the fact that we have decied that
+         /* Record the fact that we have decided that
             the function does use far jumps.  */
          cfun->machine->far_jump_used = 1;
          return 1;
@@ -9879,11 +11846,9 @@ thumb_far_jump_used_p (int in_prologue)
   return 0;
 }
 
-/* Return non-zero if FUNC must be entered in ARM mode.  */
-
+/* Return nonzero if FUNC must be entered in ARM mode.  */
 int
-is_called_in_ARM_mode (func)
-     tree func;
+is_called_in_ARM_mode (tree func)
 {
   if (TREE_CODE (func) != FUNCTION_DECL)
     abort ();
@@ -9900,9 +11865,8 @@ is_called_in_ARM_mode (func)
 }
 
 /* The bits which aren't usefully expanded as rtl. */
-
 const char *
-thumb_unexpanded_epilogue ()
+thumb_unexpanded_epilogue (void)
 {
   int regno;
   int live_regs_mask = 0;
@@ -9914,20 +11878,19 @@ thumb_unexpanded_epilogue ()
   if (return_used_this_function)
     return "";
 
+  if (IS_NAKED (arm_current_func_type ()))
+    return "";
+
   for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
-    if (regs_ever_live[regno] && !call_used_regs[regno]
-       && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+    if (THUMB_REG_PUSHED_P (regno))
       live_regs_mask |= 1 << regno;
 
   for (regno = 8; regno < 13; regno++)
-    {
-      if (regs_ever_live[regno] && !call_used_regs[regno]
-         && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
-       high_regs_pushed++;
-    }
+    if (THUMB_REG_PUSHED_P (regno))
+      high_regs_pushed++;
 
   /* The prolog may have pushed some high registers to use as
-     work registers.  eg the testuite file:
+     work registers.  eg the testsuite file:
      gcc/testsuite/gcc/gcc.c-torture/execute/complex-2.c
      compiles to produce:
        push    {r4, r5, r6, r7, lr}
@@ -9969,8 +11932,7 @@ thumb_unexpanded_epilogue ()
          ("no low registers available for popping high registers");
       
       for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
-       if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
-           && !(TARGET_SINGLE_PIC_BASE && (next_hi_reg == arm_pic_register)))
+       if (THUMB_REG_PUSHED_P (next_hi_reg))
          break;
 
       while (high_regs_pushed)
@@ -9999,10 +11961,7 @@ thumb_unexpanded_epilogue ()
                               regno);
                  
                  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
-                   if (regs_ever_live[next_hi_reg]
-                       && !call_used_regs[next_hi_reg]
-                       && !(TARGET_SINGLE_PIC_BASE 
-                            && (next_hi_reg == arm_pic_register)))
+                   if (THUMB_REG_PUSHED_P (next_hi_reg))
                      break;
                }
            }
@@ -10075,9 +12034,8 @@ thumb_unexpanded_epilogue ()
 }
 
 /* Functions to save and restore machine-specific function data.  */
-
 static struct machine_function *
-arm_init_machine_status ()
+arm_init_machine_status (void)
 {
   struct machine_function *machine;
   machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
@@ -10090,11 +12048,8 @@ arm_init_machine_status ()
 
 /* Return an RTX indicating where the return address to the
    calling function can be found.  */
-
 rtx
-arm_return_addr (count, frame)
-     int count;
-     rtx frame ATTRIBUTE_UNUSED;
+arm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
 {
   if (count != 0)
     return NULL_RTX;
@@ -10110,20 +12065,104 @@ arm_return_addr (count, frame)
 }
 
 /* Do anything needed before RTL is emitted for each function.  */
-
 void
-arm_init_expanders ()
+arm_init_expanders (void)
 {
   /* Arrange to initialize and mark the machine per-function status.  */
   init_machine_status = arm_init_machine_status;
 }
 
-/* Generate the rest of a function's prologue.  */
+HOST_WIDE_INT
+thumb_get_frame_size (void)
+{
+  int regno;
+
+  int base_size = ROUND_UP_WORD (get_frame_size ());
+  int count_regs = 0;
+  int entry_size = 0;
+  int leaf;
+
+  if (! TARGET_THUMB)
+    abort ();
+
+  if (! TARGET_ATPCS)
+    return base_size;
+
+  /* We need to know if we are a leaf function.  Unfortunately, it
+     is possible to be called after start_sequence has been called,
+     which causes get_insns to return the insns for the sequence,
+     not the function, which will cause leaf_function_p to return
+     the incorrect result.
+
+     To work around this, we cache the computed frame size.  This
+     works because we will only be calling RTL expanders that need
+     to know about leaf functions once reload has completed, and the
+     frame size cannot be changed after that time, so we can safely
+     use the cached value.  */
+
+  if (reload_completed)
+    return cfun->machine->frame_size;
+
+  leaf = leaf_function_p ();
+
+  /* A leaf function does not need any stack alignment if it has nothing
+     on the stack.  */
+  if (leaf && base_size == 0)
+    {
+      cfun->machine->frame_size = 0;
+      return 0;
+    }
+
+  /* We know that SP will be word aligned on entry, and we must
+     preserve that condition at any subroutine call.  But those are
+     the only constraints.  */
+
+  /* Space for variadic functions.  */
+  if (current_function_pretend_args_size)
+    entry_size += current_function_pretend_args_size;
+
+  /* Space for pushed lo registers.  */
+  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
+    if (THUMB_REG_PUSHED_P (regno))
+      count_regs++;
+
+  /* Space for backtrace structure.  */
+  if (TARGET_BACKTRACE)
+    {
+      if (count_regs == 0 && regs_ever_live[LAST_ARG_REGNUM] != 0)
+       entry_size += 20;
+      else
+       entry_size += 16;
+    }
 
+  if (count_regs || !leaf || thumb_far_jump_used_p (1))
+    count_regs++;      /* LR */
+
+  entry_size += count_regs * 4;
+  count_regs = 0;
+
+  /* Space for pushed hi regs.  */
+  for (regno = 8; regno < 13; regno++)
+    if (THUMB_REG_PUSHED_P (regno))
+      count_regs++;
+
+  entry_size += count_regs * 4;
+
+  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
+    base_size += 4;
+  if ((entry_size + base_size + current_function_outgoing_args_size) & 7)
+    abort ();
+
+  cfun->machine->frame_size = base_size;
+
+  return base_size;
+}
+
+/* Generate the rest of a function's prologue.  */
 void
-thumb_expand_prologue ()
+thumb_expand_prologue (void)
 {
-  HOST_WIDE_INT amount = (get_frame_size ()
+  HOST_WIDE_INT amount = (thumb_get_frame_size ()
                          + current_function_outgoing_args_size);
   unsigned long func_type;
 
@@ -10144,7 +12183,7 @@ thumb_expand_prologue ()
 
   if (amount)
     {
-      amount = ROUND_UP (amount);
+      amount = ROUND_UP_WORD (amount);
       
       if (amount < 512)
        emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
@@ -10169,18 +12208,16 @@ thumb_expand_prologue ()
             been pushed at the start of the prologue and so we can corrupt
             it now.  */
          for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
-           if (regs_ever_live[regno]
-               && !call_used_regs[regno] /* Paranoia */
-               && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))
+           if (THUMB_REG_PUSHED_P (regno)
                && !(frame_pointer_needed
                     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
              break;
 
-         if (regno > LAST_LO_REGNUM) /* Very unlikely */
+         if (regno > LAST_LO_REGNUM) /* Very unlikely */
            {
              rtx spare = gen_rtx (REG, SImode, IP_REGNUM);
 
-             /* Choose an arbitary, non-argument low register.  */
+             /* Choose an arbitrary, non-argument low register.  */
              reg = gen_rtx (REG, SImode, LAST_LO_REGNUM);
 
              /* Save it by copying it into a high, scratch register.  */
@@ -10218,11 +12255,12 @@ thumb_expand_prologue ()
 }
 
 void
-thumb_expand_epilogue ()
+thumb_expand_epilogue (void)
 {
-  HOST_WIDE_INT amount = (get_frame_size ()
+  HOST_WIDE_INT amount = (thumb_get_frame_size ()
                          + current_function_outgoing_args_size);
-  
+  int regno;
+
   /* Naked functions don't have prologues.  */
   if (IS_NAKED (arm_current_func_type ()))
     return;
@@ -10231,7 +12269,7 @@ thumb_expand_epilogue ()
     emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
   else if (amount)
     {
-      amount = ROUND_UP (amount);
+      amount = ROUND_UP_WORD (amount);
       
       if (amount < 512)
        emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
@@ -10252,12 +12290,19 @@ thumb_expand_epilogue ()
 
   if (current_function_profile || TARGET_NO_SCHED_PRO)
     emit_insn (gen_blockage ());
+
+  /* Emit a clobber for each insn that will be restored in the epilogue,
+     so that flow2 will get register lifetimes correct.  */
+  for (regno = 0; regno < 13; regno++)
+    if (regs_ever_live[regno] && !call_used_regs[regno])
+      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
+
+  if (! regs_ever_live[LR_REGNUM])
+    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
 }
 
 static void
-thumb_output_function_prologue (f, size)
-     FILE * f;
-     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
+thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
   int live_regs_mask = 0;
   int high_regs_pushed = 0;
@@ -10291,13 +12336,13 @@ thumb_output_function_prologue (f, size)
       
 #define STUB_NAME ".real_start_of"
       
-      asm_fprintf (f, "\t.code\t16\n");
+      fprintf (f, "\t.code\t16\n");
 #ifdef ARM_PE
       if (arm_dllexport_name_p (name))
         name = arm_strip_name_encoding (name);
 #endif        
       asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
-      asm_fprintf (f, "\t.thumb_func\n");
+      fprintf (f, "\t.thumb_func\n");
       asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
     }
     
@@ -10307,9 +12352,9 @@ thumb_output_function_prologue (f, size)
        {
          int num_pushes;
          
-         asm_fprintf (f, "\tpush\t{");
+         fprintf (f, "\tpush\t{");
 
-         num_pushes = NUM_INTS (current_function_pretend_args_size);
+         num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
          
          for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
               regno <= LAST_ARG_REGNUM;
@@ -10317,7 +12362,7 @@ thumb_output_function_prologue (f, size)
            asm_fprintf (f, "%r%s", regno,
                         regno == LAST_ARG_REGNUM ? "" : ", ");
 
-         asm_fprintf (f, "}\n");
+         fprintf (f, "}\n");
        }
       else
        asm_fprintf (f, "\tsub\t%r, %r, #%d\n", 
@@ -10326,8 +12371,7 @@ thumb_output_function_prologue (f, size)
     }
 
   for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
-    if (regs_ever_live[regno] && !call_used_regs[regno]
-       && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+    if (THUMB_REG_PUSHED_P (regno))
       live_regs_mask |= 1 << regno;
 
   if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
@@ -10428,11 +12472,8 @@ thumb_output_function_prologue (f, size)
     thumb_pushpop (f, live_regs_mask, 1);
 
   for (regno = 8; regno < 13; regno++)
-    {
-      if (regs_ever_live[regno] && !call_used_regs[regno]
-         && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
-       high_regs_pushed++;
-    }
+    if (THUMB_REG_PUSHED_P (regno))
+      high_regs_pushed++;
 
   if (high_regs_pushed)
     {
@@ -10441,20 +12482,15 @@ thumb_output_function_prologue (f, size)
       int next_hi_reg;
 
       for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
-       {
-         if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
-             && !(TARGET_SINGLE_PIC_BASE
-                  && (next_hi_reg == arm_pic_register)))
-           break;
-       }
+       if (THUMB_REG_PUSHED_P (next_hi_reg))
+         break;
 
       pushable_regs = mask;
 
       if (pushable_regs == 0)
        {
          /* Desperation time -- this probably will never happen.  */
-         if (regs_ever_live[LAST_ARG_REGNUM]
-             || !call_used_regs[LAST_ARG_REGNUM])
+         if (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM))
            asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
          mask = 1 << LAST_ARG_REGNUM;
        }
@@ -10470,15 +12506,12 @@ thumb_output_function_prologue (f, size)
                  high_regs_pushed--;
                  
                  if (high_regs_pushed)
-                   for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
-                        next_hi_reg--)
-                     {
-                       if (regs_ever_live[next_hi_reg]
-                           && !call_used_regs[next_hi_reg]
-                           && !(TARGET_SINGLE_PIC_BASE 
-                                && (next_hi_reg == arm_pic_register)))
+                   {
+                     for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
+                          next_hi_reg--)
+                       if (THUMB_REG_PUSHED_P (next_hi_reg))
                          break;
-                     }
+                   }
                  else
                    {
                      mask &= ~((1 << regno) - 1);
@@ -10491,8 +12524,7 @@ thumb_output_function_prologue (f, size)
        }
 
       if (pushable_regs == 0
-         && (regs_ever_live[LAST_ARG_REGNUM]
-             || !call_used_regs[LAST_ARG_REGNUM]))
+         && (THUMB_REG_PUSHED_P (LAST_ARG_REGNUM)))
        asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
     }
 }
@@ -10500,10 +12532,8 @@ thumb_output_function_prologue (f, size)
 /* Handle the case of a double word load into a low register from
    a computed memory address.  The computed address may involve a
    register which is overwritten by the load.  */
-
 const char *
-thumb_load_double_from_address (operands)
-     rtx *operands;
+thumb_load_double_from_address (rtx *operands)
 {
   rtx addr;
   rtx base;
@@ -10622,11 +12652,8 @@ thumb_load_double_from_address (operands)
   return "";
 }
 
-
 const char *
-thumb_output_move_mem_multiple (n, operands)
-     int n;
-     rtx * operands;
+thumb_output_move_mem_multiple (int n, rtx *operands)
 {
   rtx tmp;
 
@@ -10675,10 +12702,8 @@ thumb_output_move_mem_multiple (n, operands)
 }
 
 /* Routines for generating rtl.  */
-
 void
-thumb_expand_movstrqi (operands)
-     rtx * operands;
+thumb_expand_movstrqi (rtx *operands)
 {
   rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
   rtx in  = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
@@ -10728,69 +12753,58 @@ thumb_expand_movstrqi (operands)
 }
 
 int
-thumb_cmp_operand (op, mode)
-     rtx op;
-     enum machine_mode mode;
+thumb_cmp_operand (rtx op, enum machine_mode mode)
 {
   return ((GET_CODE (op) == CONST_INT
-          && (unsigned HOST_WIDE_INT) (INTVAL (op)) < 256)
-         || register_operand (op, mode));
+          && INTVAL (op) < 256
+          && INTVAL (op) >= 0)
+         || s_register_operand (op, mode));
 }
 
-static const char *
-thumb_condition_code (x, invert)
-     rtx x;
-     int invert;
+int
+thumb_cmpneg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  static const char * const conds[] =
-  {
-    "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", 
-    "hi", "ls", "ge", "lt", "gt", "le"
-  };
-  int val;
+  return (GET_CODE (op) == CONST_INT
+         && INTVAL (op) < 0
+         && INTVAL (op) > -256);
+}
 
-  switch (GET_CODE (x))
-    {
-    case EQ: val = 0; break;
-    case NE: val = 1; break;
-    case GEU: val = 2; break;
-    case LTU: val = 3; break;
-    case GTU: val = 8; break;
-    case LEU: val = 9; break;
-    case GE: val = 10; break;
-    case LT: val = 11; break;
-    case GT: val = 12; break;
-    case LE: val = 13; break;
-    default:
-      abort ();
-    }
+/* Return TRUE if a result can be stored in OP without clobbering the
+   condition code register.  Prior to reload we only accept a
+   register.  After reload we have to be able to handle memory as
+   well, since a pseudo may not get a hard reg and reload cannot
+   handle output-reloads on jump insns.
+
+   We could possibly handle mem before reload as well, but that might
+   complicate things with the need to handle increment
+   side-effects.  */
 
-  return conds[val ^ invert];
+int
+thumb_cbrch_target_operand (rtx op, enum machine_mode mode)
+{
+  return (s_register_operand (op, mode)
+         || ((reload_in_progress || reload_completed)
+             && memory_operand (op, mode)));
 }
 
 /* Handle storing a half-word to memory during reload.  */ 
-
 void
-thumb_reload_out_hi (operands)
-     rtx * operands;
+thumb_reload_out_hi (rtx *operands)
 {
   emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
 }
 
-/* Handle storing a half-word to memory during reload.  */ 
-
+/* Handle reading a half-word from memory during reload.  */ 
 void
-thumb_reload_in_hi (operands)
-     rtx * operands ATTRIBUTE_UNUSED;
+thumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
 {
   abort ();
 }
 
 /* Return the length of a function name prefix
     that starts with the character 'c'.  */
-
 static int
-arm_get_strip_length (char c)
+arm_get_strip_length (int c)
 {
   switch (c)
     {
@@ -10801,9 +12815,8 @@ arm_get_strip_length (char c)
 
 /* Return a pointer to a function's name with any
    and all prefix encodings stripped from it.  */
-
 const char *
-arm_strip_name_encoding (const char * name)
+arm_strip_name_encoding (const char *name)
 {
   int skip;
   
@@ -10813,6 +12826,27 @@ arm_strip_name_encoding (const char * name)
   return name;
 }
 
+/* If there is a '*' anywhere in the name's prefix, then
+   emit the stripped name verbatim, otherwise prepend an
+   underscore if leading underscores are being used.  */
+void
+arm_asm_output_labelref (FILE *stream, const char *name)
+{
+  int skip;
+  int verbatim = 0;
+
+  while ((skip = arm_get_strip_length (* name)))
+    {
+      verbatim |= (*name == '*');
+      name += skip;
+    }
+
+  if (verbatim)
+    fputs (name, stream);
+  else
+    asm_fprintf (stream, "%U%s", name);
+}
+
 rtx aof_pic_label;
 
 #ifdef AOF_ASSEMBLER
@@ -10827,8 +12861,7 @@ struct pic_chain
 static struct pic_chain * aof_pic_chain = NULL;
 
 rtx
-aof_pic_entry (x)
-     rtx x;
+aof_pic_entry (rtx x)
 {
   struct pic_chain ** chainp;
   int offset;
@@ -10850,8 +12883,7 @@ aof_pic_entry (x)
 }
 
 void
-aof_dump_pic_table (f)
-     FILE * f;
+aof_dump_pic_table (FILE *f)
 {
   struct pic_chain * chain;
 
@@ -10874,7 +12906,7 @@ aof_dump_pic_table (f)
 int arm_text_section_count = 1;
 
 char *
-aof_text_section ()
+aof_text_section (void )
 {
   static char buf[100];
   sprintf (buf, "\tAREA |C$$code%d|, CODE, READONLY",
@@ -10887,7 +12919,7 @@ aof_text_section ()
 static int arm_data_section_count = 1;
 
 char *
-aof_data_section ()
+aof_data_section (void)
 {
   static char buf[100];
   sprintf (buf, "\tAREA |C$$data%d|, DATA", arm_data_section_count++);
@@ -10913,8 +12945,7 @@ struct import
 static struct import * imports_list = NULL;
 
 void
-aof_add_import (name)
-     const char * name;
+aof_add_import (const char *name)
 {
   struct import * new;
 
@@ -10929,8 +12960,7 @@ aof_add_import (name)
 }
 
 void
-aof_delete_import (name)
-     const char * name;
+aof_delete_import (const char *name)
 {
   struct import ** old;
 
@@ -10946,9 +12976,8 @@ aof_delete_import (name)
 
 int arm_main_function = 0;
 
-void
-aof_dump_imports (f)
-     FILE * f;
+static void
+aof_dump_imports (FILE *f)
 {
   /* The AOF assembler needs this to cause the startup code to be extracted
      from the library.  Brining in __main causes the whole thing to work
@@ -10969,6 +12998,54 @@ aof_dump_imports (f)
       imports_list = imports_list->next;
     }
 }
+
+static void
+aof_globalize_label (FILE *stream, const char *name)
+{
+  default_globalize_label (stream, name);
+  if (! strcmp (name, "main"))
+    arm_main_function = 1;
+}
+
+static void
+aof_file_start ()
+{
+  fputs ("__r0\tRN\t0\n", asm_out_file);
+  fputs ("__a1\tRN\t0\n", asm_out_file);
+  fputs ("__a2\tRN\t1\n", asm_out_file);
+  fputs ("__a3\tRN\t2\n", asm_out_file);
+  fputs ("__a4\tRN\t3\n", asm_out_file);
+  fputs ("__v1\tRN\t4\n", asm_out_file);
+  fputs ("__v2\tRN\t5\n", asm_out_file);
+  fputs ("__v3\tRN\t6\n", asm_out_file);
+  fputs ("__v4\tRN\t7\n", asm_out_file);
+  fputs ("__v5\tRN\t8\n", asm_out_file);
+  fputs ("__v6\tRN\t9\n", asm_out_file);
+  fputs ("__sl\tRN\t10\n", asm_out_file);
+  fputs ("__fp\tRN\t11\n", asm_out_file);
+  fputs ("__ip\tRN\t12\n", asm_out_file);
+  fputs ("__sp\tRN\t13\n", asm_out_file);
+  fputs ("__lr\tRN\t14\n", asm_out_file);
+  fputs ("__pc\tRN\t15\n", asm_out_file);
+  fputs ("__f0\tFN\t0\n", asm_out_file);
+  fputs ("__f1\tFN\t1\n", asm_out_file);
+  fputs ("__f2\tFN\t2\n", asm_out_file);
+  fputs ("__f3\tFN\t3\n", asm_out_file);
+  fputs ("__f4\tFN\t4\n", asm_out_file);
+  fputs ("__f5\tFN\t5\n", asm_out_file);
+  fputs ("__f6\tFN\t6\n", asm_out_file);
+  fputs ("__f7\tFN\t7\n", asm_out_file);
+  text_section ();
+}
+
+static void
+aof_file_end (void)
+{
+  if (flag_pic)
+    aof_dump_pic_table (asm_out_file);
+  aof_dump_imports (asm_out_file);
+  fputs ("\tEND\n", asm_out_file);
+}
 #endif /* AOF_ASSEMBLER */
 
 #ifdef OBJECT_FORMAT_ELF
@@ -10980,12 +13057,15 @@ aof_dump_imports (f)
    used before the section type.  */
 
 static void
-arm_elf_asm_named_section (name, flags)
-     const char *name;
-     unsigned int flags;
+arm_elf_asm_named_section (const char *name, unsigned int flags)
 {
-  char flagchars[8], *f = flagchars;
-  const char *type;
+  char flagchars[10], *f = flagchars;
+
+  if (! named_section_first_declaration (name))
+    {
+      fprintf (asm_out_file, "\t.section\t%s\n", name);
+      return;
+    }
 
   if (!(flags & SECTION_DEBUG))
     *f++ = 'a';
@@ -10999,19 +13079,28 @@ arm_elf_asm_named_section (name, flags)
     *f++ = 'M';
   if (flags & SECTION_STRINGS)
     *f++ = 'S';
+  if (flags & SECTION_TLS)
+    *f++ = 'T';
   *f = '\0';
 
-  if (flags & SECTION_BSS)
-    type = "nobits";
-  else
-    type = "progbits";
+  fprintf (asm_out_file, "\t.section\t%s,\"%s\"", name, flagchars);
 
-  if (flags & SECTION_ENTSIZE)
-    fprintf (asm_out_file, "\t.section\t%s,\"%s\",%%%s,%d\n",
-            name, flagchars, type, flags & SECTION_ENTSIZE);
-  else
-    fprintf (asm_out_file, "\t.section\t%s,\"%s\",%%%s\n",
-            name, flagchars, type);
+  if (!(flags & SECTION_NOTYPE))
+    {
+      const char *type;
+
+      if (flags & SECTION_BSS)
+       type = "nobits";
+      else
+       type = "progbits";
+
+      fprintf (asm_out_file, ",%%%s", type);
+
+      if (flags & SECTION_ENTSIZE)
+       fprintf (asm_out_file, ",%d", flags & SECTION_ENTSIZE);
+    }
+
+  putc ('\n', asm_out_file);
 }
 #endif
 
@@ -11023,20 +13112,14 @@ arm_elf_asm_named_section (name, flags)
    simplification.  */
 
 static void
-arm_encode_section_info (decl, first)
-     tree decl;
-     int first;
+arm_encode_section_info (tree decl, rtx rtl, int first)
 {
   /* This doesn't work with AOF syntax, since the string table may be in
      a different AREA.  */
 #ifndef AOF_ASSEMBLER
   if (optimize > 0 && TREE_CONSTANT (decl)
       && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST))
-    {
-      rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd'
-                 ? TREE_CST_RTL (decl) : DECL_RTL (decl));
-      SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-    }
+    SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
 #endif
 
   /* If we are referencing a function that is weak then encode a long call
@@ -11051,3 +13134,108 @@ arm_encode_section_info (decl, first)
     }
 }
 #endif /* !ARM_PE */
+
+static void
+arm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
+{
+  if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
+      && !strcmp (prefix, "L"))
+    {
+      arm_ccfsm_state = 0;
+      arm_target_insn = NULL;
+    }
+  default_internal_label (stream, prefix, labelno);
+}
+
+/* Output code to add DELTA to the first argument, and then jump
+   to FUNCTION.  Used for C++ multiple inheritance.  */
+static void
+arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
+                    HOST_WIDE_INT delta,
+                    HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
+                    tree function)
+{
+  int mi_delta = delta;
+  const char *const mi_op = mi_delta < 0 ? "sub" : "add";
+  int shift = 0;
+  int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
+                    ? 1 : 0);
+  if (mi_delta < 0)
+    mi_delta = - mi_delta;
+  while (mi_delta != 0)
+    {
+      if ((mi_delta & (3 << shift)) == 0)
+        shift += 2;
+      else
+        {
+          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
+                       mi_op, this_regno, this_regno,
+                       mi_delta & (0xff << shift));
+          mi_delta &= ~(0xff << shift);
+          shift += 8;
+        }
+    }
+  fputs ("\tb\t", file);
+  assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
+  if (NEED_PLT_RELOC)
+    fputs ("(PLT)", file);
+  fputc ('\n', file);
+}
+
+int
+arm_emit_vector_const (FILE *file, rtx x)
+{
+  int i;
+  const char * pattern;
+
+  if (GET_CODE (x) != CONST_VECTOR)
+    abort ();
+
+  switch (GET_MODE (x))
+    {
+    case V2SImode: pattern = "%08x"; break;
+    case V4HImode: pattern = "%04x"; break;
+    case V8QImode: pattern = "%02x"; break;
+    default:       abort ();
+    }
+
+  fprintf (file, "0x");
+  for (i = CONST_VECTOR_NUNITS (x); i--;)
+    {
+      rtx element;
+
+      element = CONST_VECTOR_ELT (x, i);
+      fprintf (file, pattern, INTVAL (element));
+    }
+
+  return 1;
+}
+
+const char *
+arm_output_load_gr (rtx *operands)
+{
+  rtx reg;
+  rtx offset;
+  rtx wcgr;
+  rtx sum;
+  
+  if (GET_CODE (operands [1]) != MEM
+      || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
+      || GET_CODE (reg = XEXP (sum, 0)) != REG
+      || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
+      || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
+    return "wldrw%?\t%0, %1";
+  
+  /* Fix up an out-of-range load of a GR register.  */  
+  output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
+  wcgr = operands[0];
+  operands[0] = reg;
+  output_asm_insn ("ldr%?\t%0, %1", operands);
+
+  operands[0] = wcgr;
+  operands[1] = reg;
+  output_asm_insn ("tmcr%?\t%0, %1", operands);
+  output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
+
+  return "";
+}