OSDN Git Service

2007-02-21 Paul Brook <paul@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / arm.c
index 1d646c7..6998332 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for ARM.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007  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).
@@ -67,10 +67,12 @@ static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
 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, RTX_CODE, 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 thumb2_legitimate_index_p (enum machine_mode, rtx, int);
+static int thumb1_base_register_rtx_p (rtx, enum machine_mode, int);
+inline static int thumb1_index_register_rtx_p (rtx, int);
 static int thumb_far_jump_used_p (void);
 static bool thumb_force_lr_save (void);
+static unsigned long thumb1_compute_save_reg_mask (void);
 static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
 static rtx emit_sfm (int, int);
 static int arm_size_return_regs (void);
@@ -114,7 +116,7 @@ static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
 #endif
 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 void thumb1_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);
@@ -154,6 +156,7 @@ static void arm_encode_section_info (tree, rtx, int);
 #endif
 
 static void arm_file_end (void);
+static void arm_file_start (void);
 
 #ifdef AOF_ASSEMBLER
 static void aof_globalize_label (FILE *, const char *);
@@ -176,6 +179,7 @@ static bool arm_must_pass_in_stack (enum machine_mode, tree);
 static void arm_unwind_emit (FILE *, rtx);
 static bool arm_output_ttype (rtx);
 #endif
+static void arm_dwarf_handle_frame_unspec (const char *, rtx, int);
 
 static tree arm_cxx_guard_type (void);
 static bool arm_cxx_guard_mask_bit (void);
@@ -202,6 +206,8 @@ static bool arm_tls_symbol_p (rtx x);
 #undef  TARGET_ATTRIBUTE_TABLE
 #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
 
+#undef TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START arm_file_start
 #undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END arm_file_end
 
@@ -357,6 +363,9 @@ static bool arm_tls_symbol_p (rtx x);
 #define TARGET_ARM_EABI_UNWINDER true
 #endif /* TARGET_UNWIND_INFO */
 
+#undef TARGET_DWARF_HANDLE_FRAME_UNSPEC
+#define TARGET_DWARF_HANDLE_FRAME_UNSPEC arm_dwarf_handle_frame_unspec
+
 #undef  TARGET_CANNOT_COPY_INSN_P
 #define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p
 
@@ -390,6 +399,9 @@ rtx arm_compare_op0, arm_compare_op1;
 /* The processor for which instructions should be scheduled.  */
 enum processor_type arm_tune = arm_none;
 
+/* The default processor used if not overridden by commandline.  */
+static enum processor_type arm_default_cpu = arm_none;
+
 /* Which floating point model to use.  */
 enum arm_fp_model arm_fp_model;
 
@@ -434,11 +446,15 @@ static int thumb_call_reg_needed;
 #define FL_WBUF              (1 << 14)       /* Schedule for write buffer ops.
                                         Note: ARM6 & 7 derivatives only.  */
 #define FL_ARCH6K     (1 << 15)       /* Architecture rel 6 K extensions.  */
+#define FL_THUMB2     (1 << 16)              /* Thumb-2.  */
+#define FL_NOTM              (1 << 17)       /* Instructions not present in the 'M'
+                                        profile.  */
+#define FL_DIV       (1 << 18)       /* Hardware divide.  */
 
 #define FL_IWMMXT     (1 << 29)              /* XScale v2 or "Intel Wireless MMX technology".  */
 
-#define FL_FOR_ARCH2   0
-#define FL_FOR_ARCH3   FL_MODE32
+#define FL_FOR_ARCH2   FL_NOTM
+#define FL_FOR_ARCH3   (FL_FOR_ARCH2 | FL_MODE32)
 #define FL_FOR_ARCH3M  (FL_FOR_ARCH3 | FL_ARCH3M)
 #define FL_FOR_ARCH4   (FL_FOR_ARCH3M | FL_ARCH4)
 #define FL_FOR_ARCH4T  (FL_FOR_ARCH4 | FL_THUMB)
@@ -452,6 +468,11 @@ static int thumb_call_reg_needed;
 #define FL_FOR_ARCH6K  (FL_FOR_ARCH6 | FL_ARCH6K)
 #define FL_FOR_ARCH6Z  FL_FOR_ARCH6
 #define FL_FOR_ARCH6ZK FL_FOR_ARCH6K
+#define FL_FOR_ARCH6T2 (FL_FOR_ARCH6 | FL_THUMB2)
+#define FL_FOR_ARCH7   (FL_FOR_ARCH6T2 &~ FL_NOTM)
+#define FL_FOR_ARCH7A  (FL_FOR_ARCH7 | FL_NOTM)
+#define FL_FOR_ARCH7R  (FL_FOR_ARCH7A | FL_DIV)
+#define FL_FOR_ARCH7M  (FL_FOR_ARCH7 | FL_DIV)
 
 /* The bits in this mask specify which
    instructions we are allowed to generate.  */
@@ -485,6 +506,9 @@ int arm_arch6 = 0;
 /* Nonzero if this chip supports the ARM 6K extensions.  */
 int arm_arch6k = 0;
 
+/* Nonzero if instructions not present in the 'M' profile can be used.  */
+int arm_arch_notm = 0;
+
 /* Nonzero if this chip can benefit from load scheduling.  */
 int arm_ld_sched = 0;
 
@@ -517,6 +541,12 @@ int thumb_code = 0;
    interworking clean.  */
 int arm_cpp_interwork = 0;
 
+/* Nonzero if chip supports Thumb 2.  */
+int arm_arch_thumb2;
+
+/* Nonzero if chip supports integer division instruction.  */
+int arm_arch_hwdiv;
+
 /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, we
    must report the mode of the memory reference from PRINT_OPERAND to
    PRINT_OPERAND_ADDRESS.  */
@@ -538,9 +568,17 @@ static int arm_constant_limit = 3;
 
 /* For an explanation of these variables, see final_prescan_insn below.  */
 int arm_ccfsm_state;
+/* arm_current_cc is also used for Thumb-2 cond_exec blocks.  */
 enum arm_cond_code arm_current_cc;
 rtx arm_target_insn;
 int arm_target_label;
+/* The number of conditionally executed insns, including the current insn.  */
+int arm_condexec_count = 0;
+/* A bitmask specifying the patterns for the IT block.
+   Zero means do not output an IT block before this insn. */
+int arm_condexec_mask = 0;
+/* The number of bits used in arm_condexec_mask.  */
+int arm_condexec_masklen = 0;
 
 /* The condition codes of the ARM, and the inverse function.  */
 static const char * const arm_condition_codes[] =
@@ -549,7 +587,12 @@ static const char * const arm_condition_codes[] =
   "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
 };
 
+#define ARM_LSL_NAME (TARGET_UNIFIED_ASM ? "lsl" : "asl")
 #define streq(string1, string2) (strcmp (string1, string2) == 0)
+
+#define THUMB2_WORK_REGS (0xff & ~(  (1 << THUMB_HARD_FRAME_POINTER_REGNUM) \
+                                  | (1 << SP_REGNUM) | (1 << PC_REGNUM) \
+                                  | (1 << PIC_OFFSET_TABLE_REGNUM)))
 \f
 /* Initialization code.  */
 
@@ -597,6 +640,11 @@ static const struct processors all_architectures[] =
   {"armv6k",  mpcore,    "6K",  FL_CO_PROC |             FL_FOR_ARCH6K, NULL},
   {"armv6z",  arm1176jzs, "6Z",  FL_CO_PROC |             FL_FOR_ARCH6Z, NULL},
   {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
+  {"armv6t2", arm1156t2s, "6T2", FL_CO_PROC |             FL_FOR_ARCH6T2, NULL},
+  {"armv7",   cortexa8,          "7",   FL_CO_PROC |             FL_FOR_ARCH7, NULL},
+  {"armv7-a", cortexa8,          "7A",  FL_CO_PROC |             FL_FOR_ARCH7A, NULL},
+  {"armv7-r", cortexr4,          "7R",  FL_CO_PROC |             FL_FOR_ARCH7R, NULL},
+  {"armv7-m", cortexm3,          "7M",  FL_CO_PROC |             FL_FOR_ARCH7M, NULL},
   {"ep9312",  ep9312,     "4T",  FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
   {"iwmmxt",  iwmmxt,     "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
   {NULL, arm_none, NULL, 0 , NULL}
@@ -1020,8 +1068,9 @@ arm_override_options (void)
          insn_flags = sel->flags;
        }
       sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
+      arm_default_cpu = (enum processor_type) (sel - all_cores);
       if (arm_tune == arm_none)
-       arm_tune = (enum processor_type) (sel - all_cores);
+       arm_tune = arm_default_cpu;
     }
 
   /* The processor for which we should tune should now have been
@@ -1036,6 +1085,9 @@ arm_override_options (void)
 
   /* Make sure that the processor choice does not conflict with any of the
      other command line choices.  */
+  if (TARGET_ARM && !(insn_flags & FL_NOTM))
+    error ("target CPU does not support ARM mode");
+
   if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
     {
       warning (0, "target CPU does not support interworking" );
@@ -1093,11 +1145,6 @@ arm_override_options (void)
       && (TARGET_DEFAULT & MASK_APCS_FRAME))
     warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
 
-  /* If stack checking is disabled, we can use r10 as the PIC register,
-     which keeps r9 available.  */
-  if (flag_pic && TARGET_SINGLE_PIC_BASE)
-    arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
-
   if (TARGET_APCS_FLOAT)
     warning (0, "passing floating point arguments in fp regs not yet supported");
 
@@ -1109,6 +1156,8 @@ arm_override_options (void)
   arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
   arm_arch6 = (insn_flags & FL_ARCH6) != 0;
   arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
+  arm_arch_notm = (insn_flags & FL_NOTM) != 0;
+  arm_arch_thumb2 = (insn_flags & FL_THUMB2) != 0;
   arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
   arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
 
@@ -1118,6 +1167,7 @@ arm_override_options (void)
   arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
   arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
   arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
+  arm_arch_hwdiv = (insn_flags & FL_DIV) != 0;
 
   /* V5 code we generate is completely interworking capable, so we turn off
      TARGET_INTERWORK here to avoid many tests later on.  */
@@ -1232,6 +1282,10 @@ arm_override_options (void)
   if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
     sorry ("iWMMXt and hardware floating point");
 
+  /* ??? iWMMXt insn patterns need auditing for Thumb-2.  */
+  if (TARGET_THUMB2 && TARGET_IWMMXT)
+    sorry ("Thumb-2 iWMMXt");
+
   /* If soft-float is specified then don't use FPU.  */
   if (TARGET_SOFT_FLOAT)
     arm_fpu_arch = FPUTYPE_NONE;
@@ -1265,8 +1319,8 @@ arm_override_options (void)
        target_thread_pointer = TP_SOFT;
     }
 
-  if (TARGET_HARD_TP && TARGET_THUMB)
-    error ("can not use -mtp=cp15 with -mthumb");
+  if (TARGET_HARD_TP && TARGET_THUMB1)
+    error ("can not use -mtp=cp15 with 16-bit Thumb");
 
   /* Override the default structure alignment for AAPCS ABI.  */
   if (TARGET_AAPCS_BASED)
@@ -1284,6 +1338,11 @@ arm_override_options (void)
                 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
     }
 
+  /* If stack checking is disabled, we can use r10 as the PIC register,
+     which keeps r9 available.  The EABI specifies r9 as the PIC register.  */
+  if (flag_pic && TARGET_SINGLE_PIC_BASE)
+    arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10;
+
   if (arm_pic_register_string != NULL)
     {
       int pic_register = decode_reg_name (arm_pic_register_string);
@@ -1301,6 +1360,7 @@ arm_override_options (void)
        arm_pic_register = pic_register;
     }
 
+  /* ??? We might want scheduling for thumb2.  */
   if (TARGET_THUMB && flag_schedule_insns)
     {
       /* Don't warn since it's on by default in -O2.  */
@@ -1382,6 +1442,9 @@ arm_isr_value (tree argument)
   const isr_attribute_arg * ptr;
   const char *              arg;
 
+  if (!arm_arch_notm)
+    return ARM_FT_NORMAL | ARM_FT_STACKALIGN;
+
   /* No argument - default to IRQ.  */
   if (argument == NULL_TREE)
     return ARM_FT_ISR;
@@ -1475,13 +1538,14 @@ use_return_insn (int iscond, rtx sibling)
 
   func_type = arm_current_func_type ();
 
-  /* Naked functions and volatile functions need special
+  /* Naked, volatile and stack alignment functions need special
      consideration.  */
-  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
+  if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED | ARM_FT_STACKALIGN))
     return 0;
 
-  /* So do interrupt functions that use the frame pointer.  */
-  if (IS_INTERRUPT (func_type) && frame_pointer_needed)
+  /* So do interrupt functions that use the frame pointer and Thumb
+     interrupt functions.  */
+  if (IS_INTERRUPT (func_type) && (frame_pointer_needed || TARGET_THUMB))
     return 0;
 
   offsets = arm_get_frame_offsets ();
@@ -1514,7 +1578,7 @@ use_return_insn (int iscond, rtx sibling)
      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)
+  if (stack_adjust == 4 && !arm_arch5 && TARGET_ARM)
     {
       /* Validate that r3 is a call-clobbered register (always true in
         the default abi) ...  */
@@ -1542,7 +1606,7 @@ use_return_insn (int iscond, rtx sibling)
 
   /* Can't be done if interworking with Thumb, and any registers have been
      stacked.  */
-  if (TARGET_INTERWORK && saved_int_regs != 0)
+  if (TARGET_INTERWORK && saved_int_regs != 0 && !IS_INTERRUPT(func_type))
     return 0;
 
   /* On StrongARM, conditional returns are expensive if they aren't
@@ -1608,17 +1672,36 @@ const_ok_for_arm (HOST_WIDE_INT i)
   if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
     return TRUE;
 
-  /* Get the number of trailing zeros, rounded down to the nearest even
-     number.  */
-  lowbit = (ffs ((int) i) - 1) & ~1;
+  /* Get the number of trailing zeros.  */
+  lowbit = ffs((int) i) - 1;
+  
+  /* Only even shifts are allowed in ARM mode so round down to the
+     nearest even number.  */
+  if (TARGET_ARM)
+    lowbit &= ~1;
 
   if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
     return TRUE;
-  else if (lowbit <= 4
+
+  if (TARGET_ARM)
+    {
+      /* Allow rotated constants in ARM mode.  */
+      if (lowbit <= 4
           && ((i & ~0xc000003f) == 0
               || (i & ~0xf000000f) == 0
               || (i & ~0xfc000003) == 0))
-    return TRUE;
+       return TRUE;
+    }
+  else
+    {
+      HOST_WIDE_INT v;
+
+      /* Allow repeated pattern.  */
+      v = i & 0xff;
+      v |= v << 16;
+      if (i == v || i == (v | (v << 8)))
+       return TRUE;
+    }
 
   return FALSE;
 }
@@ -1658,6 +1741,7 @@ const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
    either produce a simpler sequence, or we will want to cse the values.
    Return value is the number of insns emitted.  */
 
+/* ??? Tweak this for thumb2.  */
 int
 arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
                    HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
@@ -1716,6 +1800,8 @@ arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
                           1);
 }
 
