OSDN Git Service

gcc/cp/
[pf3gnuchains/gcc-fork.git] / gcc / config / arm / arm.c
index f36b726..d64b6fd 100644 (file)
@@ -1,6 +1,6 @@
 /* Output routines for GCC for ARM.
    Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008 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).
@@ -59,6 +59,8 @@ typedef struct minipool_fixup   Mfix;
 
 const struct attribute_spec arm_attribute_table[];
 
+void (*arm_lang_output_object_attributes_hook)(void);
+
 /* Forward function declarations.  */
 static arm_stack_offsets *arm_get_frame_offsets (void);
 static void arm_add_gc_roots (void);
@@ -72,13 +74,10 @@ 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);
-#ifndef AOF_ASSEMBLER
+static unsigned arm_size_return_regs (void);
 static bool arm_assemble_integer (rtx, unsigned int, int);
-#endif
 static const char *fp_const_from_val (REAL_VALUE_TYPE *);
 static arm_cc get_arm_condition_code (rtx);
 static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
@@ -158,14 +157,6 @@ static void arm_encode_section_info (tree, rtx, int);
 static void arm_file_end (void);
 static void arm_file_start (void);
 
-#ifdef AOF_ASSEMBLER
-static void aof_globalize_label (FILE *, const char *);
-static void aof_dump_imports (FILE *);
-static void aof_dump_pic_table (FILE *);
-static void aof_file_start (void);
-static void aof_file_end (void);
-static void aof_asm_init_sections (void);
-#endif
 static void arm_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
                                        tree, int *, int);
 static bool arm_pass_by_reference (CUMULATIVE_ARGS *,
@@ -175,6 +166,7 @@ static bool arm_default_short_enums (void);
 static bool arm_align_anon_bitfield (void);
 static bool arm_return_in_msb (const_tree);
 static bool arm_must_pass_in_stack (enum machine_mode, const_tree);
+static bool arm_return_in_memory (const_tree, const_tree);
 #ifdef TARGET_UNWIND_INFO
 static void arm_unwind_emit (FILE *, rtx);
 static bool arm_output_ttype (rtx);
@@ -196,7 +188,9 @@ static void arm_target_help (void);
 static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
 static bool arm_cannot_copy_insn_p (rtx);
 static bool arm_tls_symbol_p (rtx x);
+static int arm_issue_rate (void);
 static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
+static bool arm_allocate_stack_slots_for_args (void);
 
 \f
 /* Initialize the GCC target structure.  */
@@ -213,25 +207,10 @@ static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 #undef TARGET_ASM_FILE_END
 #define TARGET_ASM_FILE_END arm_file_end
 
-#ifdef AOF_ASSEMBLER
-#undef  TARGET_ASM_BYTE_OP
-#define TARGET_ASM_BYTE_OP "\tDCB\t"
-#undef  TARGET_ASM_ALIGNED_HI_OP
-#define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
-#undef  TARGET_ASM_ALIGNED_SI_OP
-#define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
-#undef TARGET_ASM_GLOBALIZE_LABEL
-#define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
-#undef TARGET_ASM_FILE_START
-#define TARGET_ASM_FILE_START aof_file_start
-#undef TARGET_ASM_FILE_END
-#define TARGET_ASM_FILE_END aof_file_end
-#else
 #undef  TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP NULL
 #undef  TARGET_ASM_INTEGER
 #define TARGET_ASM_INTEGER arm_assemble_integer
-#endif
 
 #undef  TARGET_ASM_FUNCTION_PROLOGUE
 #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
@@ -312,6 +291,9 @@ static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 #undef  TARGET_SETUP_INCOMING_VARARGS
 #define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
 
+#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS
+#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS arm_allocate_stack_slots_for_args
+
 #undef TARGET_DEFAULT_SHORT_ENUMS
 #define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums
 
@@ -352,6 +334,9 @@ static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 #undef TARGET_RETURN_IN_MSB
 #define TARGET_RETURN_IN_MSB arm_return_in_msb
 
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY arm_return_in_memory
+
 #undef TARGET_MUST_PASS_IN_STACK
 #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
 
@@ -381,6 +366,9 @@ static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
 #undef TARGET_CANNOT_FORCE_CONST_MEM
 #define TARGET_CANNOT_FORCE_CONST_MEM arm_cannot_force_const_mem
 
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE arm_issue_rate
+
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE arm_mangle_type
 
@@ -483,6 +471,7 @@ static int thumb_call_reg_needed;
 #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_ARCH6M  (FL_FOR_ARCH6 & ~FL_NOTM)
 #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)
@@ -655,6 +644,7 @@ static const struct processors all_architectures[] =
   {"armv6z",  arm1176jzs, "6Z",  FL_CO_PROC |             FL_FOR_ARCH6Z, NULL},
   {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC |             FL_FOR_ARCH6ZK, NULL},
   {"armv6t2", arm1156t2s, "6T2", FL_CO_PROC |             FL_FOR_ARCH6T2, NULL},
+  {"armv6-m", cortexm1,          "6M",                           FL_FOR_ARCH6M, NULL},
   {"armv7",   cortexa8,          "7",   FL_CO_PROC |             FL_FOR_ARCH7, NULL},
   {"armv7-a", cortexa8,          "7A",  FL_CO_PROC |             FL_FOR_ARCH7A, NULL},
   {"armv7-r", cortexr4,          "7R",  FL_CO_PROC |             FL_FOR_ARCH7R, NULL},
@@ -1637,6 +1627,14 @@ arm_current_func_type (void)
 
   return cfun->machine->func_type;
 }
+
+bool
+arm_allocate_stack_slots_for_args (void)
+{
+  /* Naked functions should not allocate stack slots for arguments.  */
+  return !IS_NAKED (arm_current_func_type ());
+}
+
 \f
 /* Return 1 if it is possible to return using a single instruction.
    If SIBLING is non-null, this is a test for a return before a sibling
@@ -1671,18 +1669,19 @@ use_return_insn (int iscond, rtx sibling)
   stack_adjust = offsets->outgoing_args - offsets->saved_regs;
 
   /* As do variadic functions.  */
-  if (current_function_pretend_args_size
+  if (crtl->args.pretend_args_size
       || cfun->machine->uses_anonymous_args
       /* Or if the function calls __builtin_eh_return () */
-      || current_function_calls_eh_return
+      || crtl->calls_eh_return
       /* Or if the function calls alloca */
-      || current_function_calls_alloca
+      || cfun->calls_alloca
       /* Or if there is a stack adjustment.  However, if the stack pointer
         is saved on the stack, we can use a pre-incrementing stack load.  */
-      || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
+      || !(stack_adjust == 0 || (TARGET_APCS_FRAME && frame_pointer_needed
+                                && stack_adjust == 4)))
     return 0;
 
-  saved_int_regs = arm_compute_save_reg_mask ();
+  saved_int_regs = offsets->saved_regs_mask;
 
   /* Unfortunately, the insn
 
@@ -2752,10 +2751,10 @@ arm_apply_result_size (void)
 }
 
 /* Decide whether a type should be returned in memory (true)
-   or in a register (false).  This is called by the macro
-   RETURN_IN_MEMORY.  */
-int
-arm_return_in_memory (const_tree type)
+   or in a register (false).  This is called as the target hook
+   TARGET_RETURN_IN_MEMORY.  */
+static bool
+arm_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT size;
 
@@ -2818,7 +2817,7 @@ arm_return_in_memory (const_tree type)
 
       /* ... Aggregates that are not themselves valid for returning in
         a register are not allowed.  */
-      if (RETURN_IN_MEMORY (TREE_TYPE (field)))
+      if (arm_return_in_memory (TREE_TYPE (field), NULL_TREE))
        return 1;
 
       /* Now check the remaining fields, if any.  Only bitfields are allowed,
@@ -2853,7 +2852,7 @@ arm_return_in_memory (const_tree type)
          if (FLOAT_TYPE_P (TREE_TYPE (field)))
            return 1;
 
-         if (RETURN_IN_MEMORY (TREE_TYPE (field)))
+         if (arm_return_in_memory (TREE_TYPE (field), NULL_TREE))
            return 1;
        }
 
@@ -3390,7 +3389,7 @@ require_pic_register (void)
      We don't want those calls to affect any assumptions about the real
      function; and further, we can't call entry_of_function() until we
      start the real expansion process.  */
-  if (!current_function_uses_pic_offset_table)
+  if (!crtl->uses_pic_offset_table)
     {
       gcc_assert (can_create_pseudo_p ());
       if (arm_pic_register != INVALID_REGNUM)
@@ -3401,7 +3400,7 @@ require_pic_register (void)
             if we are being called as part of the cost-estimation
             process.  */
          if (current_ir_type () != IR_GIMPLE)
-           current_function_uses_pic_offset_table = 1;
+           crtl->uses_pic_offset_table = 1;
        }
       else
        {
@@ -3414,7 +3413,7 @@ require_pic_register (void)
             process.  */
          if (current_ir_type () != IR_GIMPLE)
            {
-             current_function_uses_pic_offset_table = 1;
+             crtl->uses_pic_offset_table = 1;
              start_sequence ();
 
              arm_load_pic_register (0UL);
@@ -3433,9 +3432,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
   if (GET_CODE (orig) == SYMBOL_REF
       || GET_CODE (orig) == LABEL_REF)
     {
-#ifndef AOF_ASSEMBLER
       rtx pic_ref, address;
-#endif
       rtx insn;
       int subregs = 0;
 
@@ -3450,11 +3447,6 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          subregs = 1;
        }
 
-#ifdef AOF_ASSEMBLER
-      /* The AOF assembler can generate relocations for these directly, and
-        understands that the PIC register has to be added into the offset.  */
-      insn = emit_insn (gen_pic_load_addr_based (reg, orig));
-#else
       if (subregs)
        address = gen_reg_rtx (Pmode);
       else
@@ -3487,7 +3479,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
        }
 
       insn = emit_move_insn (reg, pic_ref);
-#endif
+
       /* Put a REG_EQUAL note on this insn, so that it can be optimized
         by loop.  */
       set_unique_reg_note (insn, REG_EQUAL, orig);
@@ -3568,15 +3560,15 @@ thumb_find_work_register (unsigned long pushed_regs_mask)
      the variable argument list and so we can be sure that it will be
      pushed right at the start of the function.  Hence it will be available
      for the rest of the prologue.
-     (*): ie current_function_pretend_args_size is greater than 0.  */
+     (*): ie crtl->args.pretend_args_size is greater than 0.  */
   if (cfun->machine->uses_anonymous_args
-      && current_function_pretend_args_size > 0)
+      && crtl->args.pretend_args_size > 0)
     return LAST_ARG_REGNUM;
 
   /* The other case is when we have fixed arguments but less than 4 registers
      worth.  In this case r3 might be used in the body of the function, but
      it is not being used to convey an argument into the function.  In theory
-     we could just check current_function_args_size to see how many bytes are
+     we could just check crtl->args.size to see how many bytes are
      being passed in argument registers, but it seems that it is unreliable.
      Sometimes it will have the value 0 when in fact arguments are being
      passed.  (See testcase execute/20021111-1.c for an example).  So we also
@@ -3586,9 +3578,9 @@ thumb_find_work_register (unsigned long pushed_regs_mask)
      when a function has an unused argument in r3.  But it is better to be
      safe than to be sorry.  */
   if (! cfun->machine->uses_anonymous_args
-      && current_function_args_size >= 0
-      && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
-      && cfun->args_info.nregs < 4)
+      && crtl->args.size >= 0
+      && crtl->args.size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
+      && crtl->args.info.nregs < 4)
     return LAST_ARG_REGNUM;
 
   /* Otherwise look for a call-saved register that is going to be pushed.  */