+/* Return the number of ARM instructions required to synthesize the given
+   constant.  */
 static int
 count_insns_for_constant (HOST_WIDE_INT remainder, int i)
 {
@@ -1757,6 +1843,7 @@ emit_constant_insn (rtx cond, rtx pattern)
 
 /* As above, but extra parameter GENERATE which, if clear, suppresses
    RTL generation.  */
+/* ??? This needs more work for thumb2.  */
 
 static int
 arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
@@ -1933,6 +2020,15 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
   switch (code)
     {
     case SET:
+      /* See if we can use movw.  */
+      if (arm_arch_thumb2 && (remainder & 0xffff0000) == 0)
+       {
+         if (generate)
+           emit_constant_insn (cond, gen_rtx_SET (VOIDmode, target,
+                                                  GEN_INT (val)));
+         return 1;
+       }
+
       /* See if we can do this by sign_extending a constant that is known
         to be negative.  This is a good, way of doing it, since the shift
         may well merge into a subsequent insn.  */
@@ -2274,59 +2370,67 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
      We start by looking for the largest block of zeros that are aligned on
      a 2-bit boundary, we then fill up the temps, wrapping around to the
      top of the word when we drop off the bottom.
-     In the worst case this code should produce no more than four insns.  */
+     In the worst case this code should produce no more than four insns.
+     Thumb-2 constants are shifted, not rotated, so the MSB is always the
+     best place to start.  */
+
+  /* ??? Use thumb2 replicated constants when the high and low halfwords are
+     the same.  */
   {
     int best_start = 0;
-    int best_consecutive_zeros = 0;
-
-    for (i = 0; i < 32; i += 2)
+    if (!TARGET_THUMB2)
       {
-       int consecutive_zeros = 0;
+       int best_consecutive_zeros = 0;
 
-       if (!(remainder & (3 << i)))
+       for (i = 0; i < 32; i += 2)
          {
-           while ((i < 32) && !(remainder & (3 << i)))
-             {
-               consecutive_zeros += 2;
-               i += 2;
-             }
-           if (consecutive_zeros > best_consecutive_zeros)
+           int consecutive_zeros = 0;
+
+           if (!(remainder & (3 << i)))
              {
-               best_consecutive_zeros = consecutive_zeros;
-               best_start = i - consecutive_zeros;
+               while ((i < 32) && !(remainder & (3 << i)))
+                 {
+                   consecutive_zeros += 2;
+                   i += 2;
+                 }
+               if (consecutive_zeros > best_consecutive_zeros)
+                 {
+                   best_consecutive_zeros = consecutive_zeros;
+                   best_start = i - consecutive_zeros;
+                 }
+               i -= 2;
              }
-           i -= 2;
          }
-      }
-
-    /* So long as it won't require any more insns to do so, it's
-       desirable to emit a small constant (in bits 0...9) in the last
-       insn.  This way there is more chance that it can be combined with
-       a later addressing insn to form a pre-indexed load or store
-       operation.  Consider:
-
-              *((volatile int *)0xe0000100) = 1;
-              *((volatile int *)0xe0000110) = 2;
-
-       We want this to wind up as:
 
-               mov rA, #0xe0000000
-               mov rB, #1
-               str rB, [rA, #0x100]
-               mov rB, #2
-               str rB, [rA, #0x110]
-
-       rather than having to synthesize both large constants from scratch.
-
-       Therefore, we calculate how many insns would be required to emit
-       the constant starting from `best_start', and also starting from
-       zero (i.e. with bit 31 first to be output).  If `best_start' doesn't
-       yield a shorter sequence, we may as well use zero.  */
-    if (best_start != 0
-       && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
-       && (count_insns_for_constant (remainder, 0) <=
-           count_insns_for_constant (remainder, best_start)))
-      best_start = 0;
+       /* So long as it won't require any more insns to do so, it's
+          desirable to emit a small constant (in bits 0...9) in the last
+          insn.  This way there is more chance that it can be combined with
+          a later addressing insn to form a pre-indexed load or store
+          operation.  Consider:
+
+                  *((volatile int *)0xe0000100) = 1;
+                  *((volatile int *)0xe0000110) = 2;
+
+          We want this to wind up as:
+
+                   mov rA, #0xe0000000
+                   mov rB, #1
+                   str rB, [rA, #0x100]
+                   mov rB, #2
+                   str rB, [rA, #0x110]
+
+          rather than having to synthesize both large constants from scratch.
+
+          Therefore, we calculate how many insns would be required to emit
+          the constant starting from `best_start', and also starting from
+          zero (i.e. with bit 31 first to be output).  If `best_start' doesn't
+          yield a shorter sequence, we may as well use zero.  */
+       if (best_start != 0
+           && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
+           && (count_insns_for_constant (remainder, 0) <=
+               count_insns_for_constant (remainder, best_start)))
+         best_start = 0;
+      }
 
     /* Now start emitting the insns.  */
     i = best_start;
@@ -2392,9 +2496,17 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
              code = PLUS;
 
            insns++;
-           i -= 6;
+           if (TARGET_ARM)
+             i -= 6;
+           else
+             i -= 7;
          }
-       i -= 2;
+       /* Arm allows rotates by a multiple of two. Thumb-2 allows arbitrary
+          shifts.  */
+       if (TARGET_ARM)
+         i -= 2;
+       else
+         i--;
       }
     while (remainder);
   }
@@ -3078,7 +3190,7 @@ current_file_function_operand (rtx sym_ref)
   return 0;
 }
 
-/* Return nonzero 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))
@@ -3141,6 +3253,7 @@ static bool
 arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
   int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
+  unsigned long func_type;
 
   if (cfun->machine->sibcall_blocked)
     return false;
@@ -3168,8 +3281,13 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
     return false;
 
+  func_type = arm_current_func_type ();
   /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
-  if (IS_INTERRUPT (arm_current_func_type ()))
+  if (IS_INTERRUPT (func_type))
+    return false;
+
+  /* Never tailcall if function may be called with a misaligned SP.  */
+  if (IS_STACKALIGN (func_type))
     return false;
 
   /* Everything else is ok.  */
@@ -3222,7 +3340,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
              /* Play games to avoid marking the function as needing pic
                 if we are being called as part of the cost-estimation
                 process.  */
-             if (!ir_type())
+             if (current_ir_type () != IR_GIMPLE)
                current_function_uses_pic_offset_table = 1;
            }
          else
@@ -3234,7 +3352,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
              /* Play games to avoid marking the function as needing pic
                 if we are being called as part of the cost-estimation
                 process.  */
-             if (!ir_type())
+             if (current_ir_type () != IR_GIMPLE)
                {
                  current_function_uses_pic_offset_table = 1;
                  start_sequence ();
@@ -3268,8 +3386,10 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
       if (TARGET_ARM)
        emit_insn (gen_pic_load_addr_arm (address, orig));
-      else
-       emit_insn (gen_pic_load_addr_thumb (address, orig));
+      else if (TARGET_THUMB2)
+       emit_insn (gen_pic_load_addr_thumb2 (address, orig));
+      else /* TARGET_THUMB1 */
+       emit_insn (gen_pic_load_addr_thumb1 (address, orig));
 
       if ((GET_CODE (orig) == LABEL_REF
           || (GET_CODE (orig) == SYMBOL_REF &&
@@ -3287,8 +3407,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 #endif
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
-                                           REG_NOTES (insn));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
+
       return reg;
     }
   else if (GET_CODE (orig) == CONST)
@@ -3344,7 +3464,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 }
 
 
-/* Find a spare low register to use during the prolog of a function.  */
+/* Find a spare register to use during the prolog of a function.  */
 
 static int
 thumb_find_work_register (unsigned long pushed_regs_mask)
@@ -3393,6 +3513,13 @@ thumb_find_work_register (unsigned long pushed_regs_mask)
     if (pushed_regs_mask & (1 << reg))
       return reg;
 
+  if (TARGET_THUMB2)
+    {
+      /* Thumb-2 can use high regs.  */
+      for (reg = FIRST_HI_REGNUM; reg < 15; reg ++)
+       if (pushed_regs_mask & (1 << reg))
+         return reg;
+    }
   /* Something went wrong - thumb_compute_save_reg_mask()
      should have arranged for a suitable register to be pushed.  */
   gcc_unreachable ();
@@ -3440,7 +3567,27 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
       emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
                                             cfun->machine->pic_reg, labelno));
     }
-  else
+  else if (TARGET_THUMB2)
+    {
+      /* Thumb-2 only allows very limited access to the PC.  Calculate the
+        address in a temporary register.  */
+      if (arm_pic_register != INVALID_REGNUM)
+       {
+         pic_tmp = gen_rtx_REG (SImode,
+                                thumb_find_work_register (saved_regs));
+       }
+      else
+       {
+         gcc_assert (!no_new_pseudos);
+         pic_tmp = gen_reg_rtx (Pmode);
+       }
+
+      emit_insn (gen_pic_load_addr_thumb2 (cfun->machine->pic_reg, pic_rtx));
+      emit_insn (gen_pic_load_dot_plus_four (pic_tmp, labelno));
+      emit_insn (gen_addsi3(cfun->machine->pic_reg, cfun->machine->pic_reg,
+                           pic_tmp));
+    }
+  else /* TARGET_THUMB1 */
     {
       if (arm_pic_register != INVALID_REGNUM
          && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
@@ -3449,11 +3596,11 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
             able to find a work register.  */
          pic_tmp = gen_rtx_REG (SImode,
                                 thumb_find_work_register (saved_regs));
-         emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
+         emit_insn (gen_pic_load_addr_thumb1 (pic_tmp, pic_rtx));
          emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
        }
       else
-       emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
+       emit_insn (gen_pic_load_addr_thumb1 (cfun->machine->pic_reg, pic_rtx));
       emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
                                            cfun->machine->pic_reg, labelno));
     }
@@ -3583,6 +3730,80 @@ arm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
   return 0;
 }
 
+/* Return nonzero if X is a valid Thumb-2 address operand.  */
+int
+thumb2_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
+{
+  bool use_ldrd;
+  enum rtx_code code = GET_CODE (x);
+  
+  if (arm_address_register_rtx_p (x, strict_p))
+    return 1;
+
+  use_ldrd = (TARGET_LDRD
+             && (mode == DImode
+                 || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
+
+  if (code == POST_INC || code == PRE_DEC
+      || ((code == PRE_INC || code == POST_DEC)
+         && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
+    return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
+
+  else if ((code == POST_MODIFY || code == PRE_MODIFY)
+          && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
+          && GET_CODE (XEXP (x, 1)) == PLUS
+          && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
+    {
+      /* Thumb-2 only has autoincrement by constant.  */
+      rtx addend = XEXP (XEXP (x, 1), 1);
+      HOST_WIDE_INT offset;
+
+      if (GET_CODE (addend) != CONST_INT)
+       return 0;
+
+      offset = INTVAL(addend);
+      if (GET_MODE_SIZE (mode) <= 4)
+       return (offset > -256 && offset < 256);
+      
+      return (use_ldrd && offset > -1024 && offset < 1024
+             && (offset & 3) == 0);
+    }
+
+  /* After reload constants split into minipools will have addresses
+     from a LABEL_REF.  */
+  else if (reload_completed
+          && (code == LABEL_REF
+              || (code == 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 (code == PLUS)
+    {
+      rtx xop0 = XEXP (x, 0);
+      rtx xop1 = XEXP (x, 1);
+
+      return ((arm_address_register_rtx_p (xop0, strict_p)
+              && thumb2_legitimate_index_p (mode, xop1, strict_p))
+             || (arm_address_register_rtx_p (xop1, strict_p)
+                 && thumb2_legitimate_index_p (mode, xop0, strict_p)));
+    }
+
+  else if (GET_MODE_CLASS (mode) != MODE_FLOAT
+          && code == SYMBOL_REF
+          && CONSTANT_POOL_ADDRESS_P (x)
+          && ! (flag_pic
+                && symbol_mentioned_p (get_pool_constant (x))
+                && ! pcrel_constant_p (get_pool_constant (x))))
+    return 1;
+
+  return 0;
+}
+
 /* Return nonzero if INDEX is valid for an address index operand in
    ARM state.  */
 static int
@@ -3670,9 +3891,87 @@ arm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
          && INTVAL (index) > -range);
 }
 
-/* Return nonzero if X is valid as a Thumb state base register.  */
+/* Return true if OP is a valid index scaling factor for Thumb-2 address
+   index operand.  i.e. 1, 2, 4 or 8.  */
+static bool
+thumb2_index_mul_operand (rtx op)
+{
+  HOST_WIDE_INT val;
+  
+  if (GET_CODE(op) != CONST_INT)
+    return false;
+
+  val = INTVAL(op);
+  return (val == 1 || val == 2 || val == 4 || val == 8);
+}
+  
+/* Return nonzero if INDEX is a valid Thumb-2 address index operand.  */
+static int
+thumb2_legitimate_index_p (enum machine_mode mode, rtx index, int strict_p)
+{
+  enum rtx_code code = GET_CODE (index);
+
+  /* ??? Combine arm and thumb2 coprocessor addressing modes.  */
+  /* Standard coprocessor addressing modes.  */
+  if (TARGET_HARD_FLOAT
+      && (TARGET_FPA || TARGET_MAVERICK)
+      && (GET_MODE_CLASS (mode) == MODE_FLOAT
+         || (TARGET_MAVERICK && mode == DImode)))
+    return (code == CONST_INT && INTVAL (index) < 1024
+           && INTVAL (index) > -1024
+           && (INTVAL (index) & 3) == 0);
+
+  if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
+    return (code == CONST_INT
+           && INTVAL (index) < 1024
+           && INTVAL (index) > -1024
+           && (INTVAL (index) & 3) == 0);
+
+  if (arm_address_register_rtx_p (index, strict_p)
+      && (GET_MODE_SIZE (mode) <= 4))
+    return 1;
+
+  if (mode == DImode || mode == DFmode)
+    {
+      HOST_WIDE_INT val = INTVAL (index);
+      /* ??? Can we assume ldrd for thumb2?  */
+      /* Thumb-2 ldrd only has reg+const addressing modes.  */
+      if (code != CONST_INT)
+       return 0;
+
+      /* ldrd supports offsets of +-1020.
+         However the ldr fallback does not.  */
+      return val > -256 && val < 256 && (val & 3) == 0;
+    }
+
+  if (code == MULT)
+    {
+      rtx xiop0 = XEXP (index, 0);
+      rtx xiop1 = XEXP (index, 1);
+
+      return ((arm_address_register_rtx_p (xiop0, strict_p)
+              && thumb2_index_mul_operand (xiop1))
+             || (arm_address_register_rtx_p (xiop1, strict_p)
+                 && thumb2_index_mul_operand (xiop0)));
+    }
+  else if (code == ASHIFT)
+    {
+      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) <= 3);
+    }
+
+  return (code == CONST_INT
+         && INTVAL (index) < 4096
+         && INTVAL (index) > -256);
+}
+
+/* Return nonzero if X is valid as a 16-bit Thumb state base register.  */
 static int
-thumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
+thumb1_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
 {
   int regno;
 
@@ -3682,7 +3981,7 @@ thumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
   regno = REGNO (x);
 
   if (strict_p)
-    return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
+    return THUMB1_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
 
   return (regno <= LAST_LO_REGNUM
          || regno > LAST_VIRTUAL_REGISTER
@@ -3697,12 +3996,12 @@ thumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
 /* 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)
+thumb1_index_register_rtx_p (rtx x, int strict_p)
 {
-  return thumb_base_register_rtx_p (x, QImode, strict_p);
+  return thumb1_base_register_rtx_p (x, QImode, strict_p);
 }
 
-/* Return nonzero if x is a legitimate Thumb-state address.
+/* Return nonzero if x is a legitimate 16-bit 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.
@@ -3720,7 +4019,7 @@ thumb_index_register_rtx_p (rtx x, int strict_p)
    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)
+thumb1_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
@@ -3734,7 +4033,7 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
     return 0;
 
   /* Accept any base register.  SP only in SImode or larger.  */
-  else if (thumb_base_register_rtx_p (x, mode, strict_p))
+  else if (thumb1_base_register_rtx_p (x, mode, strict_p))
     return 1;
 
   /* This is PC relative data before arm_reorg runs.  */
@@ -3754,7 +4053,7 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
 
   /* 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))
+          && thumb1_index_register_rtx_p (XEXP (x, 0), strict_p))
     return 1;
 
   else if (GET_CODE (x) == PLUS)
@@ -3766,18 +4065,18 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
       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))
+         && thumb1_index_register_rtx_p (XEXP (x, 0), strict_p)
+         && thumb1_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)
+      else if ((thumb1_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
+      /* 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.  */
@@ -3791,7 +4090,10 @@ thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
        return 1;
 
       else if (GET_CODE (XEXP (x, 0)) == REG
-              && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
+              && (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
+                  || REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM
+                  || (REGNO (XEXP (x, 0)) >= FIRST_VIRTUAL_REGISTER
+                      && REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER))
               && GET_MODE_SIZE (mode) >= 4
               && GET_CODE (XEXP (x, 1)) == CONST_INT
               && (INTVAL (XEXP (x, 1)) & 3) == 0)
@@ -3903,7 +4205,16 @@ arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
 
   if (TARGET_ARM)
     emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
-  else
+  else if (TARGET_THUMB2)
+    {
+      rtx tmp;
+      /* Thumb-2 only allows very limited access to the PC.  Calculate
+        the address in a temporary register.  */
+      tmp = gen_reg_rtx (SImode);
+      emit_insn (gen_pic_load_dot_plus_four (tmp, labelno));
+      emit_insn (gen_addsi3(reg, reg, tmp));
+    }
+  else /* TARGET_THUMB1 */
     emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
 
   *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE, /* LCT_CONST?  */
@@ -3957,6 +4268,16 @@ legitimize_tls_address (rtx x, rtx reg)
 
       if (TARGET_ARM)
        emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
+      else if (TARGET_THUMB2)
+       {
+         rtx tmp;
+         /* Thumb-2 only allows very limited access to the PC.  Calculate
+            the address in a temporary register.  */
+         tmp = gen_reg_rtx (SImode);
+         emit_insn (gen_pic_load_dot_plus_four (tmp, labelno));
+         emit_insn (gen_addsi3(reg, reg, tmp));
+         emit_move_insn (reg, gen_const_mem (SImode, reg));
+       }
       else
        {
          emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
@@ -4064,8 +4385,8 @@ arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
       HOST_WIDE_INT mask, base, index;
       rtx base_reg;
 
-      /* ldr and ldrb can use a 12 bit index, ldrsb and the rest can only
-         use a 8 bit index. So let's use a 12 bit index for SImode only and
+      /* ldr and ldrb can use a 12-bit index, ldrsb and the rest can only
+         use a 8-bit index. So let's use a 12-bit index for SImode only and
          hope that arm_gen_constant will enable ldrb to use more bits. */
       bits = (mode == SImode) ? 12 : 8;
       mask = (1 << bits) - 1;
@@ -4264,7 +4585,7 @@ arm_tls_referenced_p (rtx x)
 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
 #endif
 static inline int
-thumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
+thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
 {
   enum machine_mode mode = GET_MODE (x);
 
@@ -4382,6 +4703,7 @@ thumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
 
 
 /* Worker routine for arm_rtx_costs.  */
+/* ??? This needs updating for thumb2.  */
 static inline int
 arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
 {
@@ -4430,6 +4752,14 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
                 ? 0 : 4));
 
     case MINUS:
+      if (GET_CODE (XEXP (x, 1)) == MULT && mode == SImode && arm_arch_thumb2)
+       {
+         extra_cost = rtx_cost (XEXP (x, 1), code);
+         if (!REG_OR_SUBREG_REG (XEXP (x, 0)))
+           extra_cost += 4 * ARM_NUM_REGS (mode);
+         return extra_cost;
+       }
+
       if (mode == DImode)
        return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
                + ((REG_OR_SUBREG_REG (XEXP (x, 0))
@@ -4563,6 +4893,7 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
       return 4 + (mode == DImode ? 4 : 0);
 
     case SIGN_EXTEND:
+      /* ??? value extensions are cheaper on armv6. */
       if (GET_MODE (XEXP (x, 0)) == QImode)
        return (4 + (mode == DImode ? 4 : 0)
                + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
@@ -4633,7 +4964,7 @@ arm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
   if (TARGET_THUMB)
     {
       /* XXX TBD.  For now, use the standard costs.  */
-      *total = thumb_rtx_costs (x, code, outer_code);
+      *total = thumb1_rtx_costs (x, code, outer_code);
       return true;
     }
 
@@ -4845,7 +5176,8 @@ arm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
     }
 }
 
-/* RTX costs for cores with a slow MUL implementation.  */
+/* RTX costs for cores with a slow MUL implementation.  Thumb-2 is not
+   supported on any "slowmul" cores, so it can be ignored.  */
 
 static bool
 arm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
@@ -4854,7 +5186,7 @@ arm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
 
   if (TARGET_THUMB)
     {
-      *total = thumb_rtx_costs (x, code, outer_code);
+      *total = thumb1_rtx_costs (x, code, outer_code);
       return true;
     }
 
@@ -4906,12 +5238,13 @@ arm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
   enum machine_mode mode = GET_MODE (x);
 
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
-      *total = thumb_rtx_costs (x, code, outer_code);
+      *total = thumb1_rtx_costs (x, code, outer_code);
       return true;
     }
 
+  /* ??? should thumb2 use different costs?  */
   switch (code)
     {
     case MULT:
@@ -4965,7 +5298,8 @@ arm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
 }
 
 
-/* RTX cost for XScale CPUs.  */
+/* RTX cost for XScale CPUs.  Thumb-2 is not supported on any xscale cores,
+   so it can be ignored.  */
 
 static bool
 arm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
@@ -4974,7 +5308,7 @@ arm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
 
   if (TARGET_THUMB)
     {
-      *total = thumb_rtx_costs (x, code, outer_code);
+      *total = thumb1_rtx_costs (x, code, outer_code);
       return true;
     }
 
@@ -5055,7 +5389,7 @@ arm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
   int nonreg_cost;
   int cost;
 
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
       switch (code)
        {
@@ -5064,7 +5398,7 @@ arm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
          return true;
 
        default:
-         *total = thumb_rtx_costs (x, code, outer_code);
+         *total = thumb1_rtx_costs (x, code, outer_code);
          return true;
        }
     }
@@ -5156,7 +5490,7 @@ arm_thumb_address_cost (rtx x)
 static int
 arm_address_cost (rtx x)
 {
-  return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
+  return TARGET_32BIT ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
 }
 
 static int
@@ -5349,7 +5683,9 @@ cirrus_memory_offset (rtx op)
 }
 
 /* Return TRUE if OP is a valid coprocessor memory address pattern.
-   WB if true if writeback address modes are allowed.  */
+   WB is true if full writeback address modes are allowed and is false
+   if limited writeback address modes (POST_INC and PRE_DEC) are
+   allowed.  */
 
 int
 arm_coproc_mem_operand (rtx op, bool wb)
@@ -5384,12 +5720,15 @@ arm_coproc_mem_operand (rtx op, bool wb)
   if (GET_CODE (ind) == REG)
     return arm_address_register_rtx_p (ind, 0);
 
-  /* Autoincremment addressing modes.  */
-  if (wb
-      && (GET_CODE (ind) == PRE_INC
-         || GET_CODE (ind) == POST_INC
-         || GET_CODE (ind) == PRE_DEC
-         || GET_CODE (ind) == POST_DEC))
+  /* Autoincremment addressing modes.  POST_INC and PRE_DEC are
+     acceptable in any case (subject to verification by
+     arm_address_register_rtx_p).  We need WB to be true to accept
+     PRE_INC and POST_DEC.  */
+  if (GET_CODE (ind) == POST_INC
+      || GET_CODE (ind) == PRE_DEC
+      || (wb
+         && (GET_CODE (ind) == PRE_INC
+             || GET_CODE (ind) == POST_DEC)))
     return arm_address_register_rtx_p (XEXP (ind, 0), 0);
 
   if (wb
@@ -5937,10 +6276,10 @@ load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
   if (unsorted_offsets[order[0]] == 0)
     return 1; /* ldmia */
 
-  if (unsorted_offsets[order[0]] == 4)
+  if (TARGET_ARM && unsorted_offsets[order[0]] == 4)
     return 2; /* ldmib */
 
-  if (unsorted_offsets[order[nops - 1]] == 0)
+  if (TARGET_ARM && unsorted_offsets[order[nops - 1]] == 0)
     return 3; /* ldmda */
 
   if (unsorted_offsets[order[nops - 1]] == -4)
@@ -5996,19 +6335,19 @@ emit_ldm_seq (rtx *operands, int nops)
   switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
     {
     case 1:
-      strcpy (buf, "ldm%?ia\t");
+      strcpy (buf, "ldm%(ia%)\t");
       break;
 
     case 2:
-      strcpy (buf, "ldm%?ib\t");
+      strcpy (buf, "ldm%(ib%)\t");
       break;
 
     case 3:
-      strcpy (buf, "ldm%?da\t");
+      strcpy (buf, "ldm%(da%)\t");
       break;
 
     case 4:
-      strcpy (buf, "ldm%?db\t");
+      strcpy (buf, "ldm%(db%)\t");
       break;
 
     case 5:
@@ -6022,7 +6361,7 @@ emit_ldm_seq (rtx *operands, int nops)
                 (long) -offset);
       output_asm_insn (buf, operands);
       base_reg = regs[0];
-      strcpy (buf, "ldm%?ia\t");
+      strcpy (buf, "ldm%(ia%)\t");
       break;
 
     default:
@@ -6185,19 +6524,19 @@ emit_stm_seq (rtx *operands, int nops)
   switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
     {
     case 1:
-      strcpy (buf, "stm%?ia\t");
+      strcpy (buf, "stm%(ia%)\t");
       break;
 
     case 2:
-      strcpy (buf, "stm%?ib\t");
+      strcpy (buf, "stm%(ib%)\t");
       break;
 
     case 3:
-      strcpy (buf, "stm%?da\t");
+      strcpy (buf, "stm%(da%)\t");
       break;
 
     case 4:
-      strcpy (buf, "stm%?db\t");
+      strcpy (buf, "stm%(db%)\t");
       break;
 
     default:
@@ -6758,7 +7097,7 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx 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
+  if (TARGET_THUMB1
       && GET_MODE (x) == SImode
       && (op == EQ || op == NE)
       && GET_CODE (x) == ZERO_EXTRACT
@@ -6769,6 +7108,7 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
      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.)  */
+  /* ??? Does the ZERO_EXTRACT case really apply to thumb2?  */
   if (GET_MODE (x) == SImode
       && y == const0_rtx
       && (op == EQ || op == NE || op == LT || op == GE)
@@ -6779,7 +7119,7 @@ arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
          || GET_CODE (x) == LSHIFTRT
          || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
          || GET_CODE (x) == ROTATERT
-         || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
+         || (TARGET_32BIT && GET_CODE (x) == ZERO_EXTRACT)))
     return CC_NOOVmode;
 
   if (GET_MODE (x) == QImode && (op == EQ || op == NE))
@@ -7362,8 +7702,29 @@ get_jump_table_size (rtx insn)
     {
       rtx body = PATTERN (insn);
       int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
+      HOST_WIDE_INT size;
+      HOST_WIDE_INT modesize;
 
-      return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
+      modesize = GET_MODE_SIZE (GET_MODE (body));
+      size = modesize * XVECLEN (body, elt);
+      switch (modesize)
+       {
+       case 1:
+         /* Round up size  of TBB table to a halfword boundary.  */
+         size = (size + 1) & ~(HOST_WIDE_INT)1;
+         break;
+       case 2:
+         /* No padding necessary for TBH.  */
+         break;
+       case 4:
+         /* Add two bytes for alignment on Thumb.  */
+         if (TARGET_THUMB)
+           size += 2;
+         break;
+       default:
+         gcc_unreachable ();
+       }
+      return size;
     }
 
   return 0;
@@ -8387,18 +8748,20 @@ fp_const_from_val (REAL_VALUE_TYPE *r)
 /* Output the operands of a LDM/STM instruction to STREAM.
    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.  */
+   INSTR is the possibly suffixed load or store instruction.
+   RFE is nonzero if the instruction should also copy spsr to cpsr.  */
 
 static void
 print_multi_reg (FILE *stream, const char *instr, unsigned reg,
-                unsigned long mask)
+                unsigned long mask, int rfe)
 {
   unsigned i;
   bool not_first = FALSE;
 
+  gcc_assert (!rfe || (mask & (1 << PC_REGNUM)));
   fputc ('\t', stream);
   asm_fprintf (stream, instr, reg);
-  fputs (", {", stream);
+  fputc ('{', stream);
 
   for (i = 0; i <= LAST_ARM_REGNUM; i++)
     if (mask & (1 << i))
@@ -8410,17 +8773,24 @@ print_multi_reg (FILE *stream, const char *instr, unsigned reg,
        not_first = TRUE;
       }
 
-  fprintf (stream, "}\n");
+  if (rfe)
+    fprintf (stream, "}^\n");
+  else
+    fprintf (stream, "}\n");
 }
 
 
-/* Output a FLDMX instruction to STREAM.
+/* Output a FLDMD instruction to STREAM.
    BASE if the register containing the address.
    REG and COUNT specify the register range.
-   Extra registers may be added to avoid hardware bugs.  */
+   Extra registers may be added to avoid hardware bugs.
+
+   We output FLDMD even for ARMv5 VFP implementations.  Although
+   FLDMD is technically not supported until ARMv6, it is believed
+   that all VFP implementations support its use in this context.  */
 
 static void
-arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
+vfp_output_fldmd (FILE * stream, unsigned int base, int reg, int count)
 {
   int i;
 
@@ -8433,7 +8803,7 @@ arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
     }
 
   fputc ('\t', stream);
-  asm_fprintf (stream, "fldmfdx\t%r!, {", base);
+  asm_fprintf (stream, "fldmfdd\t%r!, {", base);
 
   for (i = reg; i < reg + count; i++)
     {
@@ -8449,14 +8819,14 @@ arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
 /* Output the assembly for a store multiple.  */
 
 const char *
-vfp_output_fstmx (rtx * operands)
+vfp_output_fstmd (rtx * operands)
 {
   char pattern[100];
   int p;
   int base;
   int i;
 
-  strcpy (pattern, "fstmfdx\t%m0!, {%P1");
+  strcpy (pattern, "fstmfdd\t%m0!, {%P1");
   p = strlen (pattern);
 
   gcc_assert (GET_CODE (operands[1]) == REG);
@@ -8477,7 +8847,7 @@ vfp_output_fstmx (rtx * operands)
    number of bytes pushed.  */
 
 static int
-vfp_emit_fstmx (int base_reg, int count)
+vfp_emit_fstmd (int base_reg, int count)
 {
   rtx par;
   rtx dwarf;
@@ -8494,10 +8864,6 @@ vfp_emit_fstmx (int base_reg, int count)
       count++;
     }
 
-  /* ??? The frame layout is implementation defined.  We describe
-     standard format 1 (equivalent to a FSTMD insn and unused pad word).
-     We really need some way of representing the whole block so that the
-     unwinder can figure it out at runtime.  */
   par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
   dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
 
@@ -8514,7 +8880,7 @@ vfp_emit_fstmx (int base_reg, int count)
                                   UNSPEC_PUSH_MULT));
 
   tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
-                    plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
+                    plus_constant (stack_pointer_rtx, -(count * 8)));
   RTX_FRAME_RELATED_P (tmp) = 1;
   XVECEXP (dwarf, 0, 0) = tmp;
 
@@ -8544,7 +8910,7 @@ vfp_emit_fstmx (int base_reg, int count)
                                       REG_NOTES (par));
   RTX_FRAME_RELATED_P (par) = 1;
 
-  return count * 8 + 4;
+  return count * 8;
 }
 
 
@@ -8623,7 +8989,7 @@ output_mov_long_double_fpa_from_arm (rtx *operands)
   ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
   ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
 
-  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
+  output_asm_insn ("stm%(fd%)\t%|sp!, {%0, %1, %2}", ops);
   output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
 
   return "";
@@ -8645,7 +9011,7 @@ output_mov_long_double_arm_from_fpa (rtx *operands)
   ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
 
   output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
-  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
+  output_asm_insn ("ldm%(fd%)\t%|sp!, {%0, %1, %2}", ops);
   return "";
 }
 
@@ -8697,7 +9063,7 @@ output_mov_double_fpa_from_arm (rtx *operands)
 
   ops[0] = gen_rtx_REG (SImode, arm_reg0);
   ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
-  output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
+  output_asm_insn ("stm%(fd%)\t%|sp!, {%0, %1}", ops);
   output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
   return "";
 }