@@ -3616,11 +3608,10 @@ static GTY(()) int pic_labelno;
 void
 arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
 {
-#ifndef AOF_ASSEMBLER
   rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx, pic_reg;
   rtx global_offset_table;
 
-  if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
+  if (crtl->uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
     return;
 
   gcc_assert (flag_pic);
@@ -3706,8 +3697,7 @@ arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
 
   /* Need to emit this whether or not we obey regdecls,
      since setjmp/longjmp can cause life info to screw up.  */
-  emit_insn (gen_rtx_USE (VOIDmode, pic_reg));
-#endif /* AOF_ASSEMBLER */
+  emit_use (pic_reg);
 }
 
 
@@ -4930,6 +4920,12 @@ arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
       /* Fall through */
 
     case PLUS:
+      if (arm_arch6 && mode == SImode
+         && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
+             || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
+       return 1 + (GET_CODE (XEXP (XEXP (x, 0), 0)) == MEM ? 10 : 0)
+                + (GET_CODE (XEXP (x, 1)) == MEM ? 10 : 0);
+
       if (GET_CODE (XEXP (x, 0)) == MULT)
        {
          extra_cost = rtx_cost (XEXP (x, 0), code);
@@ -5028,12 +5024,17 @@ 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 (arm_arch_thumb2 && mode == SImode)
+       return 1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0);
+
       if (GET_MODE (XEXP (x, 0)) == QImode)
        return (4 + (mode == DImode ? 4 : 0)
                + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
       /* Fall through */
     case ZERO_EXTEND:
+      if (arm_arch6 && mode == SImode)
+       return 1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0);
+
       switch (GET_MODE (XEXP (x, 0)))
        {
        case QImode:
@@ -5096,13 +5097,14 @@ arm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
   enum machine_mode mode = GET_MODE (x);
 
-  if (TARGET_THUMB)
+  if (TARGET_THUMB1)
     {
       /* XXX TBD.  For now, use the standard costs.  */
       *total = thumb1_rtx_costs (x, code, outer_code);
       return true;
     }
 
+  /* FIXME: This makes no attempt to prefer narrow Thumb-2 instructions.  */
   switch (code)
     {
     case MEM:
@@ -9105,14 +9107,6 @@ push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
 {
   Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
-#ifdef AOF_ASSEMBLER
-  /* PIC symbol references need to be converted into offsets into the
-     based area.  */
-  /* XXX This shouldn't be done here.  */
-  if (flag_pic && GET_CODE (value) == SYMBOL_REF)
-    value = aof_pic_entry (value);
-#endif /* AOF_ASSEMBLER */
-
   fix->insn = insn;
   fix->address = address;
   fix->loc = loc;
@@ -9902,7 +9896,10 @@ output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[1], 0)))
        {
        case REG:
-         output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("ldr%(d%)\t%0, [%m1]", operands);
+         else
+           output_asm_insn ("ldm%(ia%)\t%m1, %M0", operands);
          break;
 
        case PRE_INC:
@@ -9918,7 +9915,10 @@ output_move_double (rtx *operands)
          break;
 
        case POST_INC:
-         output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("ldr%(d%)\t%0, [%m1], #8", operands);
+         else
+           output_asm_insn ("ldm%(ia%)\t%m1!, %M0", operands);
          break;
 
        case POST_DEC:
@@ -9977,8 +9977,14 @@ output_move_double (rtx *operands)
 
        case LABEL_REF:
        case CONST:
+         /* We might be able to use ldrd %0, %1 here.  However the range is
+            different to ldr/adr, and it is broken on some ARMv7-M
+            implementations.  */
          output_asm_insn ("adr%?\t%0, %1", operands);
-         output_asm_insn ("ldm%(ia%)\t%0, %M0", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("ldr%(d%)\t%0, [%0]", operands);
+         else
+           output_asm_insn ("ldm%(ia%)\t%0, %M0", operands);
          break;
 
          /* ??? This needs checking for thumb2.  */
@@ -9992,7 +9998,7 @@ output_move_double (rtx *operands)
 
              if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
                {
-                 if (GET_CODE (otherops[2]) == CONST_INT)
+                 if (GET_CODE (otherops[2]) == CONST_INT && !TARGET_LDRD)
                    {
                      switch ((int) INTVAL (otherops[2]))
                        {
@@ -10051,6 +10057,9 @@ output_move_double (rtx *operands)
              else
                output_asm_insn ("sub%?\t%0, %1, %2", otherops);
 
+             if (TARGET_LDRD)
+               return "ldr%(d%)\t%0, [%0]";
+
              return "ldm%(ia%)\t%0, %M0";
            }
          else
@@ -10079,7 +10088,10 @@ output_move_double (rtx *operands)
       switch (GET_CODE (XEXP (operands[0], 0)))
         {
        case REG:
-         output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("str%(d%)\t%1, [%m0]", operands);
+         else
+           output_asm_insn ("stm%(ia%)\t%m0, %M1", operands);
          break;
 
         case PRE_INC:
@@ -10095,7 +10107,10 @@ output_move_double (rtx *operands)
          break;
 
         case POST_INC:
-         output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
+         if (TARGET_LDRD)
+           output_asm_insn ("str%(d%)\t%1, [%m0], #8", operands);
+         else
+           output_asm_insn ("stm%(ia%)\t%m0!, %M1", operands);
          break;
 
         case POST_DEC:
@@ -10139,7 +10154,7 @@ output_move_double (rtx *operands)
 
        case PLUS:
          otherops[2] = XEXP (XEXP (operands[0], 0), 1);
-         if (GET_CODE (otherops[2]) == CONST_INT)
+         if (GET_CODE (otherops[2]) == CONST_INT && !TARGET_LDRD)
            {
              switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
                {
@@ -10735,30 +10750,19 @@ arm_compute_save_reg0_reg12_mask (void)
       if (flag_pic
          && !TARGET_SINGLE_PIC_BASE
          && arm_pic_register != INVALID_REGNUM
-         && current_function_uses_pic_offset_table)
+         && crtl->uses_pic_offset_table)
        save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
     }
   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 <= last_reg; reg++)
+      for (reg = 0; reg <= 11; reg++)
        if (df_regs_ever_live_p (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
-         && df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM)
-         && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-       save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
-      else if (! TARGET_APCS_FRAME
-              && ! frame_pointer_needed
-              && df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM)
-              && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
+      if (frame_pointer_needed)
        save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
 
       /* If we aren't loading the PIC register,
@@ -10767,7 +10771,7 @@ arm_compute_save_reg0_reg12_mask (void)
          && !TARGET_SINGLE_PIC_BASE
          && arm_pic_register != INVALID_REGNUM
          && (df_regs_ever_live_p (PIC_OFFSET_TABLE_REGNUM)
-             || current_function_uses_pic_offset_table))
+             || crtl->uses_pic_offset_table))
        save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
 
       /* The prologue will copy SP into R0, so save it.  */
@@ -10776,7 +10780,7 @@ arm_compute_save_reg0_reg12_mask (void)
     }
 
   /* Save registers so the exception handler can modify them.  */
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     {
       unsigned int i;
 
@@ -10794,7 +10798,8 @@ arm_compute_save_reg0_reg12_mask (void)
 
 
 /* Compute a bit mask of which registers need to be
-   saved on the stack for the current function.  */
+   saved on the stack for the current function.
+   This is used by arm_get_frame_offsets, which may add extra registers.  */
 
 static unsigned long
 arm_compute_save_reg_mask (void)
@@ -10809,7 +10814,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 && TARGET_ARM)
+  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
     save_reg_mask |=
       (1 << ARM_HARD_FRAME_POINTER_REGNUM)
       | (1 << IP_REGNUM)
@@ -10836,7 +10841,7 @@ arm_compute_save_reg_mask (void)
       || (save_reg_mask
          && optimize_size
          && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
-         && !current_function_calls_eh_return))
+         && !crtl->calls_eh_return))
     save_reg_mask |= 1 << LR_REGNUM;
 
   if (cfun->machine->lr_save_eliminated)
@@ -10844,7 +10849,7 @@ arm_compute_save_reg_mask (void)
 
   if (TARGET_REALLY_IWMMXT
       && ((bit_count (save_reg_mask)
-          + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
+          + ARM_NUM_INTS (crtl->args.pretend_args_size)) % 2) != 0)
     {
       /* The total number of registers that are going to be pushed
         onto the stack is odd.  We need to ensure that the stack
@@ -10898,7 +10903,7 @@ thumb1_compute_save_reg_mask (void)
   if (flag_pic
       && !TARGET_SINGLE_PIC_BASE
       && arm_pic_register != INVALID_REGNUM
-      && current_function_uses_pic_offset_table)
+      && crtl->uses_pic_offset_table)
     mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
 
   /* See if we might need r11 for calls to _interwork_r11_call_via_rN().  */
@@ -10922,7 +10927,7 @@ thumb1_compute_save_reg_mask (void)
       reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
       /* Make sure the register returned by thumb_find_work_register is
         not part of the return value.  */
-      if (reg * UNITS_PER_WORD <= arm_size_return_regs ())
+      if (reg * UNITS_PER_WORD <= (unsigned) arm_size_return_regs ())
        reg = LAST_LO_REGNUM;
 
       if (! call_used_regs[reg])
@@ -11013,13 +11018,14 @@ output_return_instruction (rtx operand, int really_return, int reverse)
       return "";
     }
 
-  gcc_assert (!current_function_calls_alloca || really_return);
+  gcc_assert (!cfun->calls_alloca || really_return);
 
   sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
 
   return_used_this_function = 1;
 
-  live_regs_mask = arm_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  live_regs_mask = offsets->saved_regs_mask;
 
   if (live_regs_mask)
     {
@@ -11081,7 +11087,6 @@ output_return_instruction (rtx operand, int really_return, int reverse)
            {
              unsigned HOST_WIDE_INT stack_adjust;
 
-             offsets = arm_get_frame_offsets ();
              stack_adjust = offsets->outgoing_args - offsets->saved_regs;
              gcc_assert (stack_adjust == 0 || stack_adjust == 4);
 
@@ -11269,8 +11274,8 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
     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,
-              current_function_pretend_args_size, frame_size);
+              crtl->args.size,
+              crtl->args.pretend_args_size, frame_size);
 
   asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
               frame_pointer_needed,
@@ -11279,14 +11284,9 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
   if (cfun->machine->lr_save_eliminated)
     asm_fprintf (f, "\t%@ link register save eliminated.\n");
 
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
 
-#ifdef AOF_ASSEMBLER
-  if (flag_pic)
-    asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
-#endif
-
   return_used_this_function = 0;
 }
 
@@ -11331,10 +11331,10 @@ arm_output_epilogue (rtx sibling)
 
   /* If we are throwing an exception, then we really must be doing a
      return, so we can't tail-call.  */
-  gcc_assert (!current_function_calls_eh_return || really_return);
+  gcc_assert (!crtl->calls_eh_return || really_return);
 
   offsets = arm_get_frame_offsets ();
-  saved_regs_mask = arm_compute_save_reg_mask ();
+  saved_regs_mask = offsets->saved_regs_mask;
 
   if (TARGET_IWMMXT)
     lrm_count = bit_count (saved_regs_mask);
@@ -11345,7 +11345,7 @@ arm_output_epilogue (rtx sibling)
     if (saved_regs_mask & (1 << reg))
       floats_offset += 4;
 
-  if (frame_pointer_needed && TARGET_ARM)
+  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
     {
       /* This variable is for the Virtual Frame Pointer, not VFP regs.  */
       int vfp_offset = offsets->frame;
@@ -11462,7 +11462,7 @@ arm_output_epilogue (rtx sibling)
         special function exit sequence, or we are not really returning.  */
       if (really_return
          && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
-         && !current_function_calls_eh_return)
+         && !crtl->calls_eh_return)
        /* Delete the LR from the register mask, so that the LR on
           the stack is loaded into the PC in the register mask.  */
        saved_regs_mask &= ~ (1 << LR_REGNUM);
@@ -11479,7 +11479,7 @@ arm_output_epilogue (rtx sibling)
          occur.  If the stack pointer already points at the right
          place, then omit the subtraction.  */
       if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
-         || current_function_calls_alloca)
+         || cfun->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, 0);
@@ -11491,32 +11491,87 @@ arm_output_epilogue (rtx sibling)
     }
   else
     {
+      /* This branch is executed for ARM mode (non-apcs frames) and
+        Thumb-2 mode. Frame layout is essentially the same for those
+        cases, except that in ARM mode frame pointer points to the
+        first saved register, while in Thumb-2 mode the frame pointer points
+        to the last saved register.
+
+        It is possible to make frame pointer point to last saved
+        register in both cases, and remove some conditionals below.
+        That means that fp setup in prologue would be just "mov fp, sp"
+        and sp restore in epilogue would be just "mov sp, fp", whereas
+        now we have to use add/sub in those cases. However, the value
+        of that would be marginal, as both mov and add/sub are 32-bit
+        in ARM mode, and it would require extra conditionals
+        in arm_expand_prologue to distingish ARM-apcs-frame case
+        (where frame pointer is required to point at first register)
+        and ARM-non-apcs-frame. Therefore, such change is postponed
+        until real need arise.  */
       HOST_WIDE_INT amount;
       int rfe;
       /* Restore stack pointer if necessary.  */
-      if (frame_pointer_needed)
-       {
-         /* 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
+      if (TARGET_ARM && frame_pointer_needed)
        {
          operands[0] = stack_pointer_rtx;
-         amount = offsets->outgoing_args - offsets->saved_regs;
+         operands[1] = hard_frame_pointer_rtx;
+         
+         operands[2] = GEN_INT (offsets->frame - offsets->saved_regs);
+         output_add_immediate (operands);
        }
-
-      if (amount)
+      else
        {
-         operands[1] = operands[0];
-         operands[2] = GEN_INT (amount);
-         output_add_immediate (operands);
+         if (frame_pointer_needed)
+           {
+             /* For Thumb-2 restore sp from the frame pointer.
+                Operand restrictions mean we have to incrememnt FP, then copy
+                to SP.  */
+             amount = offsets->locals_base - offsets->saved_regs;
+             operands[0] = hard_frame_pointer_rtx;
+           }
+         else
+           {
+             unsigned long count;
+             operands[0] = stack_pointer_rtx;
+             amount = offsets->outgoing_args - offsets->saved_regs;
+             /* pop call clobbered registers if it avoids a
+                separate stack adjustment.  */
+             count = offsets->saved_regs - offsets->saved_args;
+             if (optimize_size
+                 && count != 0
+                 && !crtl->calls_eh_return
+                 && bit_count(saved_regs_mask) * 4 == count
+                 && !IS_INTERRUPT (func_type)
+                 && !crtl->tail_call_emit)
+               {
+                 unsigned long mask;
+                 mask = (1 << (arm_size_return_regs() / 4)) - 1;
+                 mask ^= 0xf;
+                 mask &= ~saved_regs_mask;
+                 reg = 0;
+                 while (bit_count (mask) * 4 > amount)
+                   {
+                     while ((mask & (1 << reg)) == 0)
+                       reg++;
+                     mask &= ~(1 << reg);
+                   }
+                 if (bit_count (mask) * 4 == amount) {
+                     amount = 0;
+                     saved_regs_mask |= mask;
+                 }
+               }
+           }
+         
+         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 (frame_pointer_needed)
-       asm_fprintf (f, "\tmov\t%r, %r\n",
-                    SP_REGNUM, HARD_FRAME_POINTER_REGNUM);
 
       if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
        {
@@ -11587,9 +11642,9 @@ arm_output_epilogue (rtx sibling)
          && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
          && !IS_STACKALIGN (func_type)
          && really_return
-         && current_function_pretend_args_size == 0
+         && crtl->args.pretend_args_size == 0
          && saved_regs_mask & (1 << LR_REGNUM)
-         && !current_function_calls_eh_return)
+         && !crtl->calls_eh_return)
        {
          saved_regs_mask &= ~ (1 << LR_REGNUM);
          saved_regs_mask |=   (1 << PC_REGNUM);
@@ -11622,11 +11677,11 @@ arm_output_epilogue (rtx sibling)
            print_multi_reg (f, "pop\t", SP_REGNUM, saved_regs_mask, 0);
        }
 