@@ -8716,7 +9082,7 @@ output_mov_double_arm_from_fpa (rtx *operands)
   ops[0] = gen_rtx_REG (SImode, arm_reg0);
   ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
   output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
-  output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
+  output_asm_insn ("ldm%(fd%)\t%|sp!, {%0, %1}", ops);
   return "";
 }
 
@@ -8741,25 +9107,28 @@ output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[1], 0)))
        {
        case REG:
-         output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
+         output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
          break;
 
        case PRE_INC:
          gcc_assert (TARGET_LDRD);
-         output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
+         output_asm_insn ("ldr%(d%)\t%0, [%m1, #8]!", operands);
          break;
 
        case PRE_DEC:
-         output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("ldr%(d%)\t%0, [%m1, #-8]!", operands);
+         else
+           output_asm_insn ("ldm%(db%)\t%m1!, %M0", operands);
          break;
 
        case POST_INC:
-         output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
+         output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
          break;
 
        case POST_DEC:
          gcc_assert (TARGET_LDRD);
-         output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
+         output_asm_insn ("ldr%(d%)\t%0, [%m1], #-8", operands);
          break;
 
        case PRE_MODIFY:
@@ -8774,24 +9143,25 @@ output_move_double (rtx *operands)
                {
                  /* Registers overlap so split out the increment.  */
                  output_asm_insn ("add%?\t%1, %1, %2", otherops);
-                 output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
+                 output_asm_insn ("ldr%(d%)\t%0, [%1] @split", otherops);
                }
              else
-               output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
+               output_asm_insn ("ldr%(d%)\t%0, [%1, %2]!", otherops);
            }
          else
            {
              /* We only allow constant increments, so this is safe.  */
-             output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
+             output_asm_insn ("ldr%(d%)\t%0, [%1], %2", otherops);
            }
          break;
 
        case LABEL_REF:
        case CONST:
          output_asm_insn ("adr%?\t%0, %1", operands);
-         output_asm_insn ("ldm%?ia\t%0, %M0", operands);
+         output_asm_insn ("ldm%(ia%)\t%0, %M0", operands);
          break;
 
+         /* ??? This needs checking for thumb2.  */
        default:
          if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
                               GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
@@ -8807,13 +9177,17 @@ output_move_double (rtx *operands)
                      switch ((int) INTVAL (otherops[2]))
                        {
                        case -8:
-                         output_asm_insn ("ldm%?db\t%1, %M0", otherops);
+                         output_asm_insn ("ldm%(db%)\t%1, %M0", otherops);
                          return "";
                        case -4:
-                         output_asm_insn ("ldm%?da\t%1, %M0", otherops);
+                         if (TARGET_THUMB2)
+                           break;
+                         output_asm_insn ("ldm%(da%)\t%1, %M0", otherops);
                          return "";
                        case 4:
-                         output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
+                         if (TARGET_THUMB2)
+                           break;
+                         output_asm_insn ("ldm%(ib%)\t%1, %M0", otherops);
                          return "";
                        }
                    }
@@ -8836,11 +9210,11 @@ output_move_double (rtx *operands)
                      if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
                        {
                          output_asm_insn ("add%?\t%1, %1, %2", otherops);
-                         output_asm_insn ("ldr%?d\t%0, [%1]",
+                         output_asm_insn ("ldr%(d%)\t%0, [%1]",
                                           otherops);
                        }
                      else
-                       output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
+                       output_asm_insn ("ldr%(d%)\t%0, [%1, %2]", otherops);
                      return "";
                    }
 
@@ -8857,7 +9231,7 @@ output_move_double (rtx *operands)
              else
                output_asm_insn ("sub%?\t%0, %1, %2", otherops);
 
-             return "ldm%?ia\t%0, %M0";
+             return "ldm%(ia%)\t%0, %M0";
            }
          else
            {
@@ -8885,25 +9259,28 @@ output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[0], 0)))
         {
        case REG:
-         output_asm_insn ("stm%?ia\t%m0, %M1", operands);
+         output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
          break;
 
         case PRE_INC:
          gcc_assert (TARGET_LDRD);
-         output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
+         output_asm_insn ("str%(d%)\t%1, [%m0, #8]!", operands);
          break;
 
         case PRE_DEC:
-         output_asm_insn ("stm%?db\t%m0!, %M1", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("str%(d%)\t%1, [%m0, #-8]!", operands);
+         else
+           output_asm_insn ("stm%(db%)\t%m0!, %M1", operands);
          break;
 
         case POST_INC:
-         output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
+         output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
          break;
 
         case POST_DEC:
          gcc_assert (TARGET_LDRD);
-         output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
+         output_asm_insn ("str%(d%)\t%1, [%m0], #-8", operands);
          break;
 
        case PRE_MODIFY:
@@ -8913,9 +9290,9 @@ output_move_double (rtx *operands)
          otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
 
          if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
-           output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
+           output_asm_insn ("str%(d%)\t%0, [%1, %2]!", otherops);
          else
-           output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
+           output_asm_insn ("str%(d%)\t%0, [%1], %2", otherops);
          break;
 
        case PLUS:
@@ -8925,15 +9302,19 @@ output_move_double (rtx *operands)
              switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
                {
                case -8:
-                 output_asm_insn ("stm%?db\t%m0, %M1", operands);
+                 output_asm_insn ("stm%(db%)\t%m0, %M1", operands);
                  return "";
 
                case -4:
-                 output_asm_insn ("stm%?da\t%m0, %M1", operands);
+                 if (TARGET_THUMB2)
+                   break;
+                 output_asm_insn ("stm%(da%)\t%m0, %M1", operands);
                  return "";
 
                case 4:
-                 output_asm_insn ("stm%?ib\t%m0, %M1", operands);
+                 if (TARGET_THUMB2)
+                   break;
+                 output_asm_insn ("stm%(ib%)\t%m0, %M1", operands);
                  return "";
                }
            }
@@ -8945,7 +9326,7 @@ output_move_double (rtx *operands)
            {
              otherops[0] = operands[1];
              otherops[1] = XEXP (XEXP (operands[0], 0), 0);
-             output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
+             output_asm_insn ("str%(d%)\t%0, [%1, %2]", otherops);
              return "";
            }
          /* Fall through */
@@ -8961,6 +9342,62 @@ output_move_double (rtx *operands)
   return "";
 }
 
+/* Output a VFP load or store instruction.  */
+
+const char *
+output_move_vfp (rtx *operands)
+{
+  rtx reg, mem, addr, ops[2];
+  int load = REG_P (operands[0]);
+  int dp = GET_MODE_SIZE (GET_MODE (operands[0])) == 8;
+  int integer_p = GET_MODE_CLASS (GET_MODE (operands[0])) == MODE_INT;
+  const char *template;
+  char buff[50];
+
+  reg = operands[!load];
+  mem = operands[load];
+
+  gcc_assert (REG_P (reg));
+  gcc_assert (IS_VFP_REGNUM (REGNO (reg)));
+  gcc_assert (GET_MODE (reg) == SFmode
+             || GET_MODE (reg) == DFmode
+             || GET_MODE (reg) == SImode
+             || GET_MODE (reg) == DImode);
+  gcc_assert (MEM_P (mem));
+
+  addr = XEXP (mem, 0);
+
+  switch (GET_CODE (addr))
+    {
+    case PRE_DEC:
+      template = "f%smdb%c%%?\t%%0!, {%%%s1}%s";
+      ops[0] = XEXP (addr, 0);
+      ops[1] = reg;
+      break;
+
+    case POST_INC:
+      template = "f%smia%c%%?\t%%0!, {%%%s1}%s";
+      ops[0] = XEXP (addr, 0);
+      ops[1] = reg;
+      break;
+
+    default:
+      template = "f%s%c%%?\t%%%s0, %%1%s";
+      ops[0] = reg;
+      ops[1] = mem;
+      break;
+    }
+
+  sprintf (buff, template,
+          load ? "ld" : "st",
+          dp ? 'd' : 's',
+          dp ? "P" : "",
+          integer_p ? "\t%@ int" : "");
+  output_asm_insn (buff, ops);
+
+  return "";
+}
+
 /* 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 *
@@ -9024,6 +9461,29 @@ output_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
   return "";
 }
 
+/* Return the name of a shifter operation.  */
+static const char *
+arm_shift_nmem(enum rtx_code code)
+{
+  switch (code)
+    {
+    case ASHIFT:
+      return ARM_LSL_NAME;
+
+    case ASHIFTRT:
+      return "asr";
+
+    case LSHIFTRT:
+      return "lsr";
+
+    case ROTATERT:
+      return "ror";
+
+    default:
+      abort();
+    }
+}
+
 /* Return the appropriate ARM instruction for the operation code.
    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
@@ -9048,10 +9508,16 @@ arithmetic_instr (rtx op, int shift_first_arg)
     case AND:
       return "and";
 
-    default:
-      gcc_unreachable ();
-    }
-}
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
+    case ROTATERT:
+      return arm_shift_nmem(GET_CODE(op));
+
+    default:
+      gcc_unreachable ();
+    }
+}
 
 /* Ensure valid constant shifts and return the appropriate shift mnemonic
    for the operation code.  The returned result should not be overwritten.
@@ -9081,26 +9547,18 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
 
   switch (code)
     {
-    case ASHIFT:
-      mnem = "asl";
-      break;
-
-    case ASHIFTRT:
-      mnem = "asr";
-      break;
-
-    case LSHIFTRT:
-      mnem = "lsr";
-      break;
-
     case ROTATE:
       gcc_assert (*amountp != -1);
       *amountp = 32 - *amountp;
+      code = ROTATERT;
 
       /* Fall through.  */
 