-      if (current_function_pretend_args_size)
+      if (crtl->args.pretend_args_size)
        {
          /* Unwind the pre-pushed regs.  */
          operands[0] = operands[1] = stack_pointer_rtx;
-         operands[2] = GEN_INT (current_function_pretend_args_size);
+         operands[2] = GEN_INT (crtl->args.pretend_args_size);
          output_add_immediate (operands);
        }
     }
@@ -11636,7 +11691,7 @@ arm_output_epilogue (rtx sibling)
     return "";
 
   /* Stack adjustment for exception handler.  */
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
                 ARM_EH_STACKADJ_REGNUM);
 
@@ -11846,13 +11901,13 @@ emit_multi_reg_push (unsigned long mask)
 }
 
 /* Calculate the size of the return value that is passed in registers.  */
-static int
+static unsigned
 arm_size_return_regs (void)
 {
   enum machine_mode mode;
 
-  if (current_function_return_rtx != 0)
-    mode = GET_MODE (current_function_return_rtx);
+  if (crtl->return_rtx != 0)
+    mode = GET_MODE (crtl->return_rtx);
   else
     mode = DECL_MODE (DECL_RESULT (current_function_decl));
 
@@ -11975,7 +12030,8 @@ thumb_force_lr_save (void)
 
 
 /* Calculate stack offsets.  These are used to calculate register elimination
-   offsets and in prologue/epilogue code.  */
+   offsets and in prologue/epilogue code.  Also calculates which registers
+   should be saved.  */
 
 static arm_stack_offsets *
 arm_get_frame_offsets (void)
@@ -11984,7 +12040,9 @@ arm_get_frame_offsets (void)
   unsigned long func_type;
   int leaf;
   int saved;
+  int core_saved;
   HOST_WIDE_INT frame_size;
+  int i;
 
   offsets = &cfun->machine->stack_offsets;
 
@@ -12008,7 +12066,7 @@ arm_get_frame_offsets (void)
   leaf = leaf_function_p ();
 
   /* Space for variadic functions.  */
-  offsets->saved_args = current_function_pretend_args_size;
+  offsets->saved_args = crtl->args.pretend_args_size;
 
   /* In Thumb mode this is incorrect, but never used.  */
   offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
@@ -12017,7 +12075,9 @@ arm_get_frame_offsets (void)
     {
       unsigned int regno;
 
-      saved = bit_count (arm_compute_save_reg_mask ()) * 4;
+      offsets->saved_regs_mask = arm_compute_save_reg_mask ();
+      core_saved = bit_count (offsets->saved_regs_mask) * 4;
+      saved = core_saved;
 
       /* We know that SP will be doubleword aligned on entry, and we must
         preserve that condition at any subroutine call.  We also require the
@@ -12048,7 +12108,9 @@ arm_get_frame_offsets (void)
     }
   else /* TARGET_THUMB1 */
     {
-      saved = bit_count (thumb1_compute_save_reg_mask ()) * 4;
+      offsets->saved_regs_mask = thumb1_compute_save_reg_mask ();
+      core_saved = bit_count (offsets->saved_regs_mask) * 4;
+      saved = core_saved;
       if (TARGET_BACKTRACE)
        saved += 16;
     }
@@ -12068,11 +12130,43 @@ arm_get_frame_offsets (void)
   /* Ensure SFP has the correct alignment.  */
   if (ARM_DOUBLEWORD_ALIGN
       && (offsets->soft_frame & 7))
-    offsets->soft_frame += 4;
+    {
+      offsets->soft_frame += 4;
+      /* Try to align stack by pushing an extra reg.  Don't bother doing this
+         when there is a stack frame as the alignment will be rolled into
+        the normal stack adjustment.  */
+      if (frame_size + crtl->outgoing_args_size == 0)
+       {
+         int reg = -1;
+
+         for (i = 4; i <= (TARGET_THUMB1 ? LAST_LO_REGNUM : 11); i++)
+           {
+             if ((offsets->saved_regs_mask & (1 << i)) == 0)
+               {
+                 reg = i;
+                 break;
+               }
+           }
+
+         if (reg == -1 && arm_size_return_regs () <= 12
+             && !crtl->tail_call_emit)
+           {
+             /* Push/pop an argument register (r3) if all callee saved
+                registers are already being pushed.  */
+             reg = 3;
+           }
+
+         if (reg != -1)
+           {
+             offsets->saved_regs += 4;
+             offsets->saved_regs_mask |= (1 << reg);
+           }
+       }
+    }
 
   offsets->locals_base = offsets->soft_frame + frame_size;
   offsets->outgoing_args = (offsets->locals_base
-                           + current_function_outgoing_args_size);
+                           + crtl->outgoing_args_size);
 
   if (ARM_DOUBLEWORD_ALIGN)
     {
@@ -12274,9 +12368,20 @@ thumb_set_frame_pointer (arm_stack_offsets *offsets)
   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));