+    case ASHIFT:
+    case ASHIFTRT:
+    case LSHIFTRT:
     case ROTATERT:
-      mnem = "ror";
+      mnem = arm_shift_nmem(code);
       break;
 
     case MULT:
@@ -9108,7 +9566,7 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
         power of 2, since this case can never be reloaded from a reg.  */
       gcc_assert (*amountp != -1);
       *amountp = int_log2 (*amountp);
-      return "asl";
+      return ARM_LSL_NAME;
 
     default:
       gcc_unreachable ();
@@ -9118,7 +9576,7 @@ shift_op (rtx op, HOST_WIDE_INT *amountp)
     {
       /* This is not 100% correct, but follows from the desire to merge
         multiplication by a power of 2 with the recognizer for a
-        shift.  >=32 is not a valid shift for "asl", so we must try and
+        shift.  >=32 is not a valid shift for "lsl", so we must try and
         output a shift that produces the correct arithmetical result.
         Using lsr #32 is identical except for the fact that the carry bit
         is not set correctly if we set the flags; but we never use the
@@ -9248,17 +9706,22 @@ arm_compute_save_reg0_reg12_mask (void)
     }
   else
     {
+      /* In arm mode we handle r11 (FP) as a special case.  */
+      unsigned last_reg = TARGET_ARM ? 10 : 11;
+      
       /* In the normal case we only need to save those registers
         which are call saved and which are used by this function.  */
-      for (reg = 0; reg <= 10; reg++)
+      for (reg = 0; reg <= last_reg; reg++)
        if (regs_ever_live[reg] && ! call_used_regs [reg])
          save_reg_mask |= (1 << reg);
 
       /* Handle the frame pointer as a special case.  */
-      if (! TARGET_APCS_FRAME
-         && ! frame_pointer_needed
-         && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-         && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
+      if (TARGET_THUMB2 && frame_pointer_needed)
+       save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
+      else if (! TARGET_APCS_FRAME
+              && ! frame_pointer_needed
+              && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
+              && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
        save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
 
       /* If we aren't loading the PIC register,
@@ -9269,6 +9732,10 @@ arm_compute_save_reg0_reg12_mask (void)
          && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
              || current_function_uses_pic_offset_table))
        save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+
+      /* The prologue will copy SP into R0, so save it.  */
+      if (IS_STACKALIGN (func_type))
+       save_reg_mask |= 1;
     }
 
   /* Save registers so the exception handler can modify them.  */
@@ -9288,6 +9755,7 @@ arm_compute_save_reg0_reg12_mask (void)
   return save_reg_mask;
 }
 
+
 /* Compute a bit mask of which registers need to be
    saved on the stack for the current function.  */
 
@@ -9296,6 +9764,7 @@ arm_compute_save_reg_mask (void)
 {
   unsigned int save_reg_mask = 0;
   unsigned long func_type = arm_current_func_type ();
+  unsigned int reg;
 
   if (IS_NAKED (func_type))
     /* This should never really happen.  */
@@ -9303,7 +9772,7 @@ arm_compute_save_reg_mask (void)
 
   /* If we are creating a stack frame, then we must save the frame pointer,
      IP (which will hold the old stack pointer), LR and the PC.  */
-  if (frame_pointer_needed)
+  if (frame_pointer_needed && TARGET_ARM)
     save_reg_mask |=
       (1 << ARM_HARD_FRAME_POINTER_REGNUM)
       | (1 << IP_REGNUM)
@@ -9340,8 +9809,6 @@ arm_compute_save_reg_mask (void)
       && ((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,
@@ -9364,6 +9831,16 @@ arm_compute_save_reg_mask (void)
        }
     }
 
+  /* We may need to push an additional register for use initializing the
+     PIC base register.  */
+  if (TARGET_THUMB2 && IS_NESTED (func_type) && flag_pic
+      && (save_reg_mask & THUMB2_WORK_REGS) == 0)
+    {
+      reg = thumb_find_work_register (1 << 4);
+      if (!call_used_regs[reg])
+       save_reg_mask |= (1 << reg);
+    }
+
   return save_reg_mask;
 }
 
@@ -9371,7 +9848,7 @@ arm_compute_save_reg_mask (void)
 /* Compute a bit mask of which registers need to be
    saved on the stack for the current function.  */
 static unsigned long
-thumb_compute_save_reg_mask (void)
+thumb1_compute_save_reg_mask (void)
 {
   unsigned long mask;
   unsigned reg;
@@ -9440,7 +9917,7 @@ arm_get_vfp_saved_size (void)
                  /* Workaround ARM10 VFPr1 bug.  */
                  if (count == 2 && !arm_arch6)
                    count++;
-                 saved += count * 8 + 4;
+                 saved += count * 8;
                }
              count = 0;
            }
@@ -9451,7 +9928,7 @@ arm_get_vfp_saved_size (void)
        {
          if (count == 2 && !arm_arch6)
            count++;
-         saved += count * 8 + 4;
+         saved += count * 8;
        }
     }
   return saved;
@@ -9508,10 +9985,10 @@ output_return_instruction (rtx operand, int really_return, int reverse)
       const char * return_reg;
 
       /* If we do not have any special requirements for function exit
-        (e.g. interworking, or ISR) then we can load the return address
+        (e.g. interworking) then we can load the return address
         directly into the PC.  Otherwise we must load it into LR.  */
       if (really_return
-         && ! TARGET_INTERWORK)
+         && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
        return_reg = reg_names[PC_REGNUM];
       else
        return_reg = reg_names[LR_REGNUM];
@@ -9567,7 +10044,7 @@ output_return_instruction (rtx operand, int really_return, int reverse)
              stack_adjust = offsets->outgoing_args - offsets->saved_regs;
              gcc_assert (stack_adjust == 0 || stack_adjust == 4);
 
-             if (stack_adjust && arm_arch5)
+             if (stack_adjust && arm_arch5 && TARGET_ARM)
                sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
              else
                {
@@ -9632,6 +10109,7 @@ output_return_instruction (rtx operand, int really_return, int reverse)
        {
        case ARM_FT_ISR:
        case ARM_FT_FIQ:
+         /* ??? This is wrong for unified assembly syntax.  */
          sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
          break;
 
@@ -9640,6 +10118,7 @@ output_return_instruction (rtx operand, int really_return, int reverse)
          break;
 
        case ARM_FT_EXCEPTION:
+         /* ??? This is wrong for unified assembly syntax.  */
          sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
          break;
 
@@ -9707,9 +10186,9 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 {
   unsigned long func_type;
 
-  if (!TARGET_ARM)
+  if (TARGET_THUMB1)
     {
-      thumb_output_function_prologue (f, frame_size);
+      thumb1_output_function_prologue (f, frame_size);
       return;
     }
 
@@ -9745,6 +10224,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
 
   if (IS_NESTED (func_type))
     asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
+  if (IS_STACKALIGN (func_type))
+    asm_fprintf (f, "\t%@ Stack Align: May be called with mis-aligned SP.\n");
 
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
               current_function_args_size,
@@ -9823,7 +10304,7 @@ arm_output_epilogue (rtx sibling)
     if (saved_regs_mask & (1 << reg))
       floats_offset += 4;
 
-  if (frame_pointer_needed)
+  if (frame_pointer_needed && TARGET_ARM)
     {
       /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
       int vfp_offset = offsets->frame;
@@ -9877,8 +10358,8 @@ arm_output_epilogue (rtx sibling)
        {
          int saved_size;
 
-         /* The fldmx insn does not have base+offset addressing modes,
-            so we use IP to hold the address.  */
+         /* The fldmd insns do not have base+offset addressing
+             modes, so we use IP to hold the address.  */
          saved_size = arm_get_vfp_saved_size ();
 
          if (saved_size > 0)
@@ -9894,14 +10375,14 @@ arm_output_epilogue (rtx sibling)
                  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
                {
                  if (start_reg != reg)
-                   arm_output_fldmx (f, IP_REGNUM,
+                   vfp_output_fldmd (f, IP_REGNUM,
                                      (start_reg - FIRST_VFP_REGNUM) / 2,
                                      (reg - start_reg) / 2);
                  start_reg = reg + 2;
                }
            }
          if (start_reg != reg)
-           arm_output_fldmx (f, IP_REGNUM,
+           vfp_output_fldmd (f, IP_REGNUM,
                              (start_reg - FIRST_VFP_REGNUM) / 2,
                              (reg - start_reg) / 2);
        }
@@ -9960,22 +10441,41 @@ arm_output_epilogue (rtx sibling)
          || 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);
+      print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask, 0);
 
       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, 0);
     }
   else
     {
+      HOST_WIDE_INT amount;
+      int rfe;
       /* Restore stack pointer if necessary.  */
-      if (offsets->outgoing_args != offsets->saved_regs)
+      if (frame_pointer_needed)
        {
-         operands[0] = operands[1] = stack_pointer_rtx;
-         operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
+         /* For Thumb-2 restore sp from the frame pointer.
+            Operand restrictions mean we have to increment FP, then copy
+            to SP.  */
+         amount = offsets->locals_base - offsets->saved_regs;
+         operands[0] = hard_frame_pointer_rtx;
+       }
+      else
+       {
+         operands[0] = stack_pointer_rtx;
+         amount = offsets->outgoing_args - offsets->saved_regs;
+       }
+
+      if (amount)
+       {
+         operands[1] = operands[0];
+         operands[2] = GEN_INT (amount);
          output_add_immediate (operands);
        }
+      if (frame_pointer_needed)
+       asm_fprintf (f, "\tmov\t%r, %r\n",
+                    SP_REGNUM, HARD_FRAME_POINTER_REGNUM);
 
       if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
        {
@@ -10025,14 +10525,14 @@ arm_output_epilogue (rtx sibling)
                  && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
                {
                  if (start_reg != reg)
-                   arm_output_fldmx (f, SP_REGNUM,
+                   vfp_output_fldmd (f, SP_REGNUM,
                                      (start_reg - FIRST_VFP_REGNUM) / 2,
                                      (reg - start_reg) / 2);
                  start_reg = reg + 2;
                }
            }
          if (start_reg != reg)
-           arm_output_fldmx (f, SP_REGNUM,
+           vfp_output_fldmd (f, SP_REGNUM,
                              (start_reg - FIRST_VFP_REGNUM) / 2,
                              (reg - start_reg) / 2);
        }
@@ -10042,7 +10542,9 @@ arm_output_epilogue (rtx sibling)
            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
+      if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
+         && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+         && !IS_STACKALIGN (func_type)
          && really_return
          && current_function_pretend_args_size == 0
          && saved_regs_mask & (1 << LR_REGNUM)
@@ -10050,11 +10552,16 @@ arm_output_epilogue (rtx sibling)
        {
          saved_regs_mask &= ~ (1 << LR_REGNUM);
          saved_regs_mask |=   (1 << PC_REGNUM);
+         rfe = IS_INTERRUPT (func_type);
        }
+      else
+       rfe = 0;
 
       /* Load the registers off the stack.  If we only have one register
-        to load use the LDR instruction - it is faster.  */
-      if (saved_regs_mask == (1 << LR_REGNUM))
+        to load use the LDR instruction - it is faster.  For Thumb-2
+        always use pop and the assembler will pick the best instruction.*/
+      if (TARGET_ARM && saved_regs_mask == (1 << LR_REGNUM)
+         && !IS_INTERRUPT(func_type))
        {
          asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
        }
@@ -10065,9 +10572,13 @@ arm_output_epilogue (rtx sibling)
               (i.e. "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);
+           print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask,
+                            rfe);
+         else if (TARGET_ARM)
+           print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, saved_regs_mask,
+                            rfe);
          else
-           print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+           print_multi_reg (f, "pop\t", SP_REGNUM, saved_regs_mask, 0);
        }
 
       if (current_function_pretend_args_size)
@@ -10105,6 +10616,11 @@ arm_output_epilogue (rtx sibling)
       break;
 
     default:
+      if (IS_STACKALIGN (func_type))
+       {
+         /* See comment in arm_expand_prologue.  */
+         asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, 0);
+       }
       if (arm_arch5 || arm_arch4t)
        asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
       else
@@ -10121,7 +10637,7 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
 {
   arm_stack_offsets *offsets;
 
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
       int regno;
 
@@ -10145,7 +10661,7 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
         RTL for it.  This does not happen for inline functions.  */
       return_used_this_function = 0;
     }
-  else
+  else /* TARGET_32BIT */
     {
       /* We need to take into account any stack-frame rounding.  */
       offsets = arm_get_frame_offsets ();
@@ -10453,9 +10969,10 @@ arm_get_frame_offsets (void)
   /* Space for variadic functions.  */
   offsets->saved_args = current_function_pretend_args_size;
 
+  /* In Thumb mode this is incorrect, but never used.  */
   offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
 
-  if (TARGET_ARM)
+  if (TARGET_32BIT)
     {
       unsigned int regno;
 
@@ -10488,9 +11005,9 @@ arm_get_frame_offsets (void)
            saved += arm_get_vfp_saved_size ();
        }
     }