+      /* Thumb-2 RTL patterns expect sp as the first input.  Thumb-1
+         expects the first two operands to be the same.  */
+      if (TARGET_THUMB2)
+       {
+         insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+                                       stack_pointer_rtx,
+                                       hard_frame_pointer_rtx));
+       }
+      else
+       {
+         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;
@@ -12310,10 +12415,11 @@ arm_expand_prologue (void)
     return;
 
   /* Make a copy of c_f_p_a_s as we may need to modify it locally.  */
-  args_to_push = current_function_pretend_args_size;
+  args_to_push = crtl->args.pretend_args_size;
 
   /* Compute which register we will have to save onto the stack.  */
-  live_regs_mask = arm_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  live_regs_mask = offsets->saved_regs_mask;
 
   ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
 
@@ -12348,7 +12454,10 @@ arm_expand_prologue (void)
       emit_insn (gen_movsi (stack_pointer_rtx, r1));
     }
 
-  if (frame_pointer_needed && TARGET_ARM)
+  /* For APCS frames, if IP register is clobbered
+     when creating frame, save that register in a special
+     way.  */
+  if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
     {
       if (IS_INTERRUPT (func_type))
        {
@@ -12447,13 +12556,13 @@ arm_expand_prologue (void)
     }
 
   /* If this is an interrupt service routine, and the link register
-     is going to be pushed, and we are not creating a stack frame,
-     (which would involve an extra push of IP and a pop in the epilogue)
+     is going to be pushed, and we're not generating extra
+     push of IP (needed when frame is needed and frame layout if apcs),
      subtracting four from LR now will mean that the function return
      can be done with a single instruction.  */
   if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
       && (live_regs_mask & (1 << LR_REGNUM)) != 0
-      && ! frame_pointer_needed
+      && !(frame_pointer_needed && TARGET_APCS_FRAME)
       && TARGET_ARM)
     {
       rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
@@ -12463,8 +12572,28 @@ arm_expand_prologue (void)
 
   if (live_regs_mask)
     {
-      insn = emit_multi_reg_push (live_regs_mask);
       saved_regs += bit_count (live_regs_mask) * 4;
+      if (optimize_size && !frame_pointer_needed
+         && saved_regs == offsets->saved_regs - offsets->saved_args)
+       {
+         /* If no coprocessor registers are being pushed and we don't have
+            to worry about a frame pointer then push extra registers to
+            create the stack frame.  This is done is a way that does not
+            alter the frame layout, so is independent of the epilogue.  */
+         int n;
+         int frame;
+         n = 0;
+         while (n < 8 && (live_regs_mask & (1 << n)) == 0)
+           n++;
+         frame = offsets->outgoing_args - (offsets->saved_args + saved_regs);
+         if (frame && n * 4 >= frame)
+           {
+             n = frame / 4;
+             live_regs_mask |= (1 << n) - 1;
+             saved_regs += frame;
+           }
+       }
+      insn = emit_multi_reg_push (live_regs_mask);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
@@ -12474,6 +12603,7 @@ arm_expand_prologue (void)
   if (frame_pointer_needed && TARGET_ARM)
     {
       /* Create the new frame pointer.  */
+      if (TARGET_APCS_FRAME)
        {
          insn = GEN_INT (-(4 + args_to_push + fp_offset));
          insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
@@ -12485,7 +12615,7 @@ arm_expand_prologue (void)
              if (!df_regs_ever_live_p (3)
                  || saved_pretend_args)
                insn = gen_rtx_REG (SImode, 3);
-             else /* if (current_function_pretend_args_size == 0) */
+             else /* if (crtl->args.pretend_args_size == 0) */
                {
                  insn = plus_constant (hard_frame_pointer_rtx, 4);
                  insn = gen_frame_mem (SImode, insn);
@@ -12495,9 +12625,15 @@ arm_expand_prologue (void)
              emit_insn (gen_prologue_use (ip_rtx));
            }
        }
+      else
+       {
+         insn = GEN_INT (saved_regs - 4);
+         insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+                                       stack_pointer_rtx, insn));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
     }
 
-  offsets = arm_get_frame_offsets ();
   if (offsets->outgoing_args != offsets->saved_args + saved_regs)
     {
       /* This add can produce multiple insns for a large constant, so we
@@ -12544,7 +12680,7 @@ arm_expand_prologue (void)
      scheduling in the prolog.  Similarly if we want non-call exceptions
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
-  if (current_function_profile || !TARGET_SCHED_PROLOG
+  if (crtl->profile || !TARGET_SCHED_PROLOG
       || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
     emit_insn (gen_blockage ());
 
@@ -13115,7 +13251,6 @@ arm_print_operand (FILE *stream, rtx x, int code)
     }
 }
 \f
-#ifndef AOF_ASSEMBLER
 /* Target hook for assembling integer objects.  The ARM version needs to
    handle word-sized values specially.  */
 static bool
@@ -13243,7 +13378,6 @@ arm_elf_asm_destructor (rtx symbol, int priority)
 {
   arm_elf_asm_cdtor (symbol, priority, /*is_ctor=*/false);
 }
-#endif
 \f
 /* A finite state machine takes care of noticing whether or not instructions
    can be conditionally executed, and thus decrease execution time and code
@@ -14535,14 +14669,14 @@ arm_init_iwmmxt_builtins (void)
 static void
 arm_init_tls_builtins (void)
 {
-  tree ftype;
-  tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
-  tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
+  tree ftype, decl;
 
   ftype = build_function_type (ptr_type_node, void_list_node);
-  add_builtin_function ("__builtin_thread_pointer", ftype,
-                       ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
-                       NULL, const_nothrow);
+  decl = add_builtin_function ("__builtin_thread_pointer", ftype,
+                              ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+                              NULL, NULL_TREE);
+  TREE_NOTHROW (decl) = 1;
+  TREE_READONLY (decl) = 1;
 }
 
 typedef enum {
@@ -14877,15 +15011,86 @@ arm_init_neon_builtins (void)
 {
   unsigned int i, fcode = ARM_BUILTIN_NEON_BASE;
 
+  tree neon_intQI_type_node;
+  tree neon_intHI_type_node;
+  tree neon_polyQI_type_node;
+  tree neon_polyHI_type_node;
+  tree neon_intSI_type_node;
+  tree neon_intDI_type_node;
+  tree neon_float_type_node;
+
+  tree intQI_pointer_node;
+  tree intHI_pointer_node;
+  tree intSI_pointer_node;
+  tree intDI_pointer_node;
+  tree float_pointer_node;
+
+  tree const_intQI_node;
+  tree const_intHI_node;
+  tree const_intSI_node;
+  tree const_intDI_node;
+  tree const_float_node;
+
+  tree const_intQI_pointer_node;
+  tree const_intHI_pointer_node;
+  tree const_intSI_pointer_node;
+  tree const_intDI_pointer_node;
+  tree const_float_pointer_node;
+
+  tree V8QI_type_node;
+  tree V4HI_type_node;
+  tree V2SI_type_node;
+  tree V2SF_type_node;
+  tree V16QI_type_node;
+  tree V8HI_type_node;
+  tree V4SI_type_node;
+  tree V4SF_type_node;
+  tree V2DI_type_node;
+
+  tree intUQI_type_node;
+  tree intUHI_type_node;
+  tree intUSI_type_node;
+  tree intUDI_type_node;
+
+  tree intEI_type_node;
+  tree intOI_type_node;
+  tree intCI_type_node;
+  tree intXI_type_node;
+
+  tree V8QI_pointer_node;
+  tree V4HI_pointer_node;
+  tree V2SI_pointer_node;
+  tree V2SF_pointer_node;
+  tree V16QI_pointer_node;
+  tree V8HI_pointer_node;
+  tree V4SI_pointer_node;
+  tree V4SF_pointer_node;
+  tree V2DI_pointer_node;
+
+  tree void_ftype_pv8qi_v8qi_v8qi;
+  tree void_ftype_pv4hi_v4hi_v4hi;
+  tree void_ftype_pv2si_v2si_v2si;
+  tree void_ftype_pv2sf_v2sf_v2sf;
+  tree void_ftype_pdi_di_di;
+  tree void_ftype_pv16qi_v16qi_v16qi;
+  tree void_ftype_pv8hi_v8hi_v8hi;
+  tree void_ftype_pv4si_v4si_v4si;
+  tree void_ftype_pv4sf_v4sf_v4sf;
+  tree void_ftype_pv2di_v2di_v2di;
+
+  tree reinterp_ftype_dreg[5][5];
+  tree reinterp_ftype_qreg[5][5];
+  tree dreg_types[5], qreg_types[5];
+
   /* Create distinguished type nodes for NEON vector element types,
      and pointers to values of such types, so we can detect them later.  */
-  tree neon_intQI_type_node = make_signed_type (GET_MODE_PRECISION (QImode));
-  tree neon_intHI_type_node = make_signed_type (GET_MODE_PRECISION (HImode));
-  tree neon_polyQI_type_node = make_signed_type (GET_MODE_PRECISION (QImode));
-  tree neon_polyHI_type_node = make_signed_type (GET_MODE_PRECISION (HImode));
-  tree neon_intSI_type_node = make_signed_type (GET_MODE_PRECISION (SImode));
-  tree neon_intDI_type_node = make_signed_type (GET_MODE_PRECISION (DImode));
-  tree neon_float_type_node = make_node (REAL_TYPE);
+  neon_intQI_type_node = make_signed_type (GET_MODE_PRECISION (QImode));
+  neon_intHI_type_node = make_signed_type (GET_MODE_PRECISION (HImode));
+  neon_polyQI_type_node = make_signed_type (GET_MODE_PRECISION (QImode));
+  neon_polyHI_type_node = make_signed_type (GET_MODE_PRECISION (HImode));
+  neon_intSI_type_node = make_signed_type (GET_MODE_PRECISION (SImode));
+  neon_intDI_type_node = make_signed_type (GET_MODE_PRECISION (DImode));
+  neon_float_type_node = make_node (REAL_TYPE);
   TYPE_PRECISION (neon_float_type_node) = FLOAT_TYPE_SIZE;
   layout_type (neon_float_type_node);
 
@@ -14902,63 +15107,62 @@ arm_init_neon_builtins (void)
                                             "__builtin_neon_sf");
   (*lang_hooks.types.register_builtin_type) (neon_intDI_type_node,
                                             "__builtin_neon_di");
-
   (*lang_hooks.types.register_builtin_type) (neon_polyQI_type_node,
                                             "__builtin_neon_poly8");
   (*lang_hooks.types.register_builtin_type) (neon_polyHI_type_node,
                                             "__builtin_neon_poly16");
 
-  tree intQI_pointer_node = build_pointer_type (neon_intQI_type_node);
-  tree intHI_pointer_node = build_pointer_type (neon_intHI_type_node);
-  tree intSI_pointer_node = build_pointer_type (neon_intSI_type_node);
-  tree intDI_pointer_node = build_pointer_type (neon_intDI_type_node);
-  tree float_pointer_node = build_pointer_type (neon_float_type_node);
+  intQI_pointer_node = build_pointer_type (neon_intQI_type_node);
+  intHI_pointer_node = build_pointer_type (neon_intHI_type_node);
+  intSI_pointer_node = build_pointer_type (neon_intSI_type_node);
+  intDI_pointer_node = build_pointer_type (neon_intDI_type_node);
+  float_pointer_node = build_pointer_type (neon_float_type_node);
 
   /* Next create constant-qualified versions of the above types.  */
-  tree const_intQI_node = build_qualified_type (neon_intQI_type_node,
-                                               TYPE_QUAL_CONST);
-  tree const_intHI_node = build_qualified_type (neon_intHI_type_node,
-                                               TYPE_QUAL_CONST);
-  tree const_intSI_node = build_qualified_type (neon_intSI_type_node,
-                                               TYPE_QUAL_CONST);
-  tree const_intDI_node = build_qualified_type (neon_intDI_type_node,
-                                               TYPE_QUAL_CONST);
-  tree const_float_node = build_qualified_type (neon_float_type_node,
-                                               TYPE_QUAL_CONST);
-
-  tree const_intQI_pointer_node = build_pointer_type (const_intQI_node);
-  tree const_intHI_pointer_node = build_pointer_type (const_intHI_node);
-  tree const_intSI_pointer_node = build_pointer_type (const_intSI_node);
-  tree const_intDI_pointer_node = build_pointer_type (const_intDI_node);
-  tree const_float_pointer_node = build_pointer_type (const_float_node);
+  const_intQI_node = build_qualified_type (neon_intQI_type_node,
+                                          TYPE_QUAL_CONST);
+  const_intHI_node = build_qualified_type (neon_intHI_type_node,
+                                          TYPE_QUAL_CONST);
+  const_intSI_node = build_qualified_type (neon_intSI_type_node,
+                                          TYPE_QUAL_CONST);
+  const_intDI_node = build_qualified_type (neon_intDI_type_node,
+                                          TYPE_QUAL_CONST);
+  const_float_node = build_qualified_type (neon_float_type_node,
+                                          TYPE_QUAL_CONST);
+
+  const_intQI_pointer_node = build_pointer_type (const_intQI_node);
+  const_intHI_pointer_node = build_pointer_type (const_intHI_node);
+  const_intSI_pointer_node = build_pointer_type (const_intSI_node);
+  const_intDI_pointer_node = build_pointer_type (const_intDI_node);
+  const_float_pointer_node = build_pointer_type (const_float_node);
 
   /* Now create vector types based on our NEON element types.  */
   /* 64-bit vectors.  */
-  tree V8QI_type_node =
+  V8QI_type_node =
     build_vector_type_for_mode (neon_intQI_type_node, V8QImode);
-  tree V4HI_type_node =
+  V4HI_type_node =
     build_vector_type_for_mode (neon_intHI_type_node, V4HImode);
-  tree V2SI_type_node =
+  V2SI_type_node =
     build_vector_type_for_mode (neon_intSI_type_node, V2SImode);
-  tree V2SF_type_node =
+  V2SF_type_node =
     build_vector_type_for_mode (neon_float_type_node, V2SFmode);
   /* 128-bit vectors.  */
-  tree V16QI_type_node =
+  V16QI_type_node =
     build_vector_type_for_mode (neon_intQI_type_node, V16QImode);
-  tree V8HI_type_node =
+  V8HI_type_node =
     build_vector_type_for_mode (neon_intHI_type_node, V8HImode);
-  tree V4SI_type_node =
+  V4SI_type_node =
     build_vector_type_for_mode (neon_intSI_type_node, V4SImode);
-  tree V4SF_type_node =
+  V4SF_type_node =
     build_vector_type_for_mode (neon_float_type_node, V4SFmode);
-  tree V2DI_type_node =
+  V2DI_type_node =
     build_vector_type_for_mode (neon_intDI_type_node, V2DImode);
 
   /* Unsigned integer types for various mode sizes.  */
-  tree intUQI_type_node = make_unsigned_type (GET_MODE_PRECISION (QImode));
-  tree intUHI_type_node = make_unsigned_type (GET_MODE_PRECISION (HImode));
-  tree intUSI_type_node = make_unsigned_type (GET_MODE_PRECISION (SImode));
-  tree intUDI_type_node = make_unsigned_type (GET_MODE_PRECISION (DImode));
+  intUQI_type_node = make_unsigned_type (GET_MODE_PRECISION (QImode));
+  intUHI_type_node = make_unsigned_type (GET_MODE_PRECISION (HImode));
+  intUSI_type_node = make_unsigned_type (GET_MODE_PRECISION (SImode));
+  intUDI_type_node = make_unsigned_type (GET_MODE_PRECISION (DImode));
 
   (*lang_hooks.types.register_builtin_type) (intUQI_type_node,
                                             "__builtin_neon_uqi");
@@ -14970,10 +15174,10 @@ arm_init_neon_builtins (void)
                                             "__builtin_neon_udi");
 
   /* Opaque integer types for structures of vectors.  */