-  else /* TARGET_THUMB */
+  else /* TARGET_THUMB1 */
     {
-      saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
+      saved = bit_count (thumb1_compute_save_reg_mask ()) * 4;
       if (TARGET_BACKTRACE)
        saved += 16;
     }
@@ -10607,11 +11124,132 @@ arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
 }
 
 
-/* Generate the prologue instructions for entry into an ARM function.  */
+/* Emit RTL to save coprocessor registers on function entry.  Returns the
+   number of bytes pushed.  */
+
+static int
+arm_save_coproc_regs(void)
+{
+  int saved_size = 0;
+  unsigned reg;
+  unsigned start_reg;
+  rtx insn;
+
+  for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_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_set_insn (insn, gen_rtx_REG (V2SImode, reg));
+       RTX_FRAME_RELATED_P (insn) = 1;
+       saved_size += 8;
+      }
+
+  /* Save any floating point call-saved registers used by this
+     function.  */
+  if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
+    {
+      for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
+       if (regs_ever_live[reg] && !call_used_regs[reg])
+         {
+           insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
+           insn = gen_rtx_MEM (XFmode, insn);
+           insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
+           RTX_FRAME_RELATED_P (insn) = 1;
+           saved_size += 12;
+         }
+    }
+  else
+    {
+      start_reg = LAST_FPA_REGNUM;
+
+      for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
+       {
+         if (regs_ever_live[reg] && !call_used_regs[reg])
+           {
+             if (start_reg - reg == 3)
+               {
+                 insn = emit_sfm (reg, 4);
+                 RTX_FRAME_RELATED_P (insn) = 1;
+                 saved_size += 48;
+                 start_reg = reg - 1;
+               }
+           }
+         else
+           {
+             if (start_reg != reg)
+               {
+                 insn = emit_sfm (reg + 1, start_reg - reg);
+                 RTX_FRAME_RELATED_P (insn) = 1;
+                 saved_size += (start_reg - reg) * 12;
+               }
+             start_reg = reg - 1;
+           }
+       }
+
+      if (start_reg != reg)
+       {
+         insn = emit_sfm (reg + 1, start_reg - reg);
+         saved_size += (start_reg - reg) * 12;
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+    }
+  if (TARGET_HARD_FLOAT && TARGET_VFP)
+    {
+      start_reg = FIRST_VFP_REGNUM;
+
+      for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+       {
+         if ((!regs_ever_live[reg] || call_used_regs[reg])
+             && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
+           {
+             if (start_reg != reg)
+               saved_size += vfp_emit_fstmd (start_reg,
+                                             (reg - start_reg) / 2);
+             start_reg = reg + 2;
+           }
+       }
+      if (start_reg != reg)
+       saved_size += vfp_emit_fstmd (start_reg,
+                                     (reg - start_reg) / 2);
+    }
+  return saved_size;
+}
+
+
+/* Set the Thumb frame pointer from the stack pointer.  */
+
+static void
+thumb_set_frame_pointer (arm_stack_offsets *offsets)
+{
+  HOST_WIDE_INT amount;
+  rtx insn, dwarf;
+
+  amount = offsets->outgoing_args - offsets->locals_base;
+  if (amount < 1024)
+    insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+                                 stack_pointer_rtx, GEN_INT (amount)));
+  else
+    {
+      emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
+      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+                                   hard_frame_pointer_rtx,
+                                   stack_pointer_rtx));
+      dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
+                          plus_constant (stack_pointer_rtx, amount));
+      RTX_FRAME_RELATED_P (dwarf) = 1;
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
+                                           REG_NOTES (insn));
+    }
+
+  RTX_FRAME_RELATED_P (insn) = 1;
+}
+
+/* Generate the prologue instructions for entry into an ARM or Thumb-2
+   function.  */
 void
 arm_expand_prologue (void)
 {
-  int reg;
   rtx amount;
   rtx insn;
   rtx ip_rtx;
@@ -10637,7 +11275,38 @@ arm_expand_prologue (void)
 
   ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
 
-  if (frame_pointer_needed)
+  if (IS_STACKALIGN (func_type))
+    {
+      rtx dwarf;
+      rtx r0;
+      rtx r1;
+      /* Handle a word-aligned stack pointer.  We generate the following:
+
+         mov r0, sp
+         bic r1, r0, #7
+         mov sp, r1
+         <save and restore r0 in normal prologue/epilogue>
+         mov sp, r0
+         bx lr
+
+        The unwinder doesn't need to know about the stack realignment.
+        Just tell it we saved SP in r0.  */
+      gcc_assert (TARGET_THUMB2 && !arm_arch_notm && args_to_push == 0);
+
+      r0 = gen_rtx_REG (SImode, 0);
+      r1 = gen_rtx_REG (SImode, 1);
+      dwarf = gen_rtx_UNSPEC (SImode, NULL_RTVEC, UNSPEC_STACK_ALIGN);
+      dwarf = gen_rtx_SET (VOIDmode, r0, dwarf);
+      insn = gen_movsi (r0, stack_pointer_rtx);
+      RTX_FRAME_RELATED_P (insn) = 1;
+      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                           dwarf, REG_NOTES (insn));
+      emit_insn (insn);
+      emit_insn (gen_andsi3 (r1, r0, GEN_INT (~(HOST_WIDE_INT)7)));
+      emit_insn (gen_movsi (stack_pointer_rtx, r1));
+    }
+
+  if (frame_pointer_needed && TARGET_ARM)
     {
       if (IS_INTERRUPT (func_type))
        {
@@ -10742,7 +11411,8 @@ arm_expand_prologue (void)
      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
-      && ! frame_pointer_needed)
+      && ! frame_pointer_needed
+      && TARGET_ARM)
     {
       rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
       
@@ -10756,113 +11426,32 @@ arm_expand_prologue (void)
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
-  if (TARGET_IWMMXT)
-    for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
-      if (regs_ever_live[reg] && ! call_used_regs [reg])
-       {
-         insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
-         insn = gen_frame_mem (V2SImode, insn);
-         insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
-         RTX_FRAME_RELATED_P (insn) = 1;
-         saved_regs += 8;
-       }
-
   if (! IS_VOLATILE (func_type))
-    {
-      int start_reg;
+    saved_regs += arm_save_coproc_regs ();
 
-      /* Save any floating point call-saved registers used by this
-        function.  */
-      if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
-       {
-         for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
-           if (regs_ever_live[reg] && !call_used_regs[reg])
-             {
-               insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
-               insn = gen_frame_mem (XFmode, insn);
-               insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
-               RTX_FRAME_RELATED_P (insn) = 1;
-               saved_regs += 12;
-             }
-       }
-      else
-       {
-         start_reg = LAST_FPA_REGNUM;
-
-         for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
-           {
-             if (regs_ever_live[reg] && !call_used_regs[reg])
-               {
-                 if (start_reg - reg == 3)
-                   {
-                     insn = emit_sfm (reg, 4);
-                     RTX_FRAME_RELATED_P (insn) = 1;
-                     saved_regs += 48;
-                     start_reg = reg - 1;
-                   }
-               }
-             else
-               {
-                 if (start_reg != reg)
-                   {
-                     insn = emit_sfm (reg + 1, start_reg - reg);
-                     RTX_FRAME_RELATED_P (insn) = 1;
-                     saved_regs += (start_reg - reg) * 12;
-                   }
-                 start_reg = reg - 1;
-               }
-           }
-
-         if (start_reg != reg)
-           {
-             insn = emit_sfm (reg + 1, start_reg - reg);
-             saved_regs += (start_reg - reg) * 12;
-             RTX_FRAME_RELATED_P (insn) = 1;
-           }
-       }
-      if (TARGET_HARD_FLOAT && TARGET_VFP)
+  if (frame_pointer_needed && TARGET_ARM)
+    {
+      /* Create the new frame pointer.  */
        {
-         start_reg = FIRST_VFP_REGNUM;
+         insn = GEN_INT (-(4 + args_to_push + fp_offset));
+         insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
+         RTX_FRAME_RELATED_P (insn) = 1;
 
-         for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
+         if (IS_NESTED (func_type))
            {
-             if ((!regs_ever_live[reg] || call_used_regs[reg])
-                 && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
+             /* Recover the static chain register.  */
+             if (regs_ever_live [3] == 0
+                 || saved_pretend_args)
+               insn = gen_rtx_REG (SImode, 3);
+             else /* if (current_function_pretend_args_size == 0) */
                {
-                 if (start_reg != reg)
-                   saved_regs += vfp_emit_fstmx (start_reg,
-                                                 (reg - start_reg) / 2);
-                 start_reg = reg + 2;
+                 insn = plus_constant (hard_frame_pointer_rtx, 4);
+                 insn = gen_frame_mem (SImode, insn);
                }
+             emit_set_insn (ip_rtx, insn);
+             /* Add a USE to stop propagate_one_insn() from barfing.  */
+             emit_insn (gen_prologue_use (ip_rtx));
            }
-         if (start_reg != reg)
-           saved_regs += vfp_emit_fstmx (start_reg,
-                                         (reg - start_reg) / 2);
-       }
-    }
-
-  if (frame_pointer_needed)
-    {
-      /* Create the new frame pointer.  */
-      insn = GEN_INT (-(4 + args_to_push + fp_offset));
-      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
-      RTX_FRAME_RELATED_P (insn) = 1;
-
-      if (IS_NESTED (func_type))
-       {
-         /* Recover the static chain register.  */
-         if (regs_ever_live [3] == 0
-             || saved_pretend_args)
-           insn = gen_rtx_REG (SImode, 3);
-         else /* if (current_function_pretend_args_size == 0) */
-           {
-             insn = plus_constant (hard_frame_pointer_rtx, 4);
-             insn = gen_frame_mem (SImode, insn);
-           }
-
-         emit_set_insn (ip_rtx, insn);
-         /* Add a USE to stop propagate_one_insn() from barfing.  */
-         emit_insn (gen_prologue_use (ip_rtx));
        }
     }
 
@@ -10894,8 +11483,19 @@ arm_expand_prologue (void)
     }
 
 
+  if (frame_pointer_needed && TARGET_THUMB2)
+    thumb_set_frame_pointer (offsets);
+
   if (flag_pic && arm_pic_register != INVALID_REGNUM)
-    arm_load_pic_register (0UL);
+    {
+      unsigned long mask;
+
+      mask = live_regs_mask;
+      mask &= THUMB2_WORK_REGS;
+      if (!IS_NESTED (func_type))
+       mask |= (1 << IP_REGNUM);
+      arm_load_pic_register (mask);
+    }
 
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  Similarly if the user has requested no
@@ -10915,6 +11515,43 @@ arm_expand_prologue (void)
     }
 }
 \f
+/* Print condition code to STREAM.  Helper function for arm_print_operand.  */
+static void
+arm_print_condition (FILE *stream)
+{
+  if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
+    {
+      /* Branch conversion is not implemented for Thumb-2.  */
+      if (TARGET_THUMB)
+       {
+         output_operand_lossage ("predicated Thumb instruction");
+         return;
+       }
+      if (current_insn_predicate != NULL)
+       {
+         output_operand_lossage
+           ("predicated instruction in conditional sequence");
+         return;
+       }
+
+      fputs (arm_condition_codes[arm_current_cc], stream);
+    }
+  else if (current_insn_predicate)
+    {
+      enum arm_cond_code code;
+
+      if (TARGET_THUMB1)
+       {
+         output_operand_lossage ("predicated Thumb instruction");
+         return;
+       }
+
+      code = get_arm_condition_code (current_insn_predicate);
+      fputs (arm_condition_codes[code], stream);
+    }
+}
+
+
 /* If CODE is 'd', then the X is a condition operand and the instruction
    should only be executed if the condition is true.
    if CODE is 'D', then the X is a condition operand and the instruction
@@ -10946,37 +11583,46 @@ arm_print_operand (FILE *stream, rtx x, int code)
       return;
 
     case '?':
-      if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
-       {
-         if (TARGET_THUMB)
-           {
-             output_operand_lossage ("predicated Thumb instruction");
-             break;
-           }
-         if (current_insn_predicate != NULL)
-           {
-             output_operand_lossage
-               ("predicated instruction in conditional sequence");
-             break;
-           }
+      arm_print_condition (stream);
+      return;
+
+    case '(':
+      /* Nothing in unified syntax, otherwise the current condition code.  */
+      if (!TARGET_UNIFIED_ASM)
+       arm_print_condition (stream);
+      break;
 
-         fputs (arm_condition_codes[arm_current_cc], stream);
+    case ')':
+      /* The current condition code in unified syntax, otherwise nothing.  */
+      if (TARGET_UNIFIED_ASM)
+       arm_print_condition (stream);
+      break;
+  
+    case '.':
+      /* The current condition code for a condition code setting instruction.
+        Preceded by 's' in unified syntax, otherwise followed by 's'.  */
+      if (TARGET_UNIFIED_ASM)
+       {
+         fputc('s', stream);
+         arm_print_condition (stream);
        }
-      else if (current_insn_predicate)
+      else
        {
-         enum arm_cond_code code;
-
-         if (TARGET_THUMB)
-           {
-             output_operand_lossage ("predicated Thumb instruction");
-             break;
-           }
-
-         code = get_arm_condition_code (current_insn_predicate);
-         fputs (arm_condition_codes[code], stream);
+         arm_print_condition (stream);
+         fputc('s', stream);
        }
       return;
 
+    case '!':
+      /* If the instruction is conditionally executed then print
+        the current condition code, otherwise print 's'.  */
+      gcc_assert (TARGET_THUMB2 && TARGET_UNIFIED_ASM);
+      if (current_insn_predicate)
+       arm_print_condition (stream);
+      else
+       fputc('s', stream);
+      break;
+
     case 'N':
       {
        REAL_VALUE_TYPE r;
@@ -11000,6 +11646,11 @@ arm_print_operand (FILE *stream, rtx x, int code)
        }
       return;
 
+    case 'L':
+      /* The low 16 bits of an immediate constant.  */
+      fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL(x) & 0xffff);
+      return;
+
     case 'i':
       fprintf (stream, "%s", arithmetic_instr (x, 1));
       return;
@@ -11349,8 +12000,10 @@ arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
 /* Add a function to the list of static constructors.  */
 
 static void
-arm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
+arm_elf_asm_constructor (rtx symbol, int priority)
 {
+  section *s;
+
   if (!TARGET_AAPCS_BASED)
     {
       default_named_section_asm_out_constructor (symbol, priority);
@@ -11358,7 +12011,16 @@ arm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
     }
 
   /* Put these in the .init_array section, using a special relocation.  */
-  switch_to_section (ctors_section);
+  if (priority != DEFAULT_INIT_PRIORITY)
+    {
+      char buf[18];
+      sprintf (buf, ".init_array.%.5u", priority);
+      s = get_section (buf, SECTION_WRITE, NULL_TREE);
+    }
+  else
+    s = ctors_section;
+
+  switch_to_section (s);
   assemble_align (POINTER_SIZE);
   fputs ("\t.word\t", asm_out_file);
   output_addr_const (asm_out_file, symbol);
@@ -11397,6 +12059,13 @@ arm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
    time.  But then, I want to reduce the code size to somewhere near what
    /bin/cc produces.  */
 
+/* In addition to this, state is maintained for Thumb-2 COND_EXEC
+   instructions.  When a COND_EXEC instruction is seen the subsequent
+   instructions are scanned so that multiple conditional instructions can be
+   combined into a single IT block.  arm_condexec_count and arm_condexec_mask
+   specify the length and true/false mask for the IT block.  These will be
+   decremented/zeroed by arm_asm_output_opcode as the insns are output.  */
+
 /* Returns the index of the ARM condition code string in
    `arm_condition_codes'.  COMPARISON should be an rtx like
    `(eq (...) (...))'.  */
@@ -11526,6 +12195,85 @@ get_arm_condition_code (rtx comparison)
     }
 }
 
+/* Tell arm_asm_ouput_opcode to output IT blocks for conditionally executed
+   instructions.  */
+void
+thumb2_final_prescan_insn (rtx insn)
+{
+  rtx first_insn = insn;
+  rtx body = PATTERN (insn);
+  rtx predicate;
+  enum arm_cond_code code;
+  int n;
+  int mask;
+
+  /* Remove the previous insn from the count of insns to be output.  */
+  if (arm_condexec_count)
+      arm_condexec_count--;
+
+  /* Nothing to do if we are already inside a conditional block.  */
+  if (arm_condexec_count)
+    return;
+
+  if (GET_CODE (body) != COND_EXEC)
+    return;
+
+  /* Conditional jumps are implemented directly.  */
+  if (GET_CODE (insn) == JUMP_INSN)
+    return;
+
+  predicate = COND_EXEC_TEST (body);
+  arm_current_cc = get_arm_condition_code (predicate);
+
+  n = get_attr_ce_count (insn);
+  arm_condexec_count = 1;
+  arm_condexec_mask = (1 << n) - 1;
+  arm_condexec_masklen = n;
+  /* See if subsequent instructions can be combined into the same block.  */
+  for (;;)
+    {
+      insn = next_nonnote_insn (insn);
+
+      /* Jumping into the middle of an IT block is illegal, so a label or
+         barrier terminates the block.  */
+      if (GET_CODE (insn) != INSN && GET_CODE(insn) != JUMP_INSN)
+       break;
+
+      body = PATTERN (insn);
+      /* USE and CLOBBER aren't really insns, so just skip them.  */
+      if (GET_CODE (body) == USE
+         || GET_CODE (body) == CLOBBER)
+       continue;
+
+      /* ??? Recognize conditional jumps, and combine them with IT blocks.  */
+      if (GET_CODE (body) != COND_EXEC)
+       break;
+      /* Allow up to 4 conditionally executed instructions in a block.  */
+      n = get_attr_ce_count (insn);
+      if (arm_condexec_masklen + n > 4)
+       break;
+
+      predicate = COND_EXEC_TEST (body);
+      code = get_arm_condition_code (predicate);
+      mask = (1 << n) - 1;
+      if (arm_current_cc == code)
+       arm_condexec_mask |= (mask << arm_condexec_masklen);
+      else if (arm_current_cc != ARM_INVERSE_CONDITION_CODE(code))
+       break;
+
+      arm_condexec_count++;
+      arm_condexec_masklen += n;
+
+      /* A jump must be the last instruction in a conditional block.  */
+      if (GET_CODE(insn) == JUMP_INSN)
+       break;
+    }
+  /* Restore recog_data (getting the attributes of other insns can
+     destroy this array, but final.c assumes that it remains intact
+     across this call).  */
+  extract_constrain_insn_cached (first_insn);
+}
+
 void
 arm_final_prescan_insn (rtx insn)
 {
@@ -11830,7 +12578,7 @@ arm_final_prescan_insn (rtx insn)
              if (!this_insn)
                {
                  /* Oh, dear! we ran off the end.. give up.  */
-                 recog (PATTERN (insn), insn, NULL);
+                 extract_constrain_insn_cached (insn);
                  arm_ccfsm_state = 0;
                  arm_target_insn = NULL;
                  return;
@@ -11863,9 +12611,26 @@ arm_final_prescan_insn (rtx insn)
 
       /* Restore recog_data (getting the attributes of other insns can
         destroy this array, but final.c assumes that it remains intact
-        across this call; since the insn has been recognized already we
-        call recog direct).  */
-      recog (PATTERN (insn), insn, NULL);
+        across this call.  */
+      extract_constrain_insn_cached (insn);
+    }
+}
+
+/* Output IT instructions.  */
+void
+thumb2_asm_output_opcode (FILE * stream)
+{
+  char buff[5];
+  int n;
+
+  if (arm_condexec_mask)
+    {
+      for (n = 0; n < arm_condexec_masklen; n++)
+       buff[n] = (arm_condexec_mask & (1 << n)) ? 't' : 'e';
+      buff[n] = 0;
+      asm_fprintf(stream, "i%s\t%s\n\t", buff,
+                 arm_condition_codes[arm_current_cc]);
+      arm_condexec_mask = 0;
     }
 }
 
@@ -11879,7 +12644,7 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
            || (TARGET_HARD_FLOAT && TARGET_VFP
                && regno == VFPCC_REGNUM));
 
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     /* For the Thumb we only allow values bigger than SImode in
        registers 0 - 6, so that there is always a second low
        register available to hold the upper part of the value.
@@ -11936,10 +12701,12 @@ arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
          && regno <= LAST_FPA_REGNUM);
 }
 
+/* For efficiency and historical reasons LO_REGS, HI_REGS and CC_REGS are
+   not used in arm mode.  */
 int
 arm_regno_class (int regno)
 {
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
       if (regno == STACK_POINTER_REGNUM)
        return STACK_REG;
@@ -11950,13 +12717,16 @@ arm_regno_class (int regno)
       return HI_REGS;
     }
 
+  if (TARGET_THUMB2 && regno < 8)
+    return LO_REGS;
+
   if (   regno <= LAST_ARM_REGNUM
       || regno == FRAME_POINTER_REGNUM
       || regno == ARG_POINTER_REGNUM)
-    return GENERAL_REGS;
+    return TARGET_THUMB2 ? HI_REGS : GENERAL_REGS;
 
   if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
-    return NO_REGS;
+    return TARGET_THUMB2 ? CC_REG : NO_REGS;
 
   if (IS_CIRRUS_REGNUM (regno))
     return CIRRUS_REGS;
@@ -11995,6 +12765,7 @@ arm_debugger_arg_offset (int value, rtx addr)
 
   /* If we are using the stack pointer to point at the
      argument, then an offset of 0 is correct.  */
+  /* ??? Check this is consistent with thumb2 frame layout.  */
   if ((TARGET_THUMB || !frame_pointer_needed)
       && REGNO (addr) == SP_REGNUM)
     return 0;
@@ -12567,11 +13338,11 @@ safe_vector_operand (rtx x, enum machine_mode mode)
 
 static rtx
 arm_expand_binop_builtin (enum insn_code icode,
-                         tree arglist, rtx target)
+                         tree exp, rtx target)
 {
   rtx pat;
-  tree arg0 = TREE_VALUE (arglist);
-  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
+  tree arg1 = CALL_EXPR_ARG (exp, 1);
   rtx op0 = expand_normal (arg0);
   rtx op1 = expand_normal (arg1);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
@@ -12606,10 +13377,10 @@ arm_expand_binop_builtin (enum insn_code icode,
 
 static rtx
 arm_expand_unop_builtin (enum insn_code icode,
-                        tree arglist, rtx target, int do_load)
+                        tree exp, rtx target, int do_load)
 {
   rtx pat;
-  tree arg0 = TREE_VALUE (arglist);
+  tree arg0 = CALL_EXPR_ARG (exp, 0);
   rtx op0 = expand_normal (arg0);
   enum machine_mode tmode = insn_data[icode].operand[0].mode;
   enum machine_mode mode0 = insn_data[icode].operand[1].mode;
@@ -12651,8 +13422,7 @@ arm_expand_builtin (tree exp,
 {
   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              fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   tree              arg0;
   tree              arg1;
   tree              arg2;
@@ -12681,8 +13451,8 @@ arm_expand_builtin (tree exp,
               : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
               : CODE_FOR_iwmmxt_textrmw);
 
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg0 = CALL_EXPR_ARG (exp, 0);
+      arg1 = CALL_EXPR_ARG (exp, 1);
       op0 = expand_normal (arg0);
       op1 = expand_normal (arg1);
       tmode = insn_data[icode].operand[0].mode;
@@ -12713,9 +13483,9 @@ arm_expand_builtin (tree exp,
       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)));
+      arg0 = CALL_EXPR_ARG (exp, 0);
+      arg1 = CALL_EXPR_ARG (exp, 1);
+      arg2 = CALL_EXPR_ARG (exp, 2);
       op0 = expand_normal (arg0);
       op1 = expand_normal (arg1);
       op2 = expand_normal (arg2);
@@ -12745,15 +13515,15 @@ arm_expand_builtin (tree exp,
       return target;
 
     case ARM_BUILTIN_SETWCX:
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg0 = CALL_EXPR_ARG (exp, 0);
+      arg1 = CALL_EXPR_ARG (exp, 1);
       op0 = force_reg (SImode, expand_normal (arg0));
       op1 = expand_normal (arg1);
       emit_insn (gen_iwmmxt_tmcr (op1, op0));
       return 0;
 
     case ARM_BUILTIN_GETWCX:
-      arg0 = TREE_VALUE (arglist);
+      arg0 = CALL_EXPR_ARG (exp, 0);
       op0 = expand_normal (arg0);
       target = gen_reg_rtx (SImode);
       emit_insn (gen_iwmmxt_tmrc (target, op0));
@@ -12761,8 +13531,8 @@ arm_expand_builtin (tree exp,
 
     case ARM_BUILTIN_WSHUFH:
       icode = CODE_FOR_iwmmxt_wshufh;
-      arg0 = TREE_VALUE (arglist);
-      arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+      arg0 = CALL_EXPR_ARG (exp, 0);
+      arg1 = CALL_EXPR_ARG (exp, 1);
       op0 = expand_normal (arg0);
       op1 = expand_normal (arg1);
       tmode = insn_data[icode].operand[0].mode;
@@ -12788,13 +13558,13 @@ arm_expand_builtin (tree exp,
       return target;
 
     case ARM_BUILTIN_WSADB:
-      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, exp, target);
     case ARM_BUILTIN_WSADH:
-      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, exp, target);
     case ARM_BUILTIN_WSADBZ:
-      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, exp, target);
     case ARM_BUILTIN_WSADHZ:
-      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
+      return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, exp, target);
 
       /* Several three-argument builtins.  */
     case ARM_BUILTIN_WMACS:
@@ -12815,9 +13585,9 @@ arm_expand_builtin (tree exp,
               : 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)));
+      arg0 = CALL_EXPR_ARG (exp, 0);
+      arg1 = CALL_EXPR_ARG (exp, 1);
+      arg2 = CALL_EXPR_ARG (exp, 2);
       op0 = expand_normal (arg0);
       op1 = expand_normal (arg1);
       op2 = expand_normal (arg2);
@@ -12856,11 +13626,11 @@ arm_expand_builtin (tree exp,
 
   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);
+      return arm_expand_binop_builtin (d->icode, exp, 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);
+      return arm_expand_unop_builtin (d->icode, exp, target, 0);
 
   /* @@@ Should really do something sensible here.  */
   return NULL_RTX;
@@ -13271,7 +14041,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
 \f
 void
-thumb_final_prescan_insn (rtx insn)
+thumb1_final_prescan_insn (rtx insn)
 {
   if (flag_print_asm_name)
     asm_fprintf (asm_out_file, "%@ 0x%04x\n",
@@ -13398,7 +14168,7 @@ thumb_unexpanded_epilogue (void)
   if (IS_NAKED (arm_current_func_type ()))
     return "";
 
-  live_regs_mask = thumb_compute_save_reg_mask ();
+  live_regs_mask = thumb1_compute_save_reg_mask ();
   high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
 
   /* If we can deduce the registers used from the function's return value.
@@ -13636,10 +14406,9 @@ thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
     }
 }
 
-
 /* Generate the rest of a function's prologue.  */
 void
-thumb_expand_prologue (void)
+thumb1_expand_prologue (void)
 {
   rtx insn, dwarf;
 
@@ -13661,7 +14430,7 @@ thumb_expand_prologue (void)
       return;
     }
 
-  live_regs_mask = thumb_compute_save_reg_mask ();
+  live_regs_mask = thumb1_compute_save_reg_mask ();
   /* Load the pic register before setting the frame pointer,
      so we can use r7 as a temporary work register.  */
   if (flag_pic && arm_pic_register != INVALID_REGNUM)
@@ -13760,27 +14529,7 @@ thumb_expand_prologue (void)
     }
 
   if (frame_pointer_needed)
-    {
-      amount = offsets->outgoing_args - offsets->locals_base;
-
-      if (amount < 1024)
-       insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
-                                     stack_pointer_rtx, GEN_INT (amount)));
-      else
-       {
-         emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
-         insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
-                                       hard_frame_pointer_rtx,
-                                       stack_pointer_rtx));
-         dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
-                              plus_constant (stack_pointer_rtx, amount));
-         RTX_FRAME_RELATED_P (dwarf) = 1;
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
-                                               REG_NOTES (insn));
-       }
-
-      RTX_FRAME_RELATED_P (insn) = 1;
-    }
+    thumb_set_frame_pointer (offsets);
 
   /* If we are profiling, make sure no instructions are scheduled before
      the call to mcount.  Similarly if the user has requested no
@@ -13803,7 +14552,7 @@ thumb_expand_prologue (void)
 
 
 void
-thumb_expand_epilogue (void)
+thumb1_expand_epilogue (void)
 {
   HOST_WIDE_INT amount;
   arm_stack_offsets *offsets;
@@ -13855,7 +14604,7 @@ thumb_expand_epilogue (void)
 }
 
 static void
-thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
+thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
   unsigned long live_regs_mask = 0;
   unsigned long l_mask;
@@ -13941,7 +14690,7 @@ thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
     }
 
   /* Get the registers we are going to push.  */