-  tree intEI_type_node = make_signed_type (GET_MODE_PRECISION (EImode));
-  tree intOI_type_node = make_signed_type (GET_MODE_PRECISION (OImode));
-  tree intCI_type_node = make_signed_type (GET_MODE_PRECISION (CImode));
-  tree intXI_type_node = make_signed_type (GET_MODE_PRECISION (XImode));
+  intEI_type_node = make_signed_type (GET_MODE_PRECISION (EImode));
+  intOI_type_node = make_signed_type (GET_MODE_PRECISION (OImode));
+  intCI_type_node = make_signed_type (GET_MODE_PRECISION (CImode));
+  intXI_type_node = make_signed_type (GET_MODE_PRECISION (XImode));
 
   (*lang_hooks.types.register_builtin_type) (intTI_type_node,
                                             "__builtin_neon_ti");
@@ -14987,52 +15191,48 @@ arm_init_neon_builtins (void)
                                             "__builtin_neon_xi");
 
   /* Pointers to vector types.  */
-  tree V8QI_pointer_node = build_pointer_type (V8QI_type_node);
-  tree V4HI_pointer_node = build_pointer_type (V4HI_type_node);
-  tree V2SI_pointer_node = build_pointer_type (V2SI_type_node);
-  tree V2SF_pointer_node = build_pointer_type (V2SF_type_node);
-  tree V16QI_pointer_node = build_pointer_type (V16QI_type_node);
-  tree V8HI_pointer_node = build_pointer_type (V8HI_type_node);
-  tree V4SI_pointer_node = build_pointer_type (V4SI_type_node);
-  tree V4SF_pointer_node = build_pointer_type (V4SF_type_node);
-  tree V2DI_pointer_node = build_pointer_type (V2DI_type_node);
+  V8QI_pointer_node = build_pointer_type (V8QI_type_node);
+  V4HI_pointer_node = build_pointer_type (V4HI_type_node);
+  V2SI_pointer_node = build_pointer_type (V2SI_type_node);
+  V2SF_pointer_node = build_pointer_type (V2SF_type_node);
+  V16QI_pointer_node = build_pointer_type (V16QI_type_node);
+  V8HI_pointer_node = build_pointer_type (V8HI_type_node);
+  V4SI_pointer_node = build_pointer_type (V4SI_type_node);
+  V4SF_pointer_node = build_pointer_type (V4SF_type_node);
+  V2DI_pointer_node = build_pointer_type (V2DI_type_node);
 
   /* Operations which return results as pairs.  */