-  live_regs_mask = thumb_compute_save_reg_mask ();
+  live_regs_mask = thumb1_compute_save_reg_mask ();
   /* Extract a mask of the ones we can give to the Thumb's push instruction.  */
   l_mask = live_regs_mask & 0x40ff;
   /* Then count how many other high registers will need to be pushed.  */
@@ -14402,10 +15151,116 @@ arm_asm_output_labelref (FILE *stream, const char *name)
 }
 
 static void
+arm_file_start (void)
+{
+  int val;
+
+  if (TARGET_UNIFIED_ASM)
+    asm_fprintf (asm_out_file, "\t.syntax unified\n");
+
+  if (TARGET_BPABI)
+    {
+      const char *fpu_name;
+      if (arm_select[0].string)
+       asm_fprintf (asm_out_file, "\t.cpu %s\n", arm_select[0].string);
+      else if (arm_select[1].string)
+       asm_fprintf (asm_out_file, "\t.arch %s\n", arm_select[1].string);
+      else
+       asm_fprintf (asm_out_file, "\t.cpu %s\n",
+                    all_cores[arm_default_cpu].name);
+
+      if (TARGET_SOFT_FLOAT)
+       {
+         if (TARGET_VFP)
+           fpu_name = "softvfp";
+         else
+           fpu_name = "softfpa";
+       }
+      else
+       {
+         switch (arm_fpu_arch)
+           {
+           case FPUTYPE_FPA:
+             fpu_name = "fpa";
+             break;
+           case FPUTYPE_FPA_EMU2:
+             fpu_name = "fpe2";
+             break;
+           case FPUTYPE_FPA_EMU3:
+             fpu_name = "fpe3";
+             break;
+           case FPUTYPE_MAVERICK:
+             fpu_name = "maverick";
+             break;
+           case FPUTYPE_VFP:
+             if (TARGET_HARD_FLOAT)
+               asm_fprintf (asm_out_file, "\t.eabi_attribute 27, 3\n");
+             if (TARGET_HARD_FLOAT_ABI)
+               asm_fprintf (asm_out_file, "\t.eabi_attribute 28, 1\n");
+             fpu_name = "vfp";
+             break;
+           default:
+             abort();
+           }
+       }
+      asm_fprintf (asm_out_file, "\t.fpu %s\n", fpu_name);
+
+      /* Some of these attributes only apply when the corresponding features
+         are used.  However we don't have any easy way of figuring this out.
+        Conservatively record the setting that would have been used.  */
+
+      /* Tag_ABI_PCS_wchar_t.  */
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 18, %d\n",
+                  (int)WCHAR_TYPE_SIZE / BITS_PER_UNIT);
+
+      /* Tag_ABI_FP_rounding.  */
+      if (flag_rounding_math)
+       asm_fprintf (asm_out_file, "\t.eabi_attribute 19, 1\n");
+      if (!flag_unsafe_math_optimizations)
+       {
+         /* Tag_ABI_FP_denomal.  */
+         asm_fprintf (asm_out_file, "\t.eabi_attribute 20, 1\n");
+         /* Tag_ABI_FP_exceptions.  */
+         asm_fprintf (asm_out_file, "\t.eabi_attribute 21, 1\n");
+       }
+      /* Tag_ABI_FP_user_exceptions.  */
+      if (flag_signaling_nans)
+       asm_fprintf (asm_out_file, "\t.eabi_attribute 22, 1\n");
+      /* Tag_ABI_FP_number_model.  */
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 23, %d\n", 
+                  flag_finite_math_only ? 1 : 3);
+
+      /* Tag_ABI_align8_needed.  */
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 24, 1\n");
+      /* Tag_ABI_align8_preserved.  */
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 25, 1\n");
+      /* Tag_ABI_enum_size.  */
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 26, %d\n",
+                  flag_short_enums ? 1 : 2);
+
+      /* Tag_ABI_optimization_goals.  */
+      if (optimize_size)
+       val = 4;
+      else if (optimize >= 2)
+       val = 2;
+      else if (optimize)
+       val = 1;
+      else
+       val = 6;
+      asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
+    }
+  default_file_start();
+}
+
+static void
 arm_file_end (void)
 {
   int regno;
 
+  if (NEED_INDICATE_EXEC_STACK)
+    /* Add .note.GNU-stack.  */
+    file_end_indicate_exec_stack ();
+
   if (! thumb_call_reg_needed)
     return;
 
@@ -14721,7 +15576,8 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
                     ? 1 : 0);
   if (mi_delta < 0)
     mi_delta = - mi_delta;
-  if (TARGET_THUMB)
+  /* When generating 16-bit thumb code, thunks are entered in arm mode.  */
+  if (TARGET_THUMB1)
     {
       int labelno = thunk_label++;
       ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
@@ -14746,6 +15602,7 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
          fputs ("\tadd\tr12, pc, r12\n", file);
        }
     }
+  /* TODO: Use movw/movt for large constants when available.  */
   while (mi_delta != 0)
     {
       if ((mi_delta & (3 << shift)) == 0)
@@ -14759,7 +15616,7 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
           shift += 8;
         }
     }
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
       fprintf (file, "\tbx\tr12\n");
       ASM_OUTPUT_ALIGN (file, 2);
@@ -15148,22 +16005,26 @@ thumb_set_return_address (rtx source, rtx scratch)
 {
   arm_stack_offsets *offsets;
   HOST_WIDE_INT delta;
+  HOST_WIDE_INT limit;
   int reg;
   rtx addr;
   unsigned long mask;
 
   emit_insn (gen_rtx_USE (VOIDmode, source));
 
-  mask = thumb_compute_save_reg_mask ();
+  mask = thumb1_compute_save_reg_mask ();
   if (mask & (1 << LR_REGNUM))
     {
       offsets = arm_get_frame_offsets ();
 
+      limit = 1024;
       /* Find the saved regs.  */
       if (frame_pointer_needed)
        {
          delta = offsets->soft_frame - offsets->saved_args;
          reg = THUMB_HARD_FRAME_POINTER_REGNUM;
+         if (TARGET_THUMB1)
+           limit = 128;
        }
       else
        {
@@ -15171,15 +16032,14 @@ thumb_set_return_address (rtx source, rtx scratch)
          reg = SP_REGNUM;
        }
       /* Allow for the stack frame.  */
-      if (TARGET_BACKTRACE)
+      if (TARGET_THUMB1 && TARGET_BACKTRACE)
        delta -= 16;
       /* The link register is always the first saved register.  */
       delta -= 4;
 
       /* Construct the address.  */
       addr = gen_rtx_REG (SImode, reg);
-      if ((reg != SP_REGNUM && delta >= 128)
-         || delta >= 1024)
+      if (delta > limit)
        {
          emit_insn (gen_movsi (scratch, GEN_INT (delta)));
          emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
@@ -15245,12 +16105,13 @@ arm_dbx_register_number (unsigned int regno)
 
 
 #ifdef TARGET_UNWIND_INFO
-/* Emit unwind directives for a store-multiple instruction.  This should
-   only ever be generated by the function prologue code, so we expect it
-   to have a particular form.  */
+/* Emit unwind directives for a store-multiple instruction or stack pointer
+   push during alignment.
+   These should only ever be generated by the function prologue code, so
+   expect them to have a particular form.  */
 
 static void
-arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
+arm_unwind_emit_sequence (FILE * asm_out_file, rtx p)
 {
   int i;
   HOST_WIDE_INT offset;
@@ -15260,8 +16121,11 @@ arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
   unsigned lastreg;
   rtx e;
 
-  /* First insn will adjust the stack pointer.  */
   e = XVECEXP (p, 0, 0);
+  if (GET_CODE (e) != SET)
+    abort ();
+
+  /* First insn will adjust the stack pointer.  */
   if (GET_CODE (e) != SET
       || GET_CODE (XEXP (e, 0)) != REG
       || REGNO (XEXP (e, 0)) != SP_REGNUM
@@ -15282,12 +16146,12 @@ arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
          offset -= 4;
        }
       reg_size = 4;
+      fprintf (asm_out_file, "\t.save {");
     }
   else if (IS_VFP_REGNUM (reg))
     {
-      /* FPA register saves use an additional word.  */
-      offset -= 4;
       reg_size = 8;
+      fprintf (asm_out_file, "\t.vsave {");
     }
   else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
     {
@@ -15304,8 +16168,6 @@ arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
   if (offset != nregs * reg_size)
     abort ();
 
-  fprintf (asm_out_file, "\t.save {");
-
   offset = 0;
   lastreg = 0;
   /* The remaining insns will describe the stores.  */
@@ -15360,6 +16222,7 @@ arm_unwind_emit_set (FILE * asm_out_file, rtx p)
 {
   rtx e0;
   rtx e1;
+  unsigned reg;
 
   e0 = XEXP (p, 0);
   e1 = XEXP (p, 1);
@@ -15396,7 +16259,6 @@ arm_unwind_emit_set (FILE * asm_out_file, rtx p)
       else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
        {
          HOST_WIDE_INT offset;
-         unsigned reg;
 
          if (GET_CODE (e1) == PLUS)
            {
@@ -15432,6 +16294,13 @@ arm_unwind_emit_set (FILE * asm_out_file, rtx p)
          asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
                       REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
        }
+      else if (GET_CODE (e1) == UNSPEC && XINT (e1, 1) == UNSPEC_STACK_ALIGN)
+       {
+         /* Stack pointer save before alignment.  */
+         reg = REGNO (e0);
+         asm_fprintf (asm_out_file, "\t.unwind_raw 0, 0x%x @ vsp = r%d\n",
+                      reg + 0x90, reg);
+       }
       else
        abort ();
       break;
@@ -15469,7 +16338,7 @@ arm_unwind_emit (FILE * asm_out_file, rtx insn)
 
     case SEQUENCE:
       /* Store multiple.  */
-      arm_unwind_emit_stm (asm_out_file, pat);
+      arm_unwind_emit_sequence (asm_out_file, pat);
       break;
 
     default:
@@ -15497,6 +16366,30 @@ arm_output_ttype (rtx x)
 #endif /* TARGET_UNWIND_INFO */
 
 
+/* Handle UNSPEC DWARF call frame instructions.  These are needed for dynamic
+   stack alignment.  */
+
+static void
+arm_dwarf_handle_frame_unspec (const char *label, rtx pattern, int index)
+{
+  rtx unspec = SET_SRC (pattern);
+  gcc_assert (GET_CODE (unspec) == UNSPEC);
+
+  switch (index)
+    {
+    case UNSPEC_STACK_ALIGN:
+      /* ??? We should set the CFA = (SP & ~7).  At this point we haven't
+         put anything on the stack, so hopefully it won't matter.
+         CFA = SP will be correct after alignment.  */
+      dwarf2out_reg_save_reg (label, stack_pointer_rtx,
+                              SET_DEST (pattern));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
 /* Output unwind directives for the start/end of a function.  */
 
 void
@@ -15582,4 +16475,71 @@ arm_output_addr_const_extra (FILE *fp, rtx x)
   return FALSE;
 }
 
+/* Output assembly for a shift instruction.
+   SET_FLAGS determines how the instruction modifies the condition codes.
+   0 - Do not set condition codes.
+   1 - Set condition codes.
+   2 - Use smallest instruction.  */
+const char *
+arm_output_shift(rtx * operands, int set_flags)
+{
+  char pattern[100];
+  static const char flag_chars[3] = {'?', '.', '!'};
+  const char *shift;
+  HOST_WIDE_INT val;
+  char c;
+  
+  c = flag_chars[set_flags];
+  if (TARGET_UNIFIED_ASM)
+    {
+      shift = shift_op(operands[3], &val);
+      if (shift)
+       {
+         if (val != -1)
+           operands[2] = GEN_INT(val);
+         sprintf (pattern, "%s%%%c\t%%0, %%1, %%2", shift, c);
+       }
+      else
+       sprintf (pattern, "mov%%%c\t%%0, %%1", c);
+    }
+  else
+    sprintf (pattern, "mov%%%c\t%%0, %%1%%S3", c);
+  output_asm_insn (pattern, operands);
+  return "";
+}
+
+/* Output a Thumb-2 casesi instruction.  */
+const char *
+thumb2_output_casesi (rtx *operands)
+{
+  rtx diff_vec = PATTERN (next_real_insn (operands[2]));
+
+  gcc_assert (GET_CODE (diff_vec) == ADDR_DIFF_VEC);
+
+  output_asm_insn ("cmp\t%0, %1", operands);
+  output_asm_insn ("bhi\t%l3", operands);
+  switch (GET_MODE(diff_vec))
+    {
+    case QImode:
+      return "tbb\t[%|pc, %0]";
+    case HImode:
+      return "tbh\t[%|pc, %0, lsl #1]";
+    case SImode:
+      if (flag_pic)
+       {
+         output_asm_insn ("adr\t%4, %l2", operands);
+         output_asm_insn ("ldr\t%5, [%4, %0, lsl #2]", operands);
+         output_asm_insn ("add\t%4, %4, %5", operands);
+         return "bx\t%4";
+       }
+      else
+       {
+         output_asm_insn ("adr\t%4, %l2", operands);
+         return "ldr\t%|pc, [%4, %0, lsl #2]";
+       }
+    default:
+      gcc_unreachable ();
+    }
+}
+
 #include "gt-arm.h"