-  tree void_ftype_pv8qi_v8qi_v8qi =
+  void_ftype_pv8qi_v8qi_v8qi =
     build_function_type_list (void_type_node, V8QI_pointer_node, V8QI_type_node,
                              V8QI_type_node, NULL);
-  tree void_ftype_pv4hi_v4hi_v4hi =
+  void_ftype_pv4hi_v4hi_v4hi =
     build_function_type_list (void_type_node, V4HI_pointer_node, V4HI_type_node,
                              V4HI_type_node, NULL);
-  tree void_ftype_pv2si_v2si_v2si =
+  void_ftype_pv2si_v2si_v2si =
     build_function_type_list (void_type_node, V2SI_pointer_node, V2SI_type_node,
                              V2SI_type_node, NULL);
-  tree void_ftype_pv2sf_v2sf_v2sf =
+  void_ftype_pv2sf_v2sf_v2sf =
     build_function_type_list (void_type_node, V2SF_pointer_node, V2SF_type_node,
                              V2SF_type_node, NULL);
-  tree void_ftype_pdi_di_di =
+  void_ftype_pdi_di_di =
     build_function_type_list (void_type_node, intDI_pointer_node,
                              neon_intDI_type_node, neon_intDI_type_node, NULL);
-  tree void_ftype_pv16qi_v16qi_v16qi =
+  void_ftype_pv16qi_v16qi_v16qi =
     build_function_type_list (void_type_node, V16QI_pointer_node,
                              V16QI_type_node, V16QI_type_node, NULL);
-  tree void_ftype_pv8hi_v8hi_v8hi =
+  void_ftype_pv8hi_v8hi_v8hi =
     build_function_type_list (void_type_node, V8HI_pointer_node, V8HI_type_node,
                              V8HI_type_node, NULL);
-  tree void_ftype_pv4si_v4si_v4si =
+  void_ftype_pv4si_v4si_v4si =
     build_function_type_list (void_type_node, V4SI_pointer_node, V4SI_type_node,
                              V4SI_type_node, NULL);
-  tree void_ftype_pv4sf_v4sf_v4sf =
+  void_ftype_pv4sf_v4sf_v4sf =
     build_function_type_list (void_type_node, V4SF_pointer_node, V4SF_type_node,
                              V4SF_type_node, NULL);
-  tree void_ftype_pv2di_v2di_v2di =
+  void_ftype_pv2di_v2di_v2di =
     build_function_type_list (void_type_node, V2DI_pointer_node, V2DI_type_node,
                              V2DI_type_node, NULL);
 
-  tree reinterp_ftype_dreg[5][5];
-  tree reinterp_ftype_qreg[5][5];
-  tree dreg_types[5], qreg_types[5];
-
   dreg_types[0] = V8QI_type_node;
   dreg_types[1] = V4HI_type_node;
   dreg_types[2] = V2SI_type_node;
@@ -15409,8 +15609,8 @@ arm_expand_unop_builtin (enum insn_code icode,
 static int
 neon_builtin_compare (const void *a, const void *b)
 {
-  const neon_builtin_datum *key = a;
-  const neon_builtin_datum *memb = b;
+  const neon_builtin_datum *const key = (const neon_builtin_datum *) a;
+  const neon_builtin_datum *const memb = (const neon_builtin_datum *) b;
   unsigned int soughtcode = key->base_fcode;
 
   if (soughtcode >= memb->base_fcode
@@ -15429,7 +15629,8 @@ locate_neon_builtin_icode (int fcode, neon_itype *itype)
   int idx;
 
   key.base_fcode = fcode;
-  found = bsearch (&key, &neon_builtin_data[0], ARRAY_SIZE (neon_builtin_data),
+  found = (neon_builtin_datum *)
+    bsearch (&key, &neon_builtin_data[0], ARRAY_SIZE (neon_builtin_data),
                   sizeof (neon_builtin_data[0]), neon_builtin_compare);
   gcc_assert (found);
   idx = fcode - (int) found->base_fcode;
@@ -16062,7 +16263,7 @@ thumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
     {
       /* Catch popping the PC.  */
       if (TARGET_INTERWORK || TARGET_BACKTRACE
-         || current_function_calls_eh_return)
+         || crtl->calls_eh_return)
        {
          /* The PC is never poped directly, instead
             it is popped into r3 and then BX is used.  */
@@ -16137,7 +16338,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
      return.  */
   if (pops_needed == 0)
     {
-      if (current_function_calls_eh_return)
+      if (crtl->calls_eh_return)
        asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
       asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
@@ -16149,7 +16350,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
   else if (!TARGET_INTERWORK
           && !TARGET_BACKTRACE
           && !is_called_in_ARM_mode (current_function_decl)
-          && !current_function_calls_eh_return)
+          && !crtl->calls_eh_return)
     {
       asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
       return;
@@ -16160,7 +16361,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
 
   /* If returning via __builtin_eh_return, the bottom three registers
      all contain information needed for the return.  */
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     size = 12;
   else
     {
@@ -16170,8 +16371,8 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
         ever used in the function, not just if the register is used
         to hold a return value.  */
 
-      if (current_function_return_rtx != 0)
-       mode = GET_MODE (current_function_return_rtx);
+      if (crtl->return_rtx != 0)
+       mode = GET_MODE (crtl->return_rtx);
       else
        mode = DECL_MODE (DECL_RESULT (current_function_decl));
 
@@ -16371,7 +16572,7 @@ thumb_exit (FILE *f, int reg_containing_return_addr)
       asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
     }
 
-  if (current_function_calls_eh_return)
+  if (crtl->calls_eh_return)
     asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
 
   /* Return to caller.  */
@@ -16495,6 +16696,7 @@ is_called_in_ARM_mode (tree func)
 const char *
 thumb_unexpanded_epilogue (void)
 {
+  arm_stack_offsets *offsets;
   int regno;
   unsigned long live_regs_mask = 0;
   int high_regs_pushed = 0;
@@ -16507,7 +16709,8 @@ thumb_unexpanded_epilogue (void)
   if (IS_NAKED (arm_current_func_type ()))
     return "";
 
-  live_regs_mask = thumb1_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  live_regs_mask = offsets->saved_regs_mask;
   high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
 
   /* If we can deduce the registers used from the function's return value.
@@ -16585,7 +16788,7 @@ thumb_unexpanded_epilogue (void)
   had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
   live_regs_mask &= 0xff;
 
-  if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
+  if (crtl->args.pretend_args_size == 0 || TARGET_BACKTRACE)
     {
       /* Pop the return address into the PC.  */
       if (had_to_push_lr)
@@ -16642,7 +16845,7 @@ thumb_unexpanded_epilogue (void)
       /* Remove the argument registers that were pushed onto the stack.  */
       asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
                   SP_REGNUM, SP_REGNUM,
-                  current_function_pretend_args_size);
+                  crtl->args.pretend_args_size);
 
       thumb_exit (asm_out_file, regno);
     }
@@ -16769,7 +16972,8 @@ thumb1_expand_prologue (void)
       return;
     }
 
-  live_regs_mask = thumb1_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  live_regs_mask = offsets->saved_regs_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)
@@ -16779,7 +16983,6 @@ thumb1_expand_prologue (void)
     emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
                    stack_pointer_rtx);
 
-  offsets = arm_get_frame_offsets ();
   amount = offsets->outgoing_args - offsets->saved_regs;
   if (amount)
     {
@@ -16875,7 +17078,7 @@ thumb1_expand_prologue (void)
      scheduling in the prolog.  Similarly if we want non-call exceptions
      using the EABI unwinder, to prevent faulting instructions from being
      swapped with a stack adjustment.  */
-  if (current_function_profile || !TARGET_SCHED_PROLOG
+  if (crtl->profile || !TARGET_SCHED_PROLOG
       || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
     emit_insn (gen_blockage ());
 
@@ -16925,22 +17128,23 @@ thumb1_expand_epilogue (void)
      the stack adjustment will not be deleted.  */
   emit_insn (gen_prologue_use (stack_pointer_rtx));
 
-  if (current_function_profile || !TARGET_SCHED_PROLOG)
+  if (crtl->profile || !TARGET_SCHED_PROLOG)
     emit_insn (gen_blockage ());
 
   /* Emit a clobber for each insn that will be restored in the epilogue,
      so that flow2 will get register lifetimes correct.  */
   for (regno = 0; regno < 13; regno++)
     if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
+      emit_clobber (gen_rtx_REG (SImode, regno));
 
   if (! df_regs_ever_live_p (LR_REGNUM))
-    emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
+    emit_use (gen_rtx_REG (SImode, LR_REGNUM));
 }
 
 static void
 thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
+  arm_stack_offsets *offsets;
   unsigned long live_regs_mask = 0;
   unsigned long l_mask;
   unsigned high_regs_pushed = 0;
@@ -16984,12 +17188,12 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
     }
 
-  if (current_function_pretend_args_size)
+  if (crtl->args.pretend_args_size)
     {
       /* Output unwind directive for the stack adjustment.  */
       if (ARM_EABI_UNWIND_TABLES)
        fprintf (f, "\t.pad #%d\n",
-                current_function_pretend_args_size);
+                crtl->args.pretend_args_size);
 
       if (cfun->machine->uses_anonymous_args)
        {
@@ -16997,7 +17201,7 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
          fprintf (f, "\tpush\t{");
 
-         num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
+         num_pushes = ARM_NUM_INTS (crtl->args.pretend_args_size);
 
          for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
               regno <= LAST_ARG_REGNUM;
@@ -17010,7 +17214,7 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
       else
        asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
                     SP_REGNUM, SP_REGNUM,
-                    current_function_pretend_args_size);
+                    crtl->args.pretend_args_size);
 
       /* We don't need to record the stores for unwinding (would it
         help the debugger any if we did?), but record the change in
@@ -17019,13 +17223,14 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
        {
          char *l = dwarf2out_cfi_label ();
 
-         cfa_offset = cfa_offset + current_function_pretend_args_size;
+         cfa_offset = cfa_offset + crtl->args.pretend_args_size;
          dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
        }
     }
 
   /* Get the registers we are going to push.  */
-  live_regs_mask = thumb1_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  live_regs_mask = offsets->saved_regs_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.  */
@@ -17080,7 +17285,7 @@ thumb1_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
        offset = 0;
 
       asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
-                  offset + 16 + current_function_pretend_args_size);
+                  offset + 16 + crtl->args.pretend_args_size);
 
       asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
                   offset + 4);
@@ -17557,10 +17762,6 @@ arm_file_start (void)
          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");
@@ -17596,6 +17797,9 @@ arm_file_start (void)
       else
        val = 6;
       asm_fprintf (asm_out_file, "\t.eabi_attribute 30, %d\n", val);
+
+      if (arm_lang_output_object_attributes_hook)
+       arm_lang_output_object_attributes_hook();
     }
   default_file_start();
 }
@@ -17629,239 +17833,6 @@ arm_file_end (void)
     }
 }
 
-rtx aof_pic_label;
-
-#ifdef AOF_ASSEMBLER
-/* Special functions only needed when producing AOF syntax assembler.  */
-
-struct pic_chain
-{
-  struct pic_chain * next;
-  const char * symname;
-};
-
-static struct pic_chain * aof_pic_chain = NULL;
-
-rtx
-aof_pic_entry (rtx x)
-{
-  struct pic_chain ** chainp;
-  int offset;
-
-  if (aof_pic_label == NULL_RTX)
-    {
-      aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
-    }
-
-  for (offset = 0, chainp = &aof_pic_chain; *chainp;
-       offset += 4, chainp = &(*chainp)->next)
-    if ((*chainp)->symname == XSTR (x, 0))
-      return plus_constant (aof_pic_label, offset);
-
-  *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
-  (*chainp)->next = NULL;
-  (*chainp)->symname = XSTR (x, 0);
-  return plus_constant (aof_pic_label, offset);
-}
-
-void
-aof_dump_pic_table (FILE *f)
-{
-  struct pic_chain * chain;
-
-  if (aof_pic_chain == NULL)
-    return;
-
-  asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
-              PIC_OFFSET_TABLE_REGNUM,
-              PIC_OFFSET_TABLE_REGNUM);
-  fputs ("|x$adcons|\n", f);
-
-  for (chain = aof_pic_chain; chain; chain = chain->next)
-    {
-      fputs ("\tDCD\t", f);
-      assemble_name (f, chain->symname);
-      fputs ("\n", f);
-    }
-}
-
-int arm_text_section_count = 1;
-
-/* A get_unnamed_section callback for switching to the text section.  */
-
-static void
-aof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
-{
-  fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
-          arm_text_section_count++);
-  if (flag_pic)
-    fprintf (asm_out_file, ", PIC, REENTRANT");
-  fprintf (asm_out_file, "\n");
-}
-
-static int arm_data_section_count = 1;
-
-/* A get_unnamed_section callback for switching to the data section.  */
-
-static void
-aof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
-{
-  fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
-          arm_data_section_count++);
-}
-
-/* Implement TARGET_ASM_INIT_SECTIONS.
-
-   AOF Assembler syntax is a nightmare when it comes to areas, since once
-   we change from one area to another, we can't go back again.  Instead,
-   we must create a new area with the same attributes and add the new output
-   to that.  Unfortunately, there is nothing we can do here to guarantee that
-   two areas with the same attributes will be linked adjacently in the
-   resulting executable, so we have to be careful not to do pc-relative
-   addressing across such boundaries.  */
-
-static void
-aof_asm_init_sections (void)
-{
-  text_section = get_unnamed_section (SECTION_CODE,
-                                     aof_output_text_section_asm_op, NULL);
-  data_section = get_unnamed_section (SECTION_WRITE,
-                                     aof_output_data_section_asm_op, NULL);
-  readonly_data_section = text_section;
-}
-
-void
-zero_init_section (void)
-{
-  static int zero_init_count = 1;
-
-  fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
-  in_section = NULL;
-}
-
-/* The AOF assembler is religiously strict about declarations of
-   imported and exported symbols, so that it is impossible to declare
-   a function as imported near the beginning of the file, and then to
-   export it later on.  It is, however, possible to delay the decision
-   until all the functions in the file have been compiled.  To get
-   around this, we maintain a list of the imports and exports, and
-   delete from it any that are subsequently defined.  At the end of
-   compilation we spit the remainder of the list out before the END
-   directive.  */
-
-struct import
-{
-  struct import * next;
-  const char * name;
-};
-
-static struct import * imports_list = NULL;
-
-void
-aof_add_import (const char *name)
-{
-  struct import * new;
-
-  for (new = imports_list; new; new = new->next)
-    if (new->name == name)
-      return;
-
-  new = (struct import *) xmalloc (sizeof (struct import));
-  new->next = imports_list;
-  imports_list = new;
-  new->name = name;
-}
-
-void
-aof_delete_import (const char *name)
-{
-  struct import ** old;
-
-  for (old = &imports_list; *old; old = & (*old)->next)
-    {
-      if ((*old)->name == name)
-       {
-         *old = (*old)->next;
-         return;
-       }
-    }
-}
-
-int arm_main_function = 0;
-
-static void
-aof_dump_imports (FILE *f)
-{
-  /* The AOF assembler needs this to cause the startup code to be extracted
-     from the library.  Brining in __main causes the whole thing to work
-     automagically.  */
-  if (arm_main_function)
-    {
-      switch_to_section (text_section);
-      fputs ("\tIMPORT __main\n", f);
-      fputs ("\tDCD __main\n", f);
-    }
-
-  /* Now dump the remaining imports.  */
-  while (imports_list)
-    {
-      fprintf (f, "\tIMPORT\t");
-      assemble_name (f, imports_list->name);
-      fputc ('\n', f);
-      imports_list = imports_list->next;
-    }
-}
-
-static void
-aof_globalize_label (FILE *stream, const char *name)
-{
-  default_globalize_label (stream, name);
-  if (! strcmp (name, "main"))
-    arm_main_function = 1;
-}
-
-static void
-aof_file_start (void)
-{
-  fputs ("__r0\tRN\t0\n", asm_out_file);
-  fputs ("__a1\tRN\t0\n", asm_out_file);
-  fputs ("__a2\tRN\t1\n", asm_out_file);
-  fputs ("__a3\tRN\t2\n", asm_out_file);
-  fputs ("__a4\tRN\t3\n", asm_out_file);
-  fputs ("__v1\tRN\t4\n", asm_out_file);
-  fputs ("__v2\tRN\t5\n", asm_out_file);
-  fputs ("__v3\tRN\t6\n", asm_out_file);
-  fputs ("__v4\tRN\t7\n", asm_out_file);
-  fputs ("__v5\tRN\t8\n", asm_out_file);
-  fputs ("__v6\tRN\t9\n", asm_out_file);
-  fputs ("__sl\tRN\t10\n", asm_out_file);
-  fputs ("__fp\tRN\t11\n", asm_out_file);
-  fputs ("__ip\tRN\t12\n", asm_out_file);
-  fputs ("__sp\tRN\t13\n", asm_out_file);
-  fputs ("__lr\tRN\t14\n", asm_out_file);
-  fputs ("__pc\tRN\t15\n", asm_out_file);
-  fputs ("__f0\tFN\t0\n", asm_out_file);
-  fputs ("__f1\tFN\t1\n", asm_out_file);
-  fputs ("__f2\tFN\t2\n", asm_out_file);
-  fputs ("__f3\tFN\t3\n", asm_out_file);
-  fputs ("__f4\tFN\t4\n", asm_out_file);
-  fputs ("__f5\tFN\t5\n", asm_out_file);
-  fputs ("__f6\tFN\t6\n", asm_out_file);
-  fputs ("__f7\tFN\t7\n", asm_out_file);
-  switch_to_section (text_section);
-}
-
-static void
-aof_file_end (void)
-{
-  if (flag_pic)
-    aof_dump_pic_table (asm_out_file);
-  arm_file_end ();
-  aof_dump_imports (asm_out_file);
-  fputs ("\tEND\n", asm_out_file);
-}
-#endif /* AOF_ASSEMBLER */
-
 #ifndef ARM_PE
 /* Symbols in the text segment can be accessed without indirecting via the
    constant pool; it may take an extra binary operation, but this is still
@@ -17872,12 +17843,8 @@ aof_file_end (void)
 static void
 arm_encode_section_info (tree decl, rtx rtl, int first)
 {
-  /* This doesn't work with AOF syntax, since the string table may be in
-     a different AREA.  */
-#ifndef AOF_ASSEMBLER
   if (optimize > 0 && TREE_CONSTANT (decl))
     SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
-#endif
 
   default_encode_section_info (decl, rtl, first);
 }
@@ -17913,12 +17880,23 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
                     ? 1 : 0);
   if (mi_delta < 0)
     mi_delta = - mi_delta;
-  /* 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);
-      fputs ("\tldr\tr12, ", file);
+      /* Thunks are entered in arm mode when avaiable.  */
+      if (TARGET_THUMB1_ONLY)
+       {
+         /* push r3 so we can use it as a temporary.  */
+         /* TODO: Omit this save if r3 is not used.  */
+         fputs ("\tpush {r3}\n", file);
+         fputs ("\tldr\tr3, ", file);
+       }
+      else
+       {
+         fputs ("\tldr\tr12, ", file);
+       }
       assemble_name (file, label);
       fputc ('\n', file);
       if (flag_pic)
@@ -17932,29 +17910,63 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
 
             Note that we have "+ 1" because some versions of GNU ld
             don't set the low bit of the result for R_ARM_REL32
-            relocations against thumb function symbols.  */
+            relocations against thumb function symbols.
+            On ARMv6M this is +4, not +8.  */
          ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
          assemble_name (file, labelpc);
          fputs (":\n", file);
-         fputs ("\tadd\tr12, pc, r12\n", file);
+         if (TARGET_THUMB1_ONLY)
+           {
+             /* This is 2 insns after the start of the thunk, so we know it
+                is 4-byte aligned.  */
+             fputs ("\tadd\tr3, pc, r3\n", file);
+             fputs ("\tmov r12, r3\n", file);
+           }
+         else
+           fputs ("\tadd\tr12, pc, r12\n", file);
        }
+      else if (TARGET_THUMB1_ONLY)
+       fputs ("\tmov r12, r3\n", file);
     }
-  /* TODO: Use movw/movt for large constants when available.  */
-  while (mi_delta != 0)
+  if (TARGET_THUMB1_ONLY)
     {
-      if ((mi_delta & (3 << shift)) == 0)
-        shift += 2;
-      else
-        {
-          asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
-                       mi_op, this_regno, this_regno,
-                       mi_delta & (0xff << shift));
-          mi_delta &= ~(0xff << shift);
-          shift += 8;
-        }
+      if (mi_delta > 255)
+       {
+         fputs ("\tldr\tr3, ", file);
+         assemble_name (file, label);
+         fputs ("+4\n", file);
+         asm_fprintf (file, "\t%s\t%r, %r, r3\n",
+                      mi_op, this_regno, this_regno);
+       }
+      else if (mi_delta != 0)
+       {
+         asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
+                      mi_op, this_regno, this_regno,
+                      mi_delta);
+       }
+    }
+  else
+    {
+      /* TODO: Use movw/movt for large constants when available.  */
+      while (mi_delta != 0)
+       {
+         if ((mi_delta & (3 << shift)) == 0)
+           shift += 2;
+         else
+           {
+             asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
+                          mi_op, this_regno, this_regno,
+                          mi_delta & (0xff << shift));
+             mi_delta &= ~(0xff << shift);
+             shift += 8;
+           }
+       }
     }
   if (TARGET_THUMB1)
     {
+      if (TARGET_THUMB1_ONLY)
+       fputs ("\tpop\t{r3}\n", file);
+
       fprintf (file, "\tbx\tr12\n");
       ASM_OUTPUT_ALIGN (file, 2);
       assemble_name (file, label);
@@ -17973,6 +17985,9 @@ arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
       else
        /* Output ".word .LTHUNKn".  */
        assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
+
+      if (TARGET_THUMB1_ONLY && mi_delta > 255)
+       assemble_integer (GEN_INT(mi_delta), 4, BITS_PER_WORD, 1);
     }
   else
     {
@@ -18050,14 +18065,20 @@ arm_output_load_gr (rtx *operands)
 
 static void
 arm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
-                           enum machine_mode mode ATTRIBUTE_UNUSED,
-                           tree type ATTRIBUTE_UNUSED,
+                           enum machine_mode mode,
+                           tree type,
                            int *pretend_size,
                            int second_time ATTRIBUTE_UNUSED)
 {
+  int nregs = cum->nregs;
+  if (nregs & 1
+      && ARM_DOUBLEWORD_ALIGN
+      && arm_needs_doubleword_align (mode, type))
+    nregs++;
+
   cfun->machine->uses_anonymous_args = 1;
-  if (cum->nregs < NUM_ARG_REGS)
-    *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
+  if (nregs < NUM_ARG_REGS)
+    *pretend_size = (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
 }
 
 /* Return nonzero if the CONSUMER instruction (a store) does not need
@@ -18297,7 +18318,8 @@ arm_cxx_key_method_may_be_inline (void)
 static void
 arm_cxx_determine_class_data_visibility (tree decl)
 {
-  if (!TARGET_AAPCS_BASED)
+  if (!TARGET_AAPCS_BASED
+      || !TARGET_DLLIMPORT_DECL_ATTRIBUTES)
     return;
 
   /* In general, \S 3.2.5.5 of the ARM EABI requires that class data
@@ -18337,7 +18359,8 @@ arm_set_return_address (rtx source, rtx scratch)
   rtx addr;
   unsigned long saved_regs;
 
-  saved_regs = arm_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  saved_regs = offsets->saved_regs_mask;
 
   if ((saved_regs & (1 << LR_REGNUM)) == 0)
     emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
@@ -18348,7 +18371,6 @@ arm_set_return_address (rtx source, rtx scratch)
       else
        {
          /* LR will be the first saved register.  */
-         offsets = arm_get_frame_offsets ();
          delta = offsets->outgoing_args - (offsets->frame + 4);
 
 
@@ -18379,13 +18401,12 @@ thumb_set_return_address (rtx source, rtx scratch)
   rtx addr;
   unsigned long mask;
 
-  emit_insn (gen_rtx_USE (VOIDmode, source));
+  emit_use (source);
 
-  mask = thumb1_compute_save_reg_mask ();
+  offsets = arm_get_frame_offsets ();
+  mask = offsets->saved_regs_mask;
   if (mask & (1 << LR_REGNUM))
     {
-      offsets = arm_get_frame_offsets ();
-
       limit = 1024;
       /* Find the saved regs.  */
       if (frame_pointer_needed)
@@ -18696,6 +18717,11 @@ arm_unwind_emit (FILE * asm_out_file, rtx insn)
   if (!ARM_EABI_UNWIND_TABLES)
     return;
 
+  if (!(flag_unwind_tables || crtl->uses_eh_lsda)
+      && (TREE_NOTHROW (current_function_decl)
+         || crtl->all_throwers_are_sibcalls))
+    return;
+
   if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
     return;
 
@@ -18776,7 +18802,17 @@ arm_output_fn_unwind (FILE * f, bool prologue)
   if (prologue)
     fputs ("\t.fnstart\n", f);
   else
-    fputs ("\t.fnend\n", f);
+    {
+      /* If this function will never be unwound, then mark it as such.
+         The came condition is used in arm_unwind_emit to suppress
+        the frame annotations.  */
+      if (!(flag_unwind_tables || crtl->uses_eh_lsda)
+         && (TREE_NOTHROW (current_function_decl)
+             || crtl->all_throwers_are_sibcalls))
+       fputs("\t.cantunwind\n", f);
+
+      fputs ("\t.fnend\n", f);
+    }
 }
 
 static bool
@@ -18928,6 +18964,22 @@ thumb2_output_casesi (rtx *operands)
     }
 }
 
+/* Most ARM cores are single issue, but some newer ones can dual issue.
+   The scheduler descriptions rely on this being correct.  */
+static int
+arm_issue_rate (void)
+{
+  switch (arm_tune)
+    {
+    case cortexr4:
+    case cortexa8:
+      return 2;
+
+    default:
+      return 1;
+    }
+}
+
 /* A table and a function to perform ARM-specific name mangling for
    NEON vector types in order to conform to the AAPCS (see "Procedure
    Call Standard for the ARM Architecture", Appendix A).  To qualify