]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/arm/arm.c
basic-block.h (first_insn_after_basic_block_note): Declare.
[gcc.git] / gcc / config / arm / arm.c
index bcdcd2452da1c404f929c1e728dc59ef1753784c..24c3317bd30b4d0501a8bfaecbce07326d043425 100644 (file)
@@ -1,5 +1,6 @@
 /* Output routines for GCC for ARM.
-   Copyright (C) 1991, 93, 94, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+   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).
@@ -25,13 +26,12 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "rtl.h"
 #include "tree.h"
-#include "tm_p.h"
+#include "obstack.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -42,7 +42,11 @@ Boston, MA 02111-1307, USA.  */
 #include "recog.h"
 #include "ggc.h"
 #include "except.h"
+#include "c-pragma.h"
+#include "integrate.h"
 #include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
 
 /* Forward definitions of types.  */
 typedef struct minipool_node    Mnode;
@@ -53,32 +57,33 @@ typedef struct minipool_fixup   Mfix;
 #define Hint     HOST_WIDE_INT
 #define Mmode    enum machine_mode
 #define Ulong    unsigned long
+#define Ccstar   const char *
 
 /* Forward function declarations.  */
 static void      arm_add_gc_roots              PARAMS ((void));
 static int       arm_gen_constant              PARAMS ((enum rtx_code, Mmode, Hint, rtx, rtx, int, int));
-static int       arm_naked_function_p          PARAMS ((tree));
 static Ulong     bit_count                     PARAMS ((signed int));
 static int       const_ok_for_op               PARAMS ((Hint, enum rtx_code));
 static int       eliminate_lr2ip               PARAMS ((rtx *));
 static rtx      emit_multi_reg_push            PARAMS ((int));
 static rtx      emit_sfm                       PARAMS ((int, int));
-static const char * fp_const_from_val          PARAMS ((REAL_VALUE_TYPE *));
+static Ccstar    fp_const_from_val             PARAMS ((REAL_VALUE_TYPE *));
 static arm_cc    get_arm_condition_code                PARAMS ((rtx));
 static void      init_fpa_table                        PARAMS ((void));
 static Hint      int_log2                      PARAMS ((Hint));
 static rtx       is_jump_table                         PARAMS ((rtx));
-static const char * output_multi_immediate     PARAMS ((rtx *, const char *, const char *, int, Hint));
-static void      print_multi_reg               PARAMS ((FILE *, const char *, int, int, int));
+static Ccstar    output_multi_immediate                PARAMS ((rtx *, Ccstar, Ccstar, int, Hint));
+static void      print_multi_reg               PARAMS ((FILE *, Ccstar, int, int));
 static Mmode     select_dominance_cc_mode      PARAMS ((rtx, rtx, Hint));
-static const char * shift_op                   PARAMS ((rtx, Hint *));
+static Ccstar    shift_op                      PARAMS ((rtx, Hint *));
 static void      arm_init_machine_status       PARAMS ((struct function *));
 static void      arm_mark_machine_status        PARAMS ((struct function *));
+static void      arm_free_machine_status        PARAMS ((struct function *));
 static int       number_of_first_bit_set        PARAMS ((int));
 static void      replace_symbols_in_block       PARAMS ((tree, rtx, rtx));
 static void      thumb_exit                     PARAMS ((FILE *, int, rtx));
 static void      thumb_pushpop                  PARAMS ((FILE *, int, int));
-static const char * thumb_condition_code        PARAMS ((rtx, int));
+static Ccstar    thumb_condition_code           PARAMS ((rtx, int));
 static rtx      is_jump_table                  PARAMS ((rtx));
 static Hint     get_jump_table_size            PARAMS ((rtx));
 static Mnode *   move_minipool_fix_forward_ref  PARAMS ((Mnode *, Mnode *, Hint));
@@ -93,10 +98,52 @@ static Mfix *    create_fix_barrier         PARAMS ((Mfix *, Hint));
 static void     push_minipool_barrier          PARAMS ((rtx, Hint));
 static void     push_minipool_fix              PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
 static void     note_invalid_constants         PARAMS ((rtx, Hint));
-\f
+static int       current_file_function_operand PARAMS ((rtx));
+static Ulong     arm_compute_save_reg_mask     PARAMS ((void));
+static Ulong     arm_isr_value                         PARAMS ((tree));
+static Ulong     arm_compute_func_type         PARAMS ((void));
+static int      arm_valid_type_attribute_p     PARAMS ((tree, tree,
+                                                        tree, tree));
+static int      arm_valid_decl_attribute_p     PARAMS ((tree, tree,
+                                                        tree, tree));
+static int      arm_comp_type_attributes       PARAMS ((tree, tree));
+static void     arm_set_default_type_attributes        PARAMS ((tree));
 #undef Hint
 #undef Mmode
 #undef Ulong
+#undef Ccstar
+\f
+/* Initialize the GCC target structure.  */
+#ifdef TARGET_DLLIMPORT_DECL_ATTRIBUTES
+#undef TARGET_MERGE_DECL_ATTRIBUTES
+#define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
+#endif
+
+#undef TARGET_VALID_TYPE_ATTRIBUTE
+#define TARGET_VALID_TYPE_ATTRIBUTE arm_valid_type_attribute_p
+
+#undef TARGET_VALID_DECL_ATTRIBUTE
+#ifdef ARM_PE
+   static int arm_pe_valid_decl_attribute_p PARAMS ((tree, tree, tree, tree));
+#  define TARGET_VALID_DECL_ATTRIBUTE arm_pe_valid_decl_attribute_p
+#else
+#  define TARGET_VALID_DECL_ATTRIBUTE arm_valid_decl_attribute_p
+#endif
+
+#undef TARGET_COMP_TYPE_ATTRIBUTES
+#define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
+
+#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
+#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
+
+struct gcc_target target = TARGET_INITIALIZER;
+\f
+/* Obstack for minipool constant handling.  */
+static struct obstack minipool_obstack;
+static char *minipool_startobj;
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
 
 /* The maximum number of insns skipped which will be conditionalised if
    possible.  */
@@ -137,6 +184,8 @@ int    arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
 #define FL_THUMB      (1 << 6)        /* Thumb aware */
 #define FL_LDSCHED    (1 << 7)       /* Load scheduling necessary */
 #define FL_STRONG     (1 << 8)       /* StrongARM */
+#define FL_ARCH5E     (1 << 9)        /* DSP extenstions to v5 */
+#define FL_XSCALE     (1 << 10)              /* XScale */
 
 /* The bits in this mask specify which instructions we are
    allowed to generate.  */
@@ -160,12 +209,18 @@ int arm_arch4 = 0;
 /* Nonzero if this chip supports the ARM Architecture 5 extensions.  */
 int arm_arch5 = 0;
 
+/* Nonzero if this chip supports the ARM Architecture 5E extensions.  */
+int arm_arch5e = 0;
+
 /* Nonzero if this chip can benefit from load scheduling.  */
 int arm_ld_sched = 0;
 
 /* Nonzero if this chip is a StrongARM.  */
 int arm_is_strong = 0;
 
+/* Nonzero if this chip is an XScale.  */
+int arm_is_xscale = 0;
+
 /* Nonzero if this chip is a an ARM6 or an ARM7.  */
 int arm_is_6_or_7 = 0;
 
@@ -244,7 +299,10 @@ static struct processors all_cores[] =
   {"arm700",   FL_CO_PROC | FL_MODE26 | FL_MODE32 },
   {"arm700i",  FL_CO_PROC | FL_MODE26 | FL_MODE32 },
   {"arm710",                FL_MODE26 | FL_MODE32 },
+  {"arm710t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
   {"arm720",                FL_MODE26 | FL_MODE32 },
+  {"arm720t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
+  {"arm740t",               FL_MODE26 | FL_MODE32                           | FL_THUMB },
   {"arm710c",               FL_MODE26 | FL_MODE32 },
   {"arm7100",               FL_MODE26 | FL_MODE32 },
   {"arm7500",               FL_MODE26 | FL_MODE32 },
@@ -256,10 +314,16 @@ static struct processors all_cores[] =
   {"arm9",                              FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm920",                            FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
   {"arm920t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
+  {"arm940t",                           FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
   {"arm9tdmi",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED },
+  {"arm9e",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED },
   {"strongarm",                     FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm110",           FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
   {"strongarm1100",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
+  {"strongarm1110",          FL_MODE26 | FL_MODE32 | FL_FAST_MULT | FL_ARCH4 |            FL_LDSCHED | FL_STRONG },
+  {"arm10tdmi",                                 FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
+  {"arm1020t",                          FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED             | FL_ARCH5 },
+  {"xscale",                             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_LDSCHED | FL_STRONG | FL_ARCH5 | FL_ARCH5E | FL_XSCALE },
   
   {NULL, 0}
 };
@@ -277,6 +341,8 @@ static struct processors all_architectures[] =
      implementations that support it, so we will leave it out for now.  */
   { "armv4t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB },
   { "armv5",     FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
+  { "armv5t",    FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 },
+  { "armv5te",   FL_CO_PROC |             FL_MODE32 | FL_FAST_MULT | FL_ARCH4 | FL_THUMB | FL_ARCH5 | FL_ARCH5E },
   { NULL, 0 }
 };
 
@@ -301,8 +367,8 @@ bit_count (value)
   
   while (value)
     {
-      value &= ~(value & - value);
-      ++ count;
+      value &= ~(value & -value);
+      ++count;
     }
 
   return count;
@@ -316,7 +382,7 @@ arm_override_options ()
   unsigned i;
   
   /* Set up the flags based on the cpu/architecture selected by the user.  */
-  for (i = sizeof (arm_select) / sizeof (arm_select[0]); i--;)
+  for (i = ARRAY_SIZE (arm_select); i--;)
     {
       struct arm_cpu_select * ptr = arm_select + i;
       
@@ -324,7 +390,7 @@ arm_override_options ()
         {
          const struct processors * sel;
 
-          for (sel = ptr->processors; sel->name != NULL; sel ++)
+          for (sel = ptr->processors; sel->name != NULL; sel++)
             if (streq (ptr->string, sel->name))
               {
                if (i == 2)
@@ -373,13 +439,14 @@ arm_override_options ()
        { TARGET_CPU_arm810,    "arm810" },
        { TARGET_CPU_arm9,      "arm9" },
        { TARGET_CPU_strongarm, "strongarm" },
+       { TARGET_CPU_xscale,    "xscale" },
        { TARGET_CPU_generic,   "arm" },
        { 0, 0 }
       };
       struct cpu_default * def;
          
       /* Find the default.  */
-      for (def = cpu_defaults; def->name; def ++)
+      for (def = cpu_defaults; def->name; def++)
        if (def->cpu == TARGET_CPU_DEFAULT)
          break;
 
@@ -388,7 +455,7 @@ arm_override_options ()
        abort ();
       
       /* Find the default CPU's flags.  */
-      for (sel = all_cores; sel->name != NULL; sel ++)
+      for (sel = all_cores; sel->name != NULL; sel++)
        if (streq (def->name, sel->name))
          break;
       
@@ -412,9 +479,9 @@ arm_override_options ()
             interworking.  Therefore we force FL_MODE26 to be removed
             from insn_flags here (if it was set), so that the search
             below will always be able to find a compatible processor.  */
-         insn_flags &= ~ FL_MODE26;
+         insn_flags &= ~FL_MODE26;
        }
-      else if (! TARGET_APCS_32)
+      else if (!TARGET_APCS_32)
        sought |= FL_MODE26;
       
       if (sought != 0 && ((sought & insn_flags) != sought))
@@ -422,7 +489,7 @@ arm_override_options ()
          /* Try to locate a CPU type that supports all of the abilities
             of the default CPU, plus the extra abilities requested by
             the user.  */
-         for (sel = all_cores; sel->name != NULL; sel ++)
+         for (sel = all_cores; sel->name != NULL; sel++)
            if ((sel->flags & sought) == (sought | insn_flags))
              break;
 
@@ -444,7 +511,7 @@ arm_override_options ()
                 options.  Instead if we cannot find a cpu that has both the
                 characteristics of the default cpu and the given command line
                 options we scan the array again looking for a best match.  */
-             for (sel = all_cores; sel->name != NULL; sel ++)
+             for (sel = all_cores; sel->name != NULL; sel++)
                if ((sel->flags & sought) == sought)
                  {
                    unsigned int count;
@@ -482,9 +549,9 @@ arm_override_options ()
         "-mapcs-32 -mcpu=arm2" then we loose here.  */
       if ((TARGET_DEFAULT & ARM_FLAG_APCS_32) == 0)
        warning ("target CPU does not support APCS-32" );
-      target_flags &= ~ ARM_FLAG_APCS_32;
+      target_flags &= ~ARM_FLAG_APCS_32;
     }
-  else if (! TARGET_APCS_32 && !(insn_flags & FL_MODE26))
+  else if (!TARGET_APCS_32 && !(insn_flags & FL_MODE26))
     {
       warning ("target CPU does not support APCS-26" );
       target_flags |= ARM_FLAG_APCS_32;
@@ -498,7 +565,7 @@ arm_override_options ()
   
   if (TARGET_THUMB && !(insn_flags & FL_THUMB))
     {
-      warning ("target CPU does not supoport THUMB instructions.");
+      warning ("target CPU does not support THUMB instructions.");
       target_flags &= ~ARM_FLAG_THUMB;
     }
 
@@ -507,7 +574,7 @@ arm_override_options ()
       /* warning ("ignoring -mapcs-frame because -mthumb was used."); */
       target_flags &= ~ARM_FLAG_APCS_FRAME;
     }
-  
+
   /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done
      from here where no function is being compiled currently.  */
   if ((target_flags & (THUMB_FLAG_LEAF_BACKTRACE | THUMB_FLAG_BACKTRACE))
@@ -523,12 +590,12 @@ arm_override_options ()
   /* If interworking is enabled then APCS-32 must be selected as well.  */
   if (TARGET_INTERWORK)
     {
-      if (! TARGET_APCS_32)
+      if (!TARGET_APCS_32)
        warning ("interworking forces APCS-32 to be used" );
       target_flags |= ARM_FLAG_APCS_32;
     }
   
-  if (TARGET_APCS_STACK && ! TARGET_APCS_FRAME)
+  if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
     {
       warning ("-mapcs-stack-check incompatible with -mno-apcs-frame");
       target_flags |= ARM_FLAG_APCS_FRAME;
@@ -538,7 +605,7 @@ arm_override_options ()
     target_flags |= ARM_FLAG_APCS_FRAME;
   
   if (TARGET_APCS_REENT && flag_pic)
-    fatal ("-fpic and -mapcs-reent are incompatible");
+    error ("-fpic and -mapcs-reent are incompatible");
   
   if (TARGET_APCS_REENT)
     warning ("APCS reentrant code not supported.  Ignored");
@@ -547,13 +614,13 @@ arm_override_options ()
      are turned off and debugging is turned on.  */
   if (TARGET_ARM
       && write_symbols != NO_DEBUG
-      && ! TARGET_APCS_FRAME
+      && !TARGET_APCS_FRAME
       && (TARGET_DEFAULT & ARM_FLAG_APCS_FRAME))
     warning ("-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_APCS_STACK)
+  if (flag_pic && !TARGET_APCS_STACK)
     arm_pic_register = 10;
   
   if (TARGET_APCS_FLOAT)
@@ -563,13 +630,15 @@ arm_override_options ()
   arm_fast_multiply = (insn_flags & FL_FAST_MULT) != 0;
   arm_arch4         = (insn_flags & FL_ARCH4) != 0;
   arm_arch5         = (insn_flags & FL_ARCH5) != 0;
-  
+  arm_arch5e        = (insn_flags & FL_ARCH5E) != 0;
+  arm_is_xscale     = (insn_flags & FL_XSCALE) != 0;
+
   arm_ld_sched      = (tune_flags & FL_LDSCHED) != 0;
   arm_is_strong     = (tune_flags & FL_STRONG) != 0;
   thumb_code       = (TARGET_ARM == 0);
   arm_is_6_or_7     = (((tune_flags & (FL_MODE26 | FL_MODE32))
                       && !(tune_flags & FL_ARCH4))) != 0;
-  
+
   /* Default value for floating point code... if no co-processor
      bus, then schedule for emulated floating point.  Otherwise,
      assume the user has an FPA.
@@ -584,7 +653,7 @@ arm_override_options ()
       else if (streq (target_fp_name, "3"))
        arm_fpu_arch = FP_SOFT3;
       else
-       fatal ("Invalid floating point emulation option: -mfpe-%s",
+       error ("Invalid floating point emulation option: -mfpe-%s",
               target_fp_name);
     }
   else
@@ -615,7 +684,7 @@ arm_override_options ()
     {
       int pic_register;
 
-      if (! flag_pic)
+      if (!flag_pic)
        warning ("-mpic-register= is useless without -fpic");
 
       pic_register = decode_reg_name (arm_pic_register_string);
@@ -642,6 +711,9 @@ arm_override_options ()
   if (optimize_size || (tune_flags & FL_LDSCHED))
     arm_constant_limit = 1;
   
+  if (arm_is_xscale)
+    arm_constant_limit = 2;
+
   /* If optimizing for size, bump the number of instructions that we
      are prepared to conditionally execute (even on a StrongARM). 
      Otherwise for the StrongARM, which has early execution of branches,
@@ -660,27 +732,155 @@ arm_add_gc_roots ()
 {
   ggc_add_rtx_root (&arm_compare_op0, 1);
   ggc_add_rtx_root (&arm_compare_op1, 1);
-  ggc_add_rtx_root (&arm_target_insn, 1); /* Not sure this is really a root */
-  /* XXX: What about the minipool tables?  */
+  ggc_add_rtx_root (&arm_target_insn, 1); /* Not sure this is really a root.  */
+
+  gcc_obstack_init(&minipool_obstack);
+  minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
+}
+\f
+/* A table of known ARM exception types.
+   For use with the interrupt function attribute.  */
+
+typedef struct
+{
+  const char *         arg;
+  unsigned long        return_value;
+}
+isr_attribute_arg;
+
+static isr_attribute_arg isr_attribute_args [] =
+{
+  { "IRQ",   ARM_FT_ISR },
+  { "irq",   ARM_FT_ISR },
+  { "FIQ",   ARM_FT_FIQ },
+  { "fiq",   ARM_FT_FIQ },
+  { "ABORT", ARM_FT_ISR },
+  { "abort", ARM_FT_ISR },
+  { "ABORT", ARM_FT_ISR },
+  { "abort", ARM_FT_ISR },
+  { "UNDEF", ARM_FT_EXCEPTION },
+  { "undef", ARM_FT_EXCEPTION },
+  { "SWI",   ARM_FT_EXCEPTION },
+  { "swi",   ARM_FT_EXCEPTION },
+  { NULL,    ARM_FT_NORMAL }
+};
+
+/* Returns the (interrupt) function type of the current
+   function, or ARM_FT_UNKNOWN if the type cannot be determined.  */
+
+static unsigned long
+arm_isr_value (argument)
+     tree argument;
+{
+  isr_attribute_arg * ptr;
+  const char *        arg;
+
+  /* No argument - default to IRQ.  */
+  if (argument == NULL_TREE)
+    return ARM_FT_ISR;
+
+  /* Get the value of the argument.  */
+  if (TREE_VALUE (argument) == NULL_TREE
+      || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
+    return ARM_FT_UNKNOWN;
+
+  arg = TREE_STRING_POINTER (TREE_VALUE (argument));
+
+  /* Check it against the list of known arguments.  */
+  for (ptr = isr_attribute_args; ptr->arg != NULL; ptr ++)
+    if (strcmp (arg, ptr->arg) == 0)
+       return ptr->return_value;
+
+  /* An unrecognised interrupt type.  */
+  return ARM_FT_UNKNOWN;
+}
+
+/* Computes the type of the current function.  */
+
+static unsigned long
+arm_compute_func_type ()
+{
+  unsigned long type = ARM_FT_UNKNOWN;
+  tree a;
+  tree attr;
+  
+  if (TREE_CODE (current_function_decl) != FUNCTION_DECL)
+    abort ();
+
+  /* Decide if the current function is volatile.  Such functions
+     never return, and many memory cycles can be saved by not storing
+     register values that will never be needed again.  This optimization
+     was added to speed up context switching in a kernel application.  */
+  if (optimize > 0
+      && current_function_nothrow
+      && TREE_THIS_VOLATILE (current_function_decl))
+    type |= ARM_FT_VOLATILE;
+  
+  if (current_function_needs_context)
+    type |= ARM_FT_NESTED;
+
+  attr = DECL_MACHINE_ATTRIBUTES (current_function_decl);
+  
+  a = lookup_attribute ("naked", attr);
+  if (a != NULL_TREE)
+    type |= ARM_FT_NAKED;
+
+  if (cfun->machine->eh_epilogue_sp_ofs != NULL_RTX)
+    type |= ARM_FT_EXCEPTION_HANDLER;
+  else
+    {
+      a = lookup_attribute ("isr", attr);
+      if (a == NULL_TREE)
+       a = lookup_attribute ("interrupt", attr);
+      
+      if (a == NULL_TREE)
+       type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
+      else
+       type |= arm_isr_value (TREE_VALUE (a));
+    }
+  
+  return type;
+}
+
+/* Returns the type of the current function.  */
+
+unsigned long
+arm_current_func_type ()
+{
+  if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
+    cfun->machine->func_type = arm_compute_func_type ();
+
+  return cfun->machine->func_type;
 }
 \f
 /* Return 1 if it is possible to return using a single instruction.  */
+
 int
 use_return_insn (iscond)
      int iscond;
 {
   int regno;
+  unsigned int func_type;
 
   /* Never use a return instruction before reload has run.  */
-  if (! reload_completed
-      /* Or if the function is variadic.  */
-      || current_function_pretend_args_size
+  if (!reload_completed)
+    return 0;
+      
+  func_type = arm_current_func_type ();
+
+  /* Naked functions, volatile functiond and interrupt
+     functions all need special consideration.  */
+  if (func_type & (ARM_FT_INTERRUPT | ARM_FT_VOLATILE | ARM_FT_NAKED))
+    return 0;
+  
+  /* As do variadic functions.  */
+  if (current_function_pretend_args_size
       || current_function_anonymous_args
       /* Of if the function calls __builtin_eh_return () */
-      || cfun->machine->eh_epilogue_sp_ofs != NULL
+      || ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
       /* Or if there is no frame pointer and there is a stack adjustment.  */
       || ((get_frame_size () + current_function_outgoing_args_size != 0)
-         && ! frame_pointer_needed))
+         && !frame_pointer_needed))
     return 0;
 
   /* Can't be done if interworking with Thumb, and any registers have been
@@ -693,24 +893,20 @@ use_return_insn (iscond)
       || TARGET_INTERWORK)
     {
       for (regno = 0; regno <= LAST_ARM_REGNUM; regno++)
-       if (regs_ever_live[regno] && ! call_used_regs[regno])
+       if (regs_ever_live[regno] && !call_used_regs[regno])
          return 0;
 
       if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
        return 0;
     }
       
-  /* Can't be done if any of the FPU regs are pushed, since this also
-     requires an insn.  */
+  /* Can't be done if any of the FPU regs are pushed,
+     since this also requires an insn.  */
   if (TARGET_HARD_FLOAT)
     for (regno = FIRST_ARM_FP_REGNUM; regno <= LAST_ARM_FP_REGNUM; regno++)
-      if (regs_ever_live[regno] && ! call_used_regs[regno])
+      if (regs_ever_live[regno] && !call_used_regs[regno])
        return 0;
 
-  /* If a function is naked, don't use the "return" insn.  */
-  if (arm_naked_function_p (current_function_decl))
-    return 0;
-
   return 1;
 }
 
@@ -720,14 +916,14 @@ int
 const_ok_for_arm (i)
      HOST_WIDE_INT i;
 {
-  unsigned HOST_WIDE_INT mask = ~ HOST_UINT (0xFF);
+  unsigned HOST_WIDE_INT mask = ~HOST_UINT (0xFF);
 
   /* For machines with >32 bit HOST_WIDE_INT, the bits above bit 31 must 
      be all zero, or all one.  */
-  if ((i & ~ HOST_UINT (0xffffffff)) != 0
-      && ((i & ~ HOST_UINT (0xffffffff)) 
-         != ((~ HOST_UINT (0))
-             & ~ HOST_UINT (0xffffffff))))
+  if ((i & ~HOST_UINT (0xffffffff)) != 0
+      && ((i & ~HOST_UINT (0xffffffff)) 
+         != ((~HOST_UINT (0))
+             & ~HOST_UINT (0xffffffff))))
     return FALSE;
   
   /* Fast return for 0 and powers of 2 */
@@ -741,7 +937,7 @@ const_ok_for_arm (i)
       mask =
          (mask << 2) | ((mask & HOST_UINT (0xffffffff))
                         >> (32 - 2)) | ~(HOST_UINT (0xffffffff));
-    } while (mask != ~ HOST_UINT (0xFF));
+    } while (mask != ~HOST_UINT (0xFF));
 
   return FALSE;
 }
@@ -805,7 +1001,7 @@ arm_split_constant (code, mode, val, target, source, subtargets)
 
         Ref: gcc -O1 -mcpu=strongarm gcc.c-torture/compile/980506-2.c
       */
-      if (! after_arm_reorg
+      if (!after_arm_reorg
          && (arm_gen_constant (code, mode, val, target, source, 1, 0)
              > arm_constant_limit + (code != SET)))
        {
@@ -837,6 +1033,33 @@ arm_split_constant (code, mode, val, target, source, subtargets)
   return arm_gen_constant (code, mode, val, target, source, subtargets, 1);
 }
 
+static int
+count_insns_for_constant (HOST_WIDE_INT remainder, int i)
+{
+  HOST_WIDE_INT temp1;
+  int num_insns = 0;
+  do
+    {
+      int end;
+         
+      if (i <= 0)
+       i += 32;
+      if (remainder & (3 << (i - 2)))
+       {
+         end = i - 8;
+         if (end < 0)
+           end += 32;
+         temp1 = remainder & ((0x0ff << end)
+                                   | ((i < end) ? (0xff >> (32 - end)) : 0));
+         remainder &= ~temp1;
+         num_insns++;
+         i -= 6;
+       }
+      i -= 2;
+    } while (remainder);
+  return num_insns;
+}
+
 /* As above, but extra parameter GENERATE which, if clear, suppresses
    RTL generation.  */
 static int
@@ -1062,7 +1285,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
            {
              if ((((temp2 | (temp2 << i))
                    & HOST_UINT (0xffffffff)) == remainder)
-                 && ! const_ok_for_arm (temp2))
+                 && !const_ok_for_arm (temp2))
                {
                  rtx new_src = (subtargets
                                 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
@@ -1085,7 +1308,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
          for (i = 17; i < 24; i++)
            {
              if (((temp1 | (temp1 >> i)) == remainder)
-                 && ! const_ok_for_arm (temp1))
+                 && !const_ok_for_arm (temp1))
                {
                  rtx new_src = (subtargets
                                 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
@@ -1114,9 +1337,9 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
         then this can be done in two instructions instead of 3-4.  */
       if (subtargets
          /* TARGET can't be NULL if SUBTARGETS is 0 */
-         || (reload_completed && ! reg_mentioned_p (target, source)))
+         || (reload_completed && !reg_mentioned_p (target, source)))
        {
-         if (const_ok_for_arm (ARM_SIGN_EXTEND (~ val)))
+         if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
            {
              if (generate)
                {
@@ -1175,7 +1398,7 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
          return 2;
        }
 
-      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~ val)))
+      if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
        {
          if (generate)
            {
@@ -1301,9 +1524,9 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
       {
        int consecutive_zeros = 0;
 
-       if (! (remainder & (3 << i)))
+       if (!(remainder & (3 << i)))
          {
-           while ((i < 32) && ! (remainder & (3 << i)))
+           while ((i < 32) && !(remainder & (3 << i)))
              {
                consecutive_zeros += 2;
                i += 2;
@@ -1317,9 +1540,36 @@ arm_gen_constant (code, mode, val, target, source, subtargets, generate)
          }
       }
 
-    /* Now start emitting the insns, starting with the one with the highest
-       bit set: we do this so that the smallest number will be emitted last;
-       this is more likely to be combinable with addressing insns.  */
+    /* 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 (ie 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;
     do
       {
@@ -1404,11 +1654,10 @@ arm_canonicalize_comparison (code, op1)
 
     case GT:
     case LE:
-      if (i != (((HOST_UINT (1)) << (HOST_BITS_PER_WIDE_INT - 1))
-               - 1)
-         && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1))))
+      if (i != (((HOST_UINT (1)) << (HOST_BITS_PER_WIDE_INT - 1)) - 1)
+         && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
        {
-         *op1 = GEN_INT (i+1);
+         *op1 = GEN_INT (i + 1);
          return code == GT ? GE : LT;
        }
       break;
@@ -1416,17 +1665,17 @@ arm_canonicalize_comparison (code, op1)
     case GE:
     case LT:
       if (i != ((HOST_UINT (1)) << (HOST_BITS_PER_WIDE_INT - 1))
-         && (const_ok_for_arm (i-1) || const_ok_for_arm (- (i-1))))
+         && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
        {
-         *op1 = GEN_INT (i-1);
+         *op1 = GEN_INT (i - 1);
          return code == GE ? GT : LE;
        }
       break;
 
     case GTU:
     case LEU:
-      if (i != ~ (HOST_UINT (0))
-         && (const_ok_for_arm (i+1) || const_ok_for_arm (- (i+1))))
+      if (i != ~(HOST_UINT (0))
+         && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
        {
          *op1 = GEN_INT (i + 1);
          return code == GTU ? GEU : LTU;
@@ -1436,7 +1685,7 @@ arm_canonicalize_comparison (code, op1)
     case GEU:
     case LTU:
       if (i != 0
-         && (const_ok_for_arm (i - 1) || const_ok_for_arm (- (i - 1))))
+         && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
        {
          *op1 = GEN_INT (i - 1);
          return code == GEU ? GTU : LEU;
@@ -1457,7 +1706,7 @@ int
 arm_return_in_memory (type)
      tree type;
 {
-  if (! AGGREGATE_TYPE_P (type))
+  if (!AGGREGATE_TYPE_P (type))
     /* All simple types are returned in registers.  */
     return 0;
   
@@ -1499,7 +1748,7 @@ arm_return_in_memory (type)
         a register are not allowed.  */
       if (RETURN_IN_MEMORY (TREE_TYPE (field)))
        return 1;
-      
+
       /* Now check the remaining fields, if any.  Only bitfields are allowed,
         since they are not addressable.  */
       for (field = TREE_CHAIN (field);
@@ -1509,7 +1758,7 @@ arm_return_in_memory (type)
          if (TREE_CODE (field) != FIELD_DECL)
            continue;
          
-         if (! DECL_BIT_FIELD_TYPE (field))
+         if (!DECL_BIT_FIELD_TYPE (field))
            return 1;
        }
 
@@ -1596,7 +1845,7 @@ arm_function_arg (pcum, mode, type, named)
     /* Compute operand 2 of the call insn.  */
     return GEN_INT (pcum->call_cookie);
   
-  if (! named || pcum->nregs >= NUM_ARG_REGS)
+  if (!named || pcum->nregs >= NUM_ARG_REGS)
     return NULL_RTX;
   
   return gen_rtx_REG (mode, pcum->nregs);
@@ -1612,32 +1861,32 @@ typedef enum
 
 static arm_pragma_enum arm_pragma_long_calls = OFF;
 
-/* Handle pragmas for compatibility with Intel's compilers.
-   FIXME: This is incomplete, since it does not handle all
-   the pragmas that the Intel compilers understand.  */
-int
-arm_process_pragma (p_getc, p_ungetc, pname)
-     int (*  p_getc)   PARAMS ((void)) ATTRIBUTE_UNUSED;
-     void (* p_ungetc) PARAMS ((int))  ATTRIBUTE_UNUSED;
-     char *  pname;
-{
-  /* Should be pragma 'far' or equivalent for callx/balx here.  */
-  if (strcmp (pname, "long_calls") == 0)
-    arm_pragma_long_calls = LONG;
-  else if (strcmp (pname, "no_long_calls") == 0)
-    arm_pragma_long_calls = SHORT;
-  else if (strcmp (pname, "long_calls_off") == 0)
-    arm_pragma_long_calls = OFF;
-  else
-    return 0;
-  
-  return 1;
+void
+arm_pr_long_calls (pfile)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+  arm_pragma_long_calls = LONG;
+}
+
+void
+arm_pr_no_long_calls (pfile)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+  arm_pragma_long_calls = SHORT;
+}
+
+void
+arm_pr_long_calls_off (pfile)
+     cpp_reader *pfile ATTRIBUTE_UNUSED;
+{
+  arm_pragma_long_calls = OFF;
 }
+
 \f
-/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
-   attribute for TYPE.  The attributes in ATTRIBUTES have previously been
-   assigned to TYPE.  */
-int
+/* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine
+   specific attribute for TYPE.  The attributes in ATTRIBUTES have
+   previously been assigned to TYPE.  */
+static int
 arm_valid_type_attribute_p (type, attributes, identifier, args)
      tree type;
      tree attributes ATTRIBUTE_UNUSED;
@@ -1661,13 +1910,18 @@ arm_valid_type_attribute_p (type, attributes, identifier, args)
   if (is_attribute_p ("short_call", identifier))
     return (args == NULL_TREE);
   
+  /* Interrupt Service Routines have special prologue and epilogue requirements.  */ 
+  if (is_attribute_p ("isr", identifier)
+      || is_attribute_p ("interrupt", identifier))
+    return arm_isr_value (args);
+
   return 0;
 }
 
 /* Return 0 if the attributes for two types are incompatible, 1 if they
    are compatible, and 2 if they are nearly compatible (which causes a
    warning to be generated).  */
-int
+static int
 arm_comp_type_attributes (type1, type2)
      tree type1;
      tree type2;
@@ -1696,6 +1950,16 @@ arm_comp_type_attributes (type1, type2)
        return 0;
     }
   
+  /* Check for mismatched ISR attribute.  */
+  l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
+  if (! l1)
+    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
+  l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
+  if (! l2)
+    l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
+  if (l1 != l2)
+    return 0;
+
   return 1;
 }
 
@@ -1716,21 +1980,19 @@ arm_encode_call_attribute (decl, flag)
   /* Do not allow weak functions to be treated as short call.  */
   if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
     return;
-  
-  if (ggc_p)
-    newstr = ggc_alloc_string (NULL, len + 2);
-  else
-    newstr = permalloc (len + 2);
 
-  sprintf (newstr, "%c%s", flag, str);
+  newstr = alloca (len + 2);
+  newstr[0] = flag;
+  strcpy (newstr + 1, str);
 
+  newstr = (char *) ggc_alloc_string (newstr, len + 1);
   XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
 }
 
 /*  Assigns default attributes to newly defined type.  This is used to
     set short_call/long_call attributes for function types of
     functions defined inside corresponding #pragma scopes.  */
-void
+static void
 arm_set_default_type_attributes (type)
   tree type;
 {
@@ -1767,11 +2029,11 @@ current_file_function_operand (sym_ref)
   if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
     return 1;
 
-  /* The current funciton is always defined within the current compilation
+  /* The current function is always defined within the current compilation
      unit.  if it s a weak defintion however, then this may not be the real
      defintion of the function, and so we have to say no.  */
   if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
-      && ! DECL_WEAK (current_function_decl))
+      && !DECL_WEAK (current_function_decl))
     return 1;
 
   /* We cannot make the determination - default to returning 0.  */
@@ -1805,7 +2067,7 @@ arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
   int call_cookie;
   int call_symbol;
 {
-  if (! call_symbol)
+  if (!call_symbol)
     {
       if (GET_CODE (sym_ref) != MEM)
        return 0;
@@ -1822,13 +2084,52 @@ arm_is_longcall_p (sym_ref, call_cookie, call_symbol)
   if (TARGET_LONG_CALLS && flag_function_sections)
     return 1;
   
-  if (current_file_function_operand (sym_ref, VOIDmode))
+  if (current_file_function_operand (sym_ref))
     return 0;
   
   return (call_cookie & CALL_LONG)
     || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
     || TARGET_LONG_CALLS;
 }
+
+/* Return non-zero if it is ok to make a tail-call to DECL.  */
+int
+arm_function_ok_for_sibcall (decl)
+     tree decl;
+{
+  int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
+
+  /* Never tailcall something for which we have no decl, or if we
+     are in Thumb mode.  */
+  if (decl == NULL || TARGET_THUMB)
+    return 0;
+
+  /* Get the calling method.  */
+  if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+    call_type = CALL_SHORT;
+  else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
+    call_type = CALL_LONG;
+
+  /* Cannot tail-call to long calls, since these are out of range of
+     a branch instruction.  However, if not compiling PIC, we know
+     we can reach the symbol if it is in this compilation unit.  */
+  if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
+    return 0;
+
+  /* If we are interworking and the function is not declared static
+     then we can't tail-call it unless we know that it exists in this 
+     compilation unit (since it might be a Thumb routine).  */
+  if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
+    return 0;
+
+  /* Never tailcall from an ISR routine - it needs a special exit sequence.  */
+  if (IS_INTERRUPT (arm_current_func_type ()))
+    return 0;
+
+  /* Everything else is ok.  */
+  return 1;
+}
+
 \f
 int
 legitimate_pic_operand_p (x)
@@ -1859,7 +2160,7 @@ legitimize_pic_address (orig, mode, reg)
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
+         if (no_new_pseudos)
            abort ();
          else
            reg = gen_reg_rtx (Pmode);
@@ -1877,7 +2178,10 @@ legitimize_pic_address (orig, mode, reg)
       else
        address = reg;
 
-      emit_insn (gen_pic_load_addr (address, orig));
+      if (TARGET_ARM)
+       emit_insn (gen_pic_load_addr_arm (address, orig));
+      else
+       emit_insn (gen_pic_load_addr_thumb (address, orig));
 
       pic_ref = gen_rtx_MEM (Pmode,
                             gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
@@ -1902,7 +2206,7 @@ legitimize_pic_address (orig, mode, reg)
 
       if (reg == 0)
        {
-         if (reload_in_progress || reload_completed)
+         if (no_new_pseudos)
            abort ();
          else
            reg = gen_reg_rtx (Pmode);
@@ -1921,16 +2225,16 @@ legitimize_pic_address (orig, mode, reg)
        {
          /* The base register doesn't really matter, we only want to
             test the index for the appropriate mode.  */
-         GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win);
+         ARM_GO_IF_LEGITIMATE_INDEX (mode, 0, offset, win);
 
-         if (! reload_in_progress && ! reload_completed)
+         if (!no_new_pseudos)
            offset = force_reg (Pmode, offset);
          else
            abort ();
 
        win:
          if (GET_CODE (offset) == CONST_INT)
-           return plus_constant_for_output (base, INTVAL (offset));
+           return plus_constant (base, INTVAL (offset));
        }
 
       if (GET_MODE_SIZE (mode) > 4
@@ -1950,8 +2254,12 @@ legitimize_pic_address (orig, mode, reg)
       if (NEED_GOT_RELOC)
        {
          rtx pic_ref, address = gen_reg_rtx (Pmode);
-         
-         emit_insn (gen_pic_load_addr (address, orig));
+
+         if (TARGET_ARM)
+           emit_insn (gen_pic_load_addr_arm (address, orig));
+         else
+           emit_insn (gen_pic_load_addr_thumb (address, orig));
+
          pic_ref = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, address);
          
          emit_move_insn (address, pic_ref);
@@ -1962,28 +2270,24 @@ legitimize_pic_address (orig, mode, reg)
   return orig;
 }
 
-static rtx pic_rtx;
-
-int
-is_pic (x)
-     rtx x;
-{
-  if (x == pic_rtx)
-    return 1;
-  return 0;
-}
+/* Generate code to load the PIC register.  PROLOGUE is true if
+   called from arm_expand_prologue (in which case we want the 
+   generated insns at the start of the function);  false if called
+   by an exception receiver that needs the PIC register reloaded
+   (in which case the insns are just dumped at the current location).  */
 
 void
-arm_finalize_pic ()
+arm_finalize_pic (prologue)
+     int prologue;
 {
 #ifndef AOF_ASSEMBLER
-  rtx l1, pic_tmp, pic_tmp2, seq;
+  rtx l1, pic_tmp, pic_tmp2, seq, pic_rtx;
   rtx global_offset_table;
 
   if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
     return;
 
-  if (! flag_pic)
+  if (!flag_pic)
     abort ();
 
   start_sequence ();
@@ -2001,15 +2305,23 @@ arm_finalize_pic ()
 
   pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
   
-  emit_insn (gen_pic_load_addr (pic_offset_table_rtx, pic_rtx));
   if (TARGET_ARM)
-    emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
+    {
+      emit_insn (gen_pic_load_addr_arm (pic_offset_table_rtx, pic_rtx));
+      emit_insn (gen_pic_add_dot_plus_eight (pic_offset_table_rtx, l1));
+    }
   else
-    emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
+    {
+      emit_insn (gen_pic_load_addr_thumb (pic_offset_table_rtx, pic_rtx));
+      emit_insn (gen_pic_add_dot_plus_four (pic_offset_table_rtx, l1));
+    }
 
   seq = gen_sequence ();
   end_sequence ();
-  emit_insn_after (seq, get_insns ());
+  if (prologue)
+    emit_insn_after (seq, get_insns ());
+  else
+    emit_insn (seq);
 
   /* Need to emit this whether or not we obey regdecls,
      since setjmp/longjmp can cause life info to screw up.  */
@@ -2062,7 +2374,7 @@ arm_rtx_costs (x, code, outer)
              while (i)                                         
                {                                                       
                  i >>= 2;                                              
-                 cycles ++;                                            
+                 cycles++;                                             
                }                                                       
              return COSTS_N_INSNS (2) + cycles;                        
            }
@@ -2384,11 +2696,11 @@ arm_rtx_costs (x, code, outer)
       if (const_ok_for_arm (INTVAL (x)))                       
        return outer == SET ? 2 : -1;                   
       else if (outer == AND                            
-              && const_ok_for_arm (~ INTVAL (x)))              
+              && const_ok_for_arm (~INTVAL (x)))               
        return -1;                                              
       else if ((outer == COMPARE                       
                || outer == PLUS || outer == MINUS)     
-              && const_ok_for_arm (- INTVAL (x)))              
+              && const_ok_for_arm (-INTVAL (x)))               
        return -1;                                              
       else                                                     
        return 5;
@@ -2420,6 +2732,47 @@ arm_adjust_cost (insn, link, dep, cost)
 {
   rtx i_pat, d_pat;
 
+  /* Some true dependencies can have a higher cost depending
+     on precisely how certain input operands are used.  */
+  if (arm_is_xscale
+      && REG_NOTE_KIND (link) == 0
+      && recog_memoized (insn) < 0
+      && recog_memoized (dep) < 0)
+    {
+      int shift_opnum = get_attr_shift (insn);
+      enum attr_type attr_type = get_attr_type (dep);
+
+      /* If nonzero, SHIFT_OPNUM contains the operand number of a shifted
+        operand for INSN.  If we have a shifted input operand and the
+        instruction we depend on is another ALU instruction, then we may
+        have to account for an additional stall.  */
+      if (shift_opnum != 0 && attr_type == TYPE_NORMAL)
+       {
+         rtx shifted_operand;
+         int opno;
+         
+         /* Get the shifted operand.  */
+         extract_insn (insn);
+         shifted_operand = recog_data.operand[shift_opnum];
+
+         /* Iterate over all the operands in DEP.  If we write an operand
+            that overlaps with SHIFTED_OPERAND, then we have increase the
+            cost of this dependency.  */
+         extract_insn (dep);
+         preprocess_constraints ();
+         for (opno = 0; opno < recog_data.n_operands; opno++)
+           {
+             /* We can ignore strict inputs.  */
+             if (recog_data.operand_type[opno] == OP_IN)
+               continue;
+
+             if (reg_overlap_mentioned_p (recog_data.operand[opno],
+                                          shifted_operand))
+               return 2;
+           }
+       }
+    }
+
   /* XXX This is not strictly true for the FPA.  */
   if (REG_NOTE_KIND (link) == REG_DEP_ANTI
       || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
@@ -2554,6 +2907,19 @@ s_register_operand (op, mode)
              || REGNO_REG_CLASS (REGNO (op)) != NO_REGS));
 }
 
+/* A hard register operand (even before reload.  */
+int
+arm_hard_register_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  if (GET_MODE (op) != mode && mode != VOIDmode)
+    return 0;
+
+  return (GET_CODE (op) == REG
+         && REGNO (op) < FIRST_PSEUDO_REGISTER);
+}
+    
 /* Only accept reg, subreg(reg), const_int.  */
 
 int
@@ -2586,7 +2952,7 @@ arm_reload_memory_operand (op, mode)
 {
   int regno = true_regnum (op);
 
-  return (! CONSTANT_P (op)
+  return (!CONSTANT_P (op)
          && (regno == -1
              || (GET_CODE (op) == REG
                  && REGNO (op) >= FIRST_PSEUDO_REGISTER)));
@@ -2604,7 +2970,7 @@ bad_signed_byte_operand (op, mode)
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
 #if 0
-  if ((mode == QImode && ! memory_operand (op, mode)) || GET_CODE (op) != MEM)
+  if ((mode == QImode && !memory_operand (op, mode)) || GET_CODE (op) != MEM)
     return 0;
 #endif
   if (GET_CODE (op) != MEM)
@@ -2614,8 +2980,8 @@ bad_signed_byte_operand (op, mode)
 
   /* A sum of anything more complex than reg + reg or reg + const is bad.  */
   if ((GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
-      && (! s_register_operand (XEXP (op, 0), VOIDmode)
-         || (! s_register_operand (XEXP (op, 1), VOIDmode)
+      && (!s_register_operand (XEXP (op, 0), VOIDmode)
+         || (!s_register_operand (XEXP (op, 1), VOIDmode)
              && GET_CODE (XEXP (op, 1)) != CONST_INT)))
     return 1;
 
@@ -2999,6 +3365,17 @@ equality_operator (x, mode)
   return GET_CODE (x) == EQ || GET_CODE (x) == NE;
 }
 
+/* Return TRUE if x is a comparison operator other than LTGT or UNEQ.  */
+int
+arm_comparison_operator (x, mode)
+     rtx x;
+     enum machine_mode mode;
+{
+  return (comparison_operator (x, mode)
+         && GET_CODE (x) != LTGT
+         && GET_CODE (x) != UNEQ);
+}
+
 /* Return TRUE for SMIN SMAX UMIN UMAX operators.  */
 int
 minmax_operator (x, mode)
@@ -3226,7 +3603,7 @@ load_multiple_operation (op, mode)
           || GET_CODE (SET_SRC (elt)) != MEM
           || GET_MODE (SET_SRC (elt)) != SImode
           || GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
-          || ! rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
+          || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
           || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
           || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != (i - base) * 4)
         return 0;
@@ -3288,7 +3665,7 @@ store_multiple_operation (op, mode)
           || GET_CODE (SET_DEST (elt)) != MEM
           || GET_MODE (SET_DEST (elt)) != SImode
           || GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
-          || ! rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
+          || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
           || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
           || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != (i - base) * 4)
         return 0;
@@ -3723,7 +4100,7 @@ multi_register_push (op, mode)
   if (GET_CODE (op) != PARALLEL
       || (GET_CODE (XVECEXP (op, 0, 0)) != SET)
       || (GET_CODE (SET_SRC (XVECEXP (op, 0, 0))) != UNSPEC)
-      || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != 2))
+      || (XINT (SET_SRC (XVECEXP (op, 0, 0)), 1) != UNSPEC_PUSH_MULT))
     return 0;
 
   return 1;
@@ -3741,22 +4118,32 @@ multi_register_push (op, mode)
      don't output any prologue or epilogue code, the user is assumed
      to do the right thing.
    
+   isr or interrupt:
+     Interrupt Service Routine.
+
    interfacearm:
      Always assume that this function will be entered in ARM mode,
      not Thumb mode, and that the caller wishes to be returned to in
      ARM mode.  */
-int
-arm_valid_machine_decl_attribute (decl, attr, args)
+static int
+arm_valid_decl_attribute_p (decl, attributes, attr, args)
      tree decl;
+     tree attributes ATTRIBUTE_UNUSED;
      tree attr;
      tree args;
 {
+  /* The interrupt attribute can take args, so check for it before
+     rejecting other attributes on the grounds that they did have args.  */
+  if (is_attribute_p ("isr", attr)
+      || is_attribute_p ("interrupt", attr))
+    return TREE_CODE (decl) == FUNCTION_DECL;
+
   if (args != NULL_TREE)
     return 0;
 
   if (is_attribute_p ("naked", attr))
     return TREE_CODE (decl) == FUNCTION_DECL;
-  
+
 #ifdef ARM_PE
   if (is_attribute_p ("interfacearm", attr))
     return TREE_CODE (decl) == FUNCTION_DECL;
@@ -3765,19 +4152,38 @@ arm_valid_machine_decl_attribute (decl, attr, args)
   return 0;
 }
 
-/* Return non-zero if FUNC is a naked function.  */
+#ifdef ARM_PE
+
+/* ARM/PE has three new attributes:
+   naked - for interrupt functions
+   dllexport - for exporting a function/variable that will live in a dll
+   dllimport - for importing a function/variable from a dll
+
+   Microsoft allows multiple declspecs in one __declspec, separating
+   them with spaces.  We do NOT support this.  Instead, use __declspec
+   multiple times.
+*/
+
 static int
-arm_naked_function_p (func)
-     tree func;
+arm_pe_valid_decl_attribute_p (decl, attributes, attr, args)
+     tree decl;
+     tree attributes;
+     tree attr;
+     tree args;
 {
-  tree a;
+  if (args != NULL_TREE)
+    return 0;
 
-  if (TREE_CODE (func) != FUNCTION_DECL)
-    abort ();
+  if (is_attribute_p ("dllexport", attr))
+    return 1;
   
-  a = lookup_attribute ("naked", DECL_MACHINE_ATTRIBUTES (func));
-  return a != NULL_TREE;
+  if (is_attribute_p ("dllimport", attr))
+    return 1;
+
+  return arm_valid_decl_attribute_p (decl, attributes, attr, args);
 }
+
+#endif /* ARM_PE  */
 \f
 /* Routines for use in generating RTL.  */
 rtx
@@ -3797,6 +4203,58 @@ arm_gen_load_multiple (base_regno, count, from, up, write_back, unchanging_p,
   int sign = up ? 1 : -1;
   rtx mem;
 
+  /* XScale has load-store double instructions, but they have stricter
+     alignment requirements than load-store multiple, so we can not
+     use them.
+
+     For XScale ldm requires 2 + NREGS cycles to complete and blocks
+     the pipeline until completion.
+
+       NREGS           CYCLES
+         1               3
+         2               4
+         3               5
+         4               6
+
+     An ldr instruction takes 1-3 cycles, but does not block the
+     pipeline.
+
+       NREGS           CYCLES
+         1              1-3
+         2              2-6
+         3              3-9
+         4              4-12
+
+     Best case ldr will always win.  However, the more ldr instructions
+     we issue, the less likely we are to be able to schedule them well.
+     Using ldr instructions also increases code size.
+
+     As a compromise, we use ldr for counts of 1 or 2 regs, and ldm
+     for counts of 3 or 4 regs.  */
+  if (arm_is_xscale && count <= 2 && ! optimize_size)
+    {
+      rtx seq;
+      
+      start_sequence ();
+      
+      for (i = 0; i < count; i++)
+       {
+         mem = gen_rtx_MEM (SImode, plus_constant (from, i * 4 * sign));
+         RTX_UNCHANGING_P (mem) = unchanging_p;
+         MEM_IN_STRUCT_P (mem) = in_struct_p;
+         MEM_SCALAR_P (mem) = scalar_p;
+         emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
+       }
+
+      if (write_back)
+       emit_move_insn (from, plus_constant (from, count * 4 * sign));
+
+      seq = gen_sequence ();
+      end_sequence ();
+      
+      return seq;
+    }
+
   result = gen_rtx_PARALLEL (VOIDmode,
                             rtvec_alloc (count + (write_back ? 1 : 0)));
   if (write_back)
@@ -3838,6 +4296,32 @@ arm_gen_store_multiple (base_regno, count, to, up, write_back, unchanging_p,
   int sign = up ? 1 : -1;
   rtx mem;
 
+  /* See arm_gen_load_multiple for discussion of
+     the pros/cons of ldm/stm usage for XScale.  */
+  if (arm_is_xscale && count <= 2 && ! optimize_size)
+    {
+      rtx seq;
+      
+      start_sequence ();
+      
+      for (i = 0; i < count; i++)
+       {
+         mem = gen_rtx_MEM (SImode, plus_constant (to, i * 4 * sign));
+         RTX_UNCHANGING_P (mem) = unchanging_p;
+         MEM_IN_STRUCT_P (mem) = in_struct_p;
+         MEM_SCALAR_P (mem) = scalar_p;
+         emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
+       }
+
+      if (write_back)
+       emit_move_insn (to, plus_constant (to, count * 4 * sign));
+
+      seq = gen_sequence ();
+      end_sequence ();
+      
+      return seq;
+    }
+
   result = gen_rtx_PARALLEL (VOIDmode,
                             rtvec_alloc (count + (write_back ? 1 : 0)));
   if (write_back)
@@ -4072,6 +4556,14 @@ arm_gen_rotated_half_load (memref)
   return gen_rtx_ROTATE (SImode, base, GEN_INT (16));
 }
 
+/* Select a dominance comparison mode if possible.  We support three forms.
+   COND_OR == 0 => (X && Y) 
+   COND_OR == 1 => ((! X( || Y)
+   COND_OR == 2 => (X || Y) 
+   If we are unable to support a dominance comparsison we return CC mode.  
+   This will then fail to match for the RTL expressions that generate this
+   call.  */
+
 static enum machine_mode
 select_dominance_cc_mode (x, y, cond_or)
      rtx x;
@@ -4090,14 +4582,17 @@ select_dominance_cc_mode (x, y, cond_or)
          != CCmode))
     return CCmode;
 
-  if (cond_or)
+  /* The if_then_else variant of this tests the second condition if the
+     first passes, but is true if the first fails.  Reverse the first
+     condition to get a true "inclusive-or" expression.  */
+  if (cond_or == 1)
     cond1 = reverse_condition (cond1);
 
   /* If the comparisons are not equal, and one doesn't dominate the other,
      then we can't do this.  */
   if (cond1 != cond2 
-      && ! comparison_dominates_p (cond1, cond2)
-      && (swapped = 1, ! comparison_dominates_p (cond2, cond1)))
+      && !comparison_dominates_p (cond1, cond2)
+      && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
     return CCmode;
 
   if (swapped)
@@ -4110,7 +4605,7 @@ select_dominance_cc_mode (x, y, cond_or)
   switch (cond1)
     {
     case EQ:
-      if (cond2 == EQ || ! cond_or)
+      if (cond2 == EQ || !cond_or)
        return CC_DEQmode;
 
       switch (cond2)
@@ -4125,7 +4620,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case LT:
-      if (cond2 == LT || ! cond_or)
+      if (cond2 == LT || !cond_or)
        return CC_DLTmode;
       if (cond2 == LE)
        return CC_DLEmode;
@@ -4134,7 +4629,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case GT:
-      if (cond2 == GT || ! cond_or)
+      if (cond2 == GT || !cond_or)
        return CC_DGTmode;
       if (cond2 == GE)
        return CC_DGEmode;
@@ -4143,7 +4638,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
       
     case LTU:
-      if (cond2 == LTU || ! cond_or)
+      if (cond2 == LTU || !cond_or)
        return CC_DLTUmode;
       if (cond2 == LEU)
        return CC_DLEUmode;
@@ -4152,7 +4647,7 @@ select_dominance_cc_mode (x, y, cond_or)
       break;
 
     case GTU:
-      if (cond2 == GTU || ! cond_or)
+      if (cond2 == GTU || !cond_or)
        return CC_DGTUmode;
       if (cond2 == GEU)
        return CC_DGEUmode;
@@ -4193,7 +4688,31 @@ arm_select_cc_mode (op, x, y)
   /* All floating point compares return CCFP if it is an equality
      comparison, and CCFPE otherwise.  */
   if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
-    return (op == EQ || op == NE) ? CCFPmode : CCFPEmode;
+    {
+      switch (op)
+       {
+       case EQ:
+       case NE:
+       case UNORDERED:
+       case ORDERED:
+       case UNLT:
+       case UNLE:
+       case UNGT:
+       case UNGE:
+       case UNEQ:
+       case LTGT:
+         return CCFPmode;
+
+       case LT:
+       case LE:
+       case GT:
+       case GE:
+         return CCFPEmode;
+
+       default:
+         abort ();
+       }
+    }
   
   /* A compare with a shifted operand.  Because of canonicalization, the
      comparison will have to be swapped when we emit the assembler.  */
@@ -4218,6 +4737,29 @@ arm_select_cc_mode (op, x, y)
       && GET_CODE (y) == CONST_INT)
     return CC_Zmode;
 
+  /* A construct for a conditional compare, if the false arm contains
+     0, then both conditions must be true, otherwise either condition
+     must be true.  Not all conditions are possible, so CCmode is
+     returned if it can't be done.  */
+  if (GET_CODE (x) == IF_THEN_ELSE
+      && (XEXP (x, 2) == const0_rtx
+         || XEXP (x, 2) == const1_rtx)
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
+    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 
+                                    INTVAL (XEXP (x, 2)));
+
+  /* Alternate canonicalizations of the above.  These are somewhat cleaner.  */
+  if (GET_CODE (x) == AND
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
+    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 0);
+
+  if (GET_CODE (x) == IOR
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
+      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
+    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 2);
+
   /* An operation that sets the condition codes as a side-effect, the
      V flag is not set correctly, so we can only use comparisons where
      this doesn't matter.  (For LT and GE we can use "mi" and "pl"
@@ -4234,18 +4776,6 @@ arm_select_cc_mode (op, x, y)
          || GET_CODE (x) == ROTATERT || GET_CODE (x) == ZERO_EXTRACT))
     return CC_NOOVmode;
 
-  /* A construct for a conditional compare, if the false arm contains
-     0, then both conditions must be true, otherwise either condition
-     must be true.  Not all conditions are possible, so CCmode is
-     returned if it can't be done.  */
-  if (GET_CODE (x) == IF_THEN_ELSE
-      && (XEXP (x, 2) == const0_rtx
-         || XEXP (x, 2) == const1_rtx)
-      && GET_RTX_CLASS (GET_CODE (XEXP (x, 0))) == '<'
-      && GET_RTX_CLASS (GET_CODE (XEXP (x, 1))) == '<')
-    return select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1), 
-                                    INTVAL (XEXP (x, 2)));
-
   if (GET_MODE (x) == QImode && (op == EQ || op == NE))
     return CC_Zmode;
 
@@ -4285,11 +4815,7 @@ arm_reload_in_hi (operands)
 
   if (GET_CODE (ref) == SUBREG)
     {
-      offset = SUBREG_WORD (ref) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref)))
-                  - MIN (UNITS_PER_WORD,
-                         GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref)))));
+      offset = SUBREG_BYTE (ref);
       ref = SUBREG_REG (ref);
     }
 
@@ -4368,7 +4894,7 @@ arm_reload_in_hi (operands)
                                   gen_rtx_MEM (QImode, 
                                                plus_constant (base,
                                                               offset + 1))));
-  if (! BYTES_BIG_ENDIAN)
+  if (!BYTES_BIG_ENDIAN)
     emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_SUBREG (SImode, operands[0], 0),
                        gen_rtx_IOR (SImode, 
                                     gen_rtx_ASHIFT
@@ -4402,11 +4928,7 @@ arm_reload_out_hi (operands)
 
   if (GET_CODE (ref) == SUBREG)
     {
-      offset = SUBREG_WORD (ref) * UNITS_PER_WORD;
-      if (BYTES_BIG_ENDIAN)
-       offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (ref)))
-                  - MIN (UNITS_PER_WORD,
-                         GET_MODE_SIZE (GET_MODE (SUBREG_REG (ref)))));
+      offset = SUBREG_BYTE (ref);
       ref = SUBREG_REG (ref);
     }
 
@@ -4442,7 +4964,7 @@ arm_reload_out_hi (operands)
        {
          /* Updating base_plus might destroy outval, see if we can
             swap the scratch and base_plus.  */
-         if (! reg_overlap_mentioned_p (scratch, outval))
+         if (!reg_overlap_mentioned_p (scratch, outval))
            {
              rtx tmp = scratch;
              scratch = base_plus;
@@ -4488,7 +5010,7 @@ arm_reload_out_hi (operands)
 
       hi = ((((offset - lo) & HOST_INT (0xffffffff))
             ^ HOST_INT (0x80000000))
-           -  HOST_INT (0x80000000));
+           - HOST_INT (0x80000000));
 
       if (hi + lo != offset)
        abort ();
@@ -4502,7 +5024,7 @@ arm_reload_out_hi (operands)
            {
              /* Updating base_plus might destroy outval, see if we
                 can swap the scratch and base_plus.  */
-             if (! reg_overlap_mentioned_p (scratch, outval))
+             if (!reg_overlap_mentioned_p (scratch, outval))
                {
                  rtx tmp = scratch;
                  scratch = base_plus;
@@ -5308,7 +5830,7 @@ create_fix_barrier (fix, max_address)
   emit_label_after (label, barrier);
 
   /* Create a minipool barrier entry for the new barrier.  */
-  new_fix = (Mfix *) oballoc (sizeof (* new_fix));
+  new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
   new_fix->insn = barrier;
   new_fix->address = selected_address;
   new_fix->next = fix->next;
@@ -5324,7 +5846,7 @@ push_minipool_barrier (insn, address)
      rtx insn;
      HOST_WIDE_INT address;
 {
-  Mfix * fix = (Mfix *) oballoc (sizeof (* fix));
+  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
   fix->insn = insn;
   fix->address = address;
@@ -5351,7 +5873,7 @@ push_minipool_fix (insn, address, loc, mode, value)
      enum machine_mode mode;
      rtx value;
 {
-  Mfix * fix = (Mfix *) oballoc (sizeof (* fix));
+  Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
 
 #ifdef AOF_ASSEMBLER
   /* PIC symbol refereneces need to be converted into offsets into the
@@ -5409,7 +5931,7 @@ note_invalid_constants (insn, address)
 
   extract_insn (insn);
 
-  if (! constrain_operands (1))
+  if (!constrain_operands (1))
     fatal_insn_not_found (insn);
 
   /* Fill in recog_op_alt with information about the constraints of this
@@ -5438,7 +5960,7 @@ note_invalid_constants (insn, address)
             this shouldn't be needed any more.  */
 #ifndef AOF_ASSEMBLER
          /* XXX Is this still needed?  */
-         else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == 3)
+         else if (GET_CODE (op) == UNSPEC && XINT (op, 1) == UNSPEC_PIC_SYM)
            push_minipool_fix (insn, address, recog_data.operand_loc[opno],
                               recog_data.operand_mode[opno],
                               XVECEXP (op, 0, 0));
@@ -5472,7 +5994,6 @@ arm_reorg (first)
   /* Scan all the insns and record the operands that will need fixing.  */
   for (insn = next_nonnote_insn (first); insn; insn = next_nonnote_insn (insn))
     {
-
       if (GET_CODE (insn) == BARRIER)
        push_minipool_barrier (insn, address);
       else if (GET_CODE (insn) == INSN || GET_CODE (insn) == CALL_INSN
@@ -5604,6 +6125,9 @@ arm_reorg (first)
      directly.  This can happen if the RTL gets split during final
      instruction generation.  */
   after_arm_reorg = 1;
+
+  /* Free the minipool memory.  */
+  obstack_free (&minipool_obstack, minipool_startobj);
 }
 \f
 /* Routines to output assembly language.  */
@@ -5636,7 +6160,7 @@ fp_const_from_val (r)
 {
   int i;
 
-  if (! fpa_consts_inited)
+  if (!fpa_consts_inited)
     init_fpa_table ();
 
   for (i = 0; i < 8; i++)
@@ -5648,16 +6172,15 @@ fp_const_from_val (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.
-   INSTR is the possibly suffixed base register.  HAT unequals zero if a hat
-   must follow the register list.  */
+   REG is the base register, either the frame pointer or the stack pointer,
+   INSTR is the possibly suffixed load or store instruction.  */
 
 static void
-print_multi_reg (stream, instr, reg, mask, hat)
+print_multi_reg (stream, instr, reg, mask)
      FILE * stream;
      const char * instr;
      int reg;
      int mask;
-     int hat;
 {
   int i;
   int not_first = FALSE;
@@ -5676,7 +6199,7 @@ print_multi_reg (stream, instr, reg, mask, hat)
        not_first = TRUE;
       }
 
-  fprintf (stream, "}%s\n", hat ? "^" : "");
+  fprintf (stream, "}%s\n", TARGET_APCS_32 ? "" : "^");
 }
 
 /* Output a 'call' insn.  */
@@ -5926,8 +6449,7 @@ output_move_double (operands)
              long l[2];
              union real_extract u;
 
-             bcopy ((char *) &CONST_DOUBLE_LOW (operands[1]), (char *) &u,
-                    sizeof (u));
+             memcpy (&u, &CONST_DOUBLE_LOW (operands[1]), sizeof (u));
              REAL_VALUE_TO_TARGET_DOUBLE (u.d, l);
              otherops[1] = GEN_INT (l[1]);
              operands[1] = GEN_INT (l[0]);
@@ -6047,7 +6569,7 @@ output_move_double (operands)
                 }
               else
                 {
-                 otherops[1] = adj_offsettable_operand (operands[1], 4);
+                 otherops[1] = adjust_address (operands[1], VOIDmode, 4);
                  /* Take care of overlapping base/data reg.  */
                  if (reg_mentioned_p (operands[0], operands[1]))
                    {
@@ -6113,7 +6635,7 @@ output_move_double (operands)
          /* Fall through */
 
         default:
-         otherops[0] = adj_offsettable_operand (operands[0], 4);
+         otherops[0] = adjust_address (operands[0], VOIDmode, 4);
          otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
          output_asm_insn ("str%?\t%1, %0", operands);
          output_asm_insn ("str%?\t%1, %0", otherops);
@@ -6427,14 +6949,14 @@ output_ascii_pseudo_op (stream, p, len)
        case '\"':
        case '\\':
          putc ('\\', stream);
-         len_so_far ++;
+         len_so_far++;
          /* drop through.  */
 
        default:
          if (c >= ' ' && c <= '~')
            {
              putc (c, stream);
-             len_so_far ++;
+             len_so_far++;
            }
          else
            {
@@ -6448,6 +6970,106 @@ output_ascii_pseudo_op (stream, p, len)
   fputs ("\"\n", stream);
 }
 \f
+/* Compute a bit mask of which registers need to be
+   saved on the stack for the current function.  */
+
+static unsigned long
+arm_compute_save_reg_mask ()
+{
+  unsigned int save_reg_mask = 0;
+  unsigned int reg;
+  unsigned long func_type = arm_current_func_type ();
+
+  if (IS_NAKED (func_type))
+    /* This should never really happen.  */
+    return 0;
+
+  /* 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)
+    save_reg_mask |=
+      (1 << ARM_HARD_FRAME_POINTER_REGNUM)
+      | (1 << IP_REGNUM)
+      | (1 << LR_REGNUM)
+      | (1 << PC_REGNUM);
+
+  /* Volatile functions do not return, so there
+     is no need to save any other registers.  */
+  if (IS_VOLATILE (func_type))
+    return save_reg_mask;
+
+  if (IS_INTERRUPT (func_type))
+    {
+      unsigned int max_reg;
+      
+      /* Interrupt functions must not corrupt any registers,
+        even call clobbered ones.  If this is a leaf function
+        we can just examine the registers used by the RTL, but
+        otherwise we have to assume that whatever function is
+        called might clobber anything, and so we have to save
+        all the call-clobbered registers as well.  */
+      if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
+       /* FIQ handlers have registers r8 - r12 banked, so
+          we only need to check r0 - r7, Normal ISRs only
+          bank r14 and r15, so ew must check up to r12.
+          r13 is the stack pointer which is always preserved,
+          so we do not need to consider it here.  */
+       max_reg = 7;
+      else
+       max_reg = 12;
+       
+      for (reg = 0; reg <= max_reg; reg++)
+       if (regs_ever_live[reg]
+           || (! current_function_is_leaf && call_used_regs [reg]))
+         save_reg_mask |= (1 << reg);
+    }
+  else
+    {
+      /* 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++)
+       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])
+       save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
+
+      /* If we aren't loading the PIC register,
+        don't stack it even though it may be live.  */
+      if (flag_pic
+         && ! TARGET_SINGLE_PIC_BASE 
+         && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
+       save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+    }
+
+  /* Decide if we need to save the link register.
+     Interrupt routines have their own banked link register,
+     so they never need to save it.
+     Otheriwse if we do not use the link register we do not need to save
+     it.  If we are pushing other registers onto the stack however, we
+     can save an instruction in the epilogue by pushing the link register
+     now and then popping it back into the PC.  This incurs extra memory
+     accesses though, so we only do it when optimising for size, and only
+     if we know that we will not need a fancy return sequence.  */
+  if (! IS_INTERRUPT (func_type)
+      && (regs_ever_live [LR_REGNUM]
+         || (save_reg_mask
+             && optimize_size
+             && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)))
+    save_reg_mask |= 1 << LR_REGNUM;
+
+  if (cfun->machine->lr_save_eliminated)
+    save_reg_mask &= ~ (1 << LR_REGNUM);
+
+  return save_reg_mask;
+}
+
+/* Generate a function exit sequence.  If REALLY_RETURN is true, then do
+   everything bar the final return instruction.  */
 
 const char *
 output_return_instruction (operand, really_return, reverse)
@@ -6455,17 +7077,18 @@ output_return_instruction (operand, really_return, reverse)
      int really_return;
      int reverse;
 {
+  char conditional[10];
   char instr[100];
-  int reg, live_regs = 0;
-  int volatile_func = arm_volatile_func ();
+  int reg;
+  unsigned long live_regs_mask;
+  unsigned long func_type;
+  
+  func_type = arm_current_func_type ();
 
-  /* If a function is naked, don't use the "return" insn.  */
-  if (arm_naked_function_p (current_function_decl))
+  if (IS_NAKED (func_type))
     return "";
-  
-  return_used_this_function = 1;
-  
-  if (TARGET_ABORT_NORETURN && volatile_func)
+
+  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
     {
       /* If this function was declared non-returning, and we have found a tail 
         call, then we have to trust that the called function won't return.  */
@@ -6483,137 +7106,165 @@ output_return_instruction (operand, really_return, reverse)
       
       return "";
     }
-      
-  if (current_function_calls_alloca && ! really_return)
-    abort ();
-  
-  for (reg = 0; reg <= 10; reg++)
-    if (regs_ever_live[reg] && ! call_used_regs[reg])
-      live_regs++;
 
-  if (! TARGET_APCS_FRAME
-      && ! frame_pointer_needed
-      && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-      && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-    live_regs++;
+  if (current_function_calls_alloca && !really_return)
+    abort ();
 
-  if (flag_pic && ! TARGET_SINGLE_PIC_BASE
-      && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    live_regs++;
+  /* Construct the conditional part of the instruction(s) to be emitted.  */
+  sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
 
-  if (live_regs || regs_ever_live[LR_REGNUM])
-    live_regs++;
+  return_used_this_function = 1;
 
-  if (frame_pointer_needed)
-    live_regs += 4;
+  live_regs_mask = arm_compute_save_reg_mask ();
 
   /* On some ARM architectures it is faster to use LDR rather than LDM to
-     load a single register.  On other architectures, the cost is the same.  */
-  if (live_regs == 1
-      && regs_ever_live[LR_REGNUM]
-      && ! really_return)
-    output_asm_insn (reverse ? "ldr%?%D0\t%|lr, [%|sp], #4" 
-                    : "ldr%?%d0\t%|lr, [%|sp], #4", &operand);
-  else if (live_regs == 1
-          && regs_ever_live[LR_REGNUM]
-          && TARGET_APCS_32)
-    output_asm_insn (reverse ? "ldr%?%D0\t%|pc, [%|sp], #4"
-                    : "ldr%?%d0\t%|pc, [%|sp], #4", &operand);
-  else if (live_regs)
-    {
-      if (! regs_ever_live[LR_REGNUM])
-        live_regs++;
+     load a single register.  On other architectures, the cost is the same.
+     In 26 bit mode we have to use LDM in order to be able to restore the CPSR.  */
+  if ((live_regs_mask  == (1 << LR_REGNUM))
+      && ! TARGET_INTERWORK
+      && ! IS_INTERRUPT (func_type)
+      && (! really_return || TARGET_APCS_32))
+    {
+      if (! really_return)
+       sprintf (instr, "ldr%s\t%%|lr, [%%|sp], #4", conditional);
+      else
+       sprintf (instr, "ldr%s\t%%|pc, [%%|sp], #4", conditional);
+    }
+  else if (live_regs_mask)
+    {
+      if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
+       /* There are two possible reasons for the IP register being saved.
+          Either a stack frame was created, in which case IP contains the
+          old stack pointer, or an ISR routine corrupted it.  If this in an
+          ISR routine then just restore IP, otherwise restore IP into SP.  */
+       if (! IS_INTERRUPT (func_type))
+         {
+           live_regs_mask &= ~ (1 << IP_REGNUM);
+           live_regs_mask |=   (1 << SP_REGNUM);
+         }
 
+      /* Generate the load multiple instruction to restore the registers.  */
       if (frame_pointer_needed)
-        strcpy (instr,
-               reverse ? "ldm%?%D0ea\t%|fp, {" : "ldm%?%d0ea\t%|fp, {");
+       sprintf (instr, "ldm%sea\t%%|fp, {", conditional);
       else
-        strcpy (instr, 
-               reverse ? "ldm%?%D0fd\t%|sp!, {" : "ldm%?%d0fd\t%|sp!, {");
+       sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
 
-      for (reg = 0; reg <= 10; reg++)
-        if (regs_ever_live[reg]
-           && (! call_used_regs[reg]
-               || (flag_pic && ! TARGET_SINGLE_PIC_BASE
-                   && reg == PIC_OFFSET_TABLE_REGNUM)))
-          {
+      for (reg = 0; reg <= SP_REGNUM; reg++)
+       if (live_regs_mask & (1 << reg))
+         {
            strcat (instr, "%|");
-            strcat (instr, reg_names[reg]);
-           if (--live_regs)
-              strcat (instr, ", ");
-          }
+           strcat (instr, reg_names[reg]);
+           strcat (instr, ", ");
+         }
 
-      if (frame_pointer_needed)
-        {
-         strcat (instr, "%|");
-          strcat (instr, reg_names[11]);
-          strcat (instr, ", ");
-         strcat (instr, "%|");
-          strcat (instr, reg_names[13]);
-          strcat (instr, ", ");
-         strcat (instr, "%|");
-         strcat (instr, TARGET_INTERWORK || (! really_return)
-                 ? reg_names[LR_REGNUM] : reg_names[PC_REGNUM] );
-        }
+      if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
+       {
+         /* If we are not restoring the LR register then we will
+            have added one too many commas to the list above.
+            Replace it with a closing brace.  */
+         instr [strlen (instr) - 2] =  '}';
+       }
       else
        {
-         if (! TARGET_APCS_FRAME
-             && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-             && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-           {
-             strcat (instr, "%|");
-             strcat (instr, reg_names[HARD_FRAME_POINTER_REGNUM]);
-             strcat (instr, ", ");
-           }
-         
          strcat (instr, "%|");
-         
-         if (TARGET_INTERWORK && really_return)
-           strcat (instr, reg_names[IP_REGNUM]);
+
+         /* At this point there should only be one or two registers left in
+            live_regs_mask: always LR, and possibly PC if we created a stack
+            frame.  LR contains the return address.  If we do not have any
+            special requirements for function exit (eg interworking, or ISR)
+            then we can load this value directly into the PC and save an
+            instruction.  */
+         if (! TARGET_INTERWORK
+             && ! IS_INTERRUPT (func_type)
+             && really_return)
+           strcat (instr, reg_names [PC_REGNUM]);
          else
-           strcat (instr, really_return ? reg_names[PC_REGNUM] : reg_names[LR_REGNUM]);
+           strcat (instr, reg_names [LR_REGNUM]);
+
+         strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
        }
-      
-      strcat (instr, (TARGET_APCS_32 || !really_return) ? "}" : "}^");
-      output_asm_insn (instr, &operand);
 
-      if (TARGET_INTERWORK && really_return)
+      if (really_return)
        {
-         strcpy (instr, "bx%?");
-         strcat (instr, reverse ? "%D0" : "%d0");
-         strcat (instr, "\t%|");
-         strcat (instr, frame_pointer_needed ? "lr" : "ip");
+         /* See if we need to generate an extra instruction to
+            perform the actual function return.  */
+         switch ((int) ARM_FUNC_TYPE (func_type))
+           {
+           case ARM_FT_ISR:
+           case ARM_FT_FIQ:
+             output_asm_insn (instr, & operand);
+
+             strcpy (instr, "sub");
+             strcat (instr, conditional);
+             strcat (instr, "s\t%|pc, %|lr, #4");
+             break;
+
+           case ARM_FT_EXCEPTION:
+             output_asm_insn (instr, & operand);
 
-         output_asm_insn (instr, & operand);
+             strcpy (instr, "mov");
+             strcat (instr, conditional);
+             strcat (instr, "s\t%|pc, %|lr");
+             break;
+
+           case ARM_FT_INTERWORKED:
+             output_asm_insn (instr, & operand);
+
+             strcpy (instr, "bx");
+             strcat (instr, conditional);
+             strcat (instr, "\t%|lr");
+             break;
+
+           default:
+             /* The return has already been handled
+                by loading the LR into the PC.  */
+             if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
+               {
+                 output_asm_insn (instr, & operand);
+
+                 strcpy (instr, "mov");
+                 strcat (instr, conditional);
+                 if (! TARGET_APCS_32)
+                   strcat (instr, "s");
+                 strcat (instr, "\t%|pc, %|lr");
+               }
+             break;
+           }
        }
     }
   else if (really_return)
     {
-      if (TARGET_INTERWORK)
-       sprintf (instr, "bx%%?%%%s0\t%%|lr", reverse ? "D" : "d");
-      else
-       sprintf (instr, "mov%%?%%%s0%s\t%%|pc, %%|lr",
-                reverse ? "D" : "d", TARGET_APCS_32 ? "" : "s");
-      
-      output_asm_insn (instr, & operand);
+      switch ((int) ARM_FUNC_TYPE (func_type))
+       {
+       case ARM_FT_ISR:
+       case ARM_FT_FIQ:
+         sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
+         break;
+
+       case ARM_FT_INTERWORKED:
+         sprintf (instr, "bx%s\t%%|lr", conditional);
+         break;
+
+       case ARM_FT_EXCEPTION:
+         sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
+         break;
+
+       default:
+         sprintf (instr, "mov%s%s\t%%|pc, %%|lr",
+                  conditional, TARGET_APCS_32 ? "" : "s");
+         break;
+       }
     }
+  else
+    /* Nothing to load off the stack, and
+       no return instruction to generate.  */
+    return "";
 
+  output_asm_insn (instr, & operand);
+      
   return "";
 }
 
-/* Return nonzero if optimizing and the current function is volatile.
-   Such functions never return, and many memory cycles can be saved
-   by not storing register values that will never be needed again.
-   This optimization was added to speed up context switching in a
-   kernel application.  */
-int
-arm_volatile_func ()
-{
-  return (optimize > 0
-         && current_function_nothrow
-         && TREE_THIS_VOLATILE (current_function_decl));
-}
-
 /* Write the function name into the code section, directly preceding
    the function prologue.
 
@@ -6659,79 +7310,70 @@ arm_poke_function_name (stream, name)
   ASM_OUTPUT_INT (stream, x);
 }
 
-/* The amount of stack adjustment that happens here, in output_return and in
-   output_epilogue must be exactly the same as was calculated during reload,
-   or things will point to the wrong place.  The only time we can safely
-   ignore this constraint is when a function has no arguments on the stack,
-   no stack frame requirement and no live registers execpt for `lr'.  If we
-   can guarantee that by making all function calls into tail calls and that
-   lr is not clobbered in any other way, then there is no need to push lr
-   onto the stack.  */
+/* Place some comments into the assembler stream
+   describing the current function.  */
+
 void
 output_arm_prologue (f, frame_size)
      FILE * f;
      int frame_size;
 {
-  int reg, live_regs_mask = 0;
-  int volatile_func = arm_volatile_func ();
-
-  /* Nonzero if we must stuff some register arguments onto the stack as if
-     they were passed there.  */
-  int store_arg_regs = 0;
-
+  unsigned long func_type;
+  
+  /* Sanity check.  */
   if (arm_ccfsm_state || arm_target_insn)
-    abort ();                                  /* Sanity check.  */
-
-  if (arm_naked_function_p (current_function_decl))
-    return;
+    abort ();
 
-  return_used_this_function = 0;
+  func_type = arm_current_func_type ();
+  
+  switch ((int) ARM_FUNC_TYPE (func_type))
+    {
+    default:
+    case ARM_FT_NORMAL:
+      break;
+    case ARM_FT_INTERWORKED:
+      asm_fprintf (f, "\t%@ Function supports interworking.\n");
+      break;
+    case ARM_FT_EXCEPTION_HANDLER:
+      asm_fprintf (f, "\t%@ C++ Exception Handler.\n");
+      break;
+    case ARM_FT_ISR:
+      asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
+      break;
+    case ARM_FT_FIQ:
+      asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
+      break;
+    case ARM_FT_EXCEPTION:
+      asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
+      break;
+    }
   
+  if (IS_NAKED (func_type))
+    asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
+
+  if (IS_VOLATILE (func_type))
+    asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
+
+  if (IS_NESTED (func_type))
+    asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
+    
   asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %d\n",
               current_function_args_size,
               current_function_pretend_args_size, frame_size);
+
   asm_fprintf (f, "\t%@ frame_needed = %d, current_function_anonymous_args = %d\n",
               frame_pointer_needed,
               current_function_anonymous_args);
 
-  if (volatile_func)
-    asm_fprintf (f, "\t%@ Volatile function.\n");
-
-  if (current_function_anonymous_args && current_function_pretend_args_size)
-    store_arg_regs = 1;
-
-  for (reg = 0; reg <= 10; reg++)
-    if (regs_ever_live[reg] && ! call_used_regs[reg])
-      live_regs_mask |= (1 << reg);
-
-  if (! TARGET_APCS_FRAME
-      && ! frame_pointer_needed
-      && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-      && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-    live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM);
-
-  if (flag_pic && ! TARGET_SINGLE_PIC_BASE
-      && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
-
-  if (frame_pointer_needed)
-    live_regs_mask |= 0xD800;
-  else if (regs_ever_live[LR_REGNUM])
-    {
-      live_regs_mask |= 1 << LR_REGNUM;
-    }
-
-  if (live_regs_mask)
-    /* If a di mode load/store multiple is used, and the base register
-       is r3, then r4 can become an ever live register without lr
-       doing so,  in this case we need to push lr as well, or we
-       will fail to get a proper return.  */
-    live_regs_mask |= 1 << LR_REGNUM;
+  if (cfun->machine->lr_save_eliminated)
+    asm_fprintf (f, "\t%@ link register save eliminated.\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;  
 }
 
 const char *
@@ -6739,74 +7381,57 @@ arm_output_epilogue (really_return)
      int really_return;
 {
   int reg;
-  int live_regs_mask = 0;
+  unsigned long saved_regs_mask;
+  unsigned long func_type;
   /* If we need this, then it will always be at least this much.  */
   int floats_offset = 12;
   rtx operands[3];
   int frame_size = get_frame_size ();
-  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
   FILE * f = asm_out_file;
-  int volatile_func = arm_volatile_func ();
-  int return_regnum;
+  rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
 
+  /* If we have already generated the return instruction
+     then it is futile to generate anything else.  */
   if (use_return_insn (FALSE) && return_used_this_function)
     return "";
 
-  /* Naked functions don't have epilogues.  */
-  if (arm_naked_function_p (current_function_decl))
-    return "";
-
-  /* If we are throwing an exception, the address we want to jump to is in
-     R1; otherwise, it's in LR.  */
-  return_regnum = eh_ofs ? 2 : LR_REGNUM;
+  func_type = arm_current_func_type ();
 
-  /* If we are throwing an exception, then we really must be doing a return,
-     so we can't tail-call.  */
-  if (eh_ofs && ! really_return)
-    abort();
+  if (IS_NAKED (func_type))
+    /* Naked functions don't have epilogues.  */
+    return "";
 
-  /* A volatile function should never return.  Call abort.  */
-  if (TARGET_ABORT_NORETURN && volatile_func)
+  if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
     {
       rtx op;
+         
+      /* A volatile function should never return.  Call abort.  */
       op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
       assemble_external_libcall (op);
       output_asm_insn ("bl\t%a0", &op);
+      
       return "";
     }
 
-  for (reg = 0; reg <= 10; reg++)
-    if (regs_ever_live[reg] && ! call_used_regs[reg])
-      {
-        live_regs_mask |= (1 << reg);
-       floats_offset += 4;
-      }
-
-  /* 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])
-    {
-      live_regs_mask |= (1 << HARD_FRAME_POINTER_REGNUM);
-      floats_offset += 4;
-    }
-
-  /* If we aren't loading the PIC register, don't stack it even though it may
-     be live.  */
-  if (flag_pic && ! TARGET_SINGLE_PIC_BASE 
-      && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-    {
-      live_regs_mask |= (1 << PIC_OFFSET_TABLE_REGNUM);
+  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
+      && ! really_return)
+    /* If we are throwing an exception, then we really must
+       be doing a return,  so we can't tail-call.  */
+    abort ();
+  
+  saved_regs_mask = arm_compute_save_reg_mask ();
+  
+  /* Compute how far away the floats will be.  */
+  for (reg = 0; reg <= LAST_ARM_REGNUM; reg ++)
+    if (saved_regs_mask & (1 << reg))
       floats_offset += 4;
-    }
-
+  
   if (frame_pointer_needed)
     {
       if (arm_fpu_arch == FP_SOFT2)
        {
          for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
-           if (regs_ever_live[reg] && ! call_used_regs[reg])
+           if (regs_ever_live[reg] && !call_used_regs[reg])
              {
                floats_offset += 12;
                asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n", 
@@ -6819,7 +7444,7 @@ arm_output_epilogue (really_return)
 
          for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg--)
            {
-             if (regs_ever_live[reg] && ! call_used_regs[reg])
+             if (regs_ever_live[reg] && !call_used_regs[reg])
                {
                  floats_offset += 12;
                  
@@ -6847,37 +7472,33 @@ arm_output_epilogue (really_return)
                         reg + 1, start_reg - reg,
                         FP_REGNUM, floats_offset);
        }
-      
-      if (TARGET_INTERWORK)
-       {
-         live_regs_mask |= 0x6800;
-         print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE);
-         if (eh_ofs)
-           asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                        REGNO (eh_ofs));
-         if (really_return)
-           asm_fprintf (f, "\tbx\t%r\n", return_regnum);
-       }
-      else if (eh_ofs || ! really_return)
-       {
-         live_regs_mask |= 0x6800;
-         print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask, FALSE);
-         if (eh_ofs)
-           {
-             asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                          REGNO (eh_ofs));
-             /* Even in 26-bit mode we do a mov (rather than a movs)
-                because we don't have the PSR bits set in the
-                address.  */
-             asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
-           }
-       }
+
+      /* saved_regs_mask should contain the IP, which at the time of stack
+        frame generation actually contains the old stack pointer.  So a
+        quick way to unwind the stack is just pop the IP register directly
+        into the stack pointer.  */
+      if ((saved_regs_mask & (1 << IP_REGNUM)) == 0)
+       abort ();
+      saved_regs_mask &= ~ (1 << IP_REGNUM);
+      saved_regs_mask |=   (1 << SP_REGNUM);
+
+      /* There are two registers left in saved_regs_mask - LR and PC.  We
+        only need to restore the LR register (the return address), but to
+        save time we can load it directly into the PC, unless we need a
+        special function exit sequence, or we are not really returning.  */
+      if (really_return && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
+       /* 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);
       else
-       {
-         live_regs_mask |= 0xA800;
-         print_multi_reg (f, "ldmea\t%r", FP_REGNUM, live_regs_mask,
-                          TARGET_APCS_32 ? FALSE : TRUE);
-       }
+       saved_regs_mask &= ~ (1 << PC_REGNUM);
+      
+      print_multi_reg (f, "ldmea\t%r", FP_REGNUM, saved_regs_mask);
+
+      if (IS_INTERRUPT (func_type))
+       /* Interrupt handlers will have pushed the
+          IP onto the stack, so restore it now.  */
+       print_multi_reg (f, "ldmea\t%r", SP_REGNUM, 1 << IP_REGNUM);
     }
   else
     {
@@ -6893,7 +7514,7 @@ arm_output_epilogue (really_return)
       if (arm_fpu_arch == FP_SOFT2)
        {
          for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
-           if (regs_ever_live[reg] && ! call_used_regs[reg])
+           if (regs_ever_live[reg] && !call_used_regs[reg])
              asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
                           reg, SP_REGNUM);
        }
@@ -6903,7 +7524,7 @@ arm_output_epilogue (really_return)
 
          for (reg = FIRST_ARM_FP_REGNUM; reg <= LAST_ARM_FP_REGNUM; reg++)
            {
-             if (regs_ever_live[reg] && ! call_used_regs[reg])
+             if (regs_ever_live[reg] && !call_used_regs[reg])
                {
                  if (reg - start_reg == 3)
                    {
@@ -6929,102 +7550,88 @@ arm_output_epilogue (really_return)
                         start_reg, reg - start_reg, SP_REGNUM);
        }
 
-      if (current_function_pretend_args_size == 0 && regs_ever_live[LR_REGNUM])
+      /* If we can, restore the LR into the PC.  */
+      if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
+         && really_return
+         && current_function_pretend_args_size == 0
+         && saved_regs_mask & (1 << LR_REGNUM))
        {
-         if (TARGET_INTERWORK)
-           {
-             live_regs_mask |= 1 << LR_REGNUM;
-
-             /* Handle LR on its own.  */
-             if (live_regs_mask == (1 << LR_REGNUM))
-               {
-                 if (eh_ofs)
-                   asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM,
-                                SP_REGNUM);
-                 else
-                   asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM,
-                                SP_REGNUM);
-               }
-             else if (live_regs_mask != 0)
-               print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask,
-                                FALSE);
-
-             if (eh_ofs)
-               asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                            REGNO (eh_ofs));
+         saved_regs_mask &= ~ (1 << LR_REGNUM);
+         saved_regs_mask |=   (1 << PC_REGNUM);
+       }
 
-             if (really_return)
-               asm_fprintf (f, "\tbx\t%r\n", return_regnum);
-           }
-         else if (eh_ofs)
-           {
-             if (live_regs_mask == 0)
-               asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
-             else
-               print_multi_reg (f, "\tldmfd\t%r!", SP_REGNUM,
-                                live_regs_mask | (1 << LR_REGNUM), FALSE);
-               
-             asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                          REGNO (eh_ofs));
-             /* Jump to the target; even in 26-bit mode.  */
-             asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
-           }
-         else if (TARGET_APCS_32 && live_regs_mask == 0 && ! really_return)
-           asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
-         else if (TARGET_APCS_32 && live_regs_mask == 0 && really_return)
-           asm_fprintf (f, "\tldr\t%r, [%r], #4\n", PC_REGNUM, SP_REGNUM);
-         else if (! really_return)
-           print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM,
-                            live_regs_mask | (1 << LR_REGNUM), FALSE);
+      /* 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))
+       {
+         /* The excpetion handler ignores the LR, so we do
+            not really need to load it off the stack.  */
+         if (eh_ofs)
+           asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM, SP_REGNUM);
          else
-           print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM,
-                            live_regs_mask | (1 << PC_REGNUM),
-                            TARGET_APCS_32 ? FALSE : TRUE);
+           asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
        }
-      else
+      else if (saved_regs_mask)
+       print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
+
+      if (current_function_pretend_args_size)
        {
-         if (live_regs_mask || regs_ever_live[LR_REGNUM])
-           {
-             /* Restore the integer regs, and the return address into lr.  */
-             live_regs_mask |= 1 << LR_REGNUM;
+         /* Unwind the pre-pushed regs.  */
+         operands[0] = operands[1] = stack_pointer_rtx;
+         operands[2] = GEN_INT (current_function_pretend_args_size);
+         output_add_immediate (operands);
+       }
+    }
 
-             if (live_regs_mask == (1 << LR_REGNUM))
-               {
-                 if (eh_ofs)
-                   asm_fprintf (f, "\tadd\t%r, %r, #4\n", SP_REGNUM,
-                                SP_REGNUM);
-                 else
-                   asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM,
-                                SP_REGNUM);
-               }
-             else if (live_regs_mask != 0)
-               print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, live_regs_mask,
-                                FALSE);
-           }
+#if 0
+  if (ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER)
+    /* Adjust the stack to remove the exception handler stuff.  */
+    asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
+                REGNO (eh_ofs));
+#endif
 
-         if (current_function_pretend_args_size)
-           {
-             /* Unwind the pre-pushed regs.  */
-             operands[0] = operands[1] = stack_pointer_rtx;
-             operands[2] = GEN_INT (current_function_pretend_args_size);
-             output_add_immediate (operands);
-           }
+  if (! really_return)
+    return "";
 
-         if (eh_ofs)
-           asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
-                        REGNO (eh_ofs));
+  /* Generate the return instruction.  */
+  switch ((int) ARM_FUNC_TYPE (func_type))
+    {
+    case ARM_FT_EXCEPTION_HANDLER:
+      /* Even in 26-bit mode we do a mov (rather than a movs)
+        because we don't have the PSR bits set in the address.  */
+      asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, EXCEPTION_LR_REGNUM);
+      break;
 
-         if (really_return)
-           {
-             /* And finally, go home.  */
-             if (TARGET_INTERWORK)
-               asm_fprintf (f, "\tbx\t%r\n", return_regnum);
-             else if (TARGET_APCS_32 || eh_ofs)
-               asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, return_regnum);
-             else
-               asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, return_regnum);
-           }
-       }
+    case ARM_FT_ISR:
+    case ARM_FT_FIQ:
+      asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
+      break;
+
+    case ARM_FT_EXCEPTION:
+      asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+      break;
+
+    case ARM_FT_INTERWORKED:
+      asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
+      break;
+
+    default:
+      if (frame_pointer_needed)
+       /* If we used the frame pointer then the return adddress
+          will have been loaded off the stack directly into the
+          PC, so there is no need to issue a MOV instruction
+          here.  */
+       ;
+      else if (current_function_pretend_args_size == 0
+              && (saved_regs_mask & (1 << LR_REGNUM)))
+       /* Similarly we may have been able to load LR into the PC
+          even if we did not create a stack frame.  */
+       ;
+      else if (TARGET_APCS_32)
+       asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+      else
+       asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
+      break;
     }
 
   return "";
@@ -7046,7 +7653,7 @@ output_func_epilogue (frame_size)
       if (use_return_insn (FALSE)
          && return_used_this_function
          && (frame_size + current_function_outgoing_args_size) != 0
-         && ! frame_pointer_needed)
+         && !frame_pointer_needed)
        abort ();
 
       /* Reset the ARM-specific per-function variables.  */
@@ -7059,26 +7666,67 @@ output_func_epilogue (frame_size)
    Unfortunately, since this insn does not reflect very well the actual
    semantics of the operation, we need to annotate the insn for the benefit
    of DWARF2 frame unwind information.  */
+
 static rtx
 emit_multi_reg_push (mask)
      int mask;
 {
   int num_regs = 0;
+  int num_dwarf_regs;
   int i, j;
   rtx par;
   rtx dwarf;
+  int dwarf_par_index;
   rtx tmp, reg;
 
   for (i = 0; i <= LAST_ARM_REGNUM; i++)
     if (mask & (1 << i))
-      num_regs ++;
+      num_regs++;
 
   if (num_regs == 0 || num_regs > 16)
     abort ();
 
+  /* We don't record the PC in the dwarf frame information.  */
+  num_dwarf_regs = num_regs;
+  if (mask & (1 << PC_REGNUM))
+    num_dwarf_regs--;
+
+  /* For the body of the insn we are going to generate an UNSPEC in
+     parallel with several USEs.  This allows the insn to be recognised
+     by the push_multi pattern in the arm.md file.  The insn looks
+     something like this:
+
+       (parallel [ 
+           (set (mem:BLK (pre_dec:BLK (reg:SI sp)))
+               (unspec:BLK [(reg:SI r4)] UNSPEC_PUSH_MULT))
+           (use (reg:SI 11 fp))
+           (use (reg:SI 12 ip))
+           (use (reg:SI 14 lr))
+           (use (reg:SI 15 pc))
+        ])
+
+     For the frame note however, we try to be more explicit and actually
+     show each register being stored into the stack frame, plus a (single)
+     decrement of the stack pointer.  We do it this way in order to be
+     friendly to the stack unwinding code, which only wants to see a single
+     stack decrement per instruction.  The RTL we generate for the note looks
+     something like this:
+
+      (sequence [ 
+           (set (reg:SI sp) (plus:SI (reg:SI sp) (const_int -20)))
+           (set (mem:SI (reg:SI sp)) (reg:SI r4))
+           (set (mem:SI (plus:SI (reg:SI sp) (const_int 4))) (reg:SI fp))
+           (set (mem:SI (plus:SI (reg:SI sp) (const_int 8))) (reg:SI ip))
+           (set (mem:SI (plus:SI (reg:SI sp) (const_int 12))) (reg:SI lr))
+        ])
+
+      This sequence is used both by the code to support stack unwinding for
+      exceptions handlers and the code to generate dwarf2 frame debugging.  */
+  
   par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
-  dwarf = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
+  dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
   RTX_FRAME_RELATED_P (dwarf) = 1;
+  dwarf_par_index = 1;
 
   for (i = 0; i <= LAST_ARM_REGNUM; i++)
     {
@@ -7093,15 +7741,17 @@ emit_multi_reg_push (mask)
                                                         stack_pointer_rtx)),
                           gen_rtx_UNSPEC (BLKmode,
                                           gen_rtvec (1, reg),
-                                          2));
+                                          UNSPEC_PUSH_MULT));
 
-         tmp = gen_rtx_SET (VOIDmode,
-                            gen_rtx_MEM (SImode,
-                                         gen_rtx_PRE_DEC (BLKmode,
-                                                          stack_pointer_rtx)),
-                            reg);
-         RTX_FRAME_RELATED_P (tmp) = 1;
-         XVECEXP (dwarf, 0, num_regs - 1) = tmp;         
+         if (i != PC_REGNUM)
+           {
+             tmp = gen_rtx_SET (VOIDmode,
+                                gen_rtx_MEM (SImode, stack_pointer_rtx),
+                                reg);
+             RTX_FRAME_RELATED_P (tmp) = 1;
+             XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
+             dwarf_par_index++;
+           }
 
          break;
        }
@@ -7115,19 +7765,31 @@ emit_multi_reg_push (mask)
 
          XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
 
-         tmp = gen_rtx_SET (VOIDmode,
-                            gen_rtx_MEM (SImode,
-                                         gen_rtx_PRE_DEC (BLKmode,
-                                                          stack_pointer_rtx)),
-                            reg);
-         RTX_FRAME_RELATED_P (tmp) = 1;
-         XVECEXP (dwarf, 0, num_regs - j - 1) = tmp;
-                          
+         if (i != PC_REGNUM)
+           {
+             tmp = gen_rtx_SET (VOIDmode,
+                                gen_rtx_MEM (SImode,
+                                             plus_constant (stack_pointer_rtx,
+                                                            4 * j)),
+                                reg);
+             RTX_FRAME_RELATED_P (tmp) = 1;
+             XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
+           }
+
          j++;
        }
     }
 
   par = emit_insn (par);
+  
+  tmp = gen_rtx_SET (SImode,
+                    stack_pointer_rtx,
+                    gen_rtx_PLUS (SImode,
+                                  stack_pointer_rtx,
+                                  GEN_INT (-4 * num_regs)));
+  RTX_FRAME_RELATED_P (tmp) = 1;
+  XVECEXP (dwarf, 0, 0) = tmp;
+  
   REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
                                       REG_NOTES (par));
   return par;
@@ -7155,7 +7817,7 @@ emit_sfm (base_reg, count)
                                gen_rtx_PRE_DEC (BLKmode, stack_pointer_rtx)),
                   gen_rtx_UNSPEC (BLKmode,
                                   gen_rtvec (1, reg),
-                                  2));
+                                  UNSPEC_PUSH_MULT));
   tmp
     = gen_rtx_SET (VOIDmode, 
                   gen_rtx_MEM (XFmode,
@@ -7184,56 +7846,109 @@ emit_sfm (base_reg, count)
   return par;
 }
 
+/* Generate the prologue instructions for entry into an ARM function.  */
+
 void
 arm_expand_prologue ()
 {
   int reg;
-  rtx amount = GEN_INT (-(get_frame_size ()
-                         + current_function_outgoing_args_size));
-  int live_regs_mask = 0;
-  int store_arg_regs = 0;
-  /* If this function doesn't return, then there is no need to push
-     the call-saved regs.  */
-  int volatile_func = arm_volatile_func ();
+  rtx amount;
   rtx insn;
+  rtx ip_rtx;
+  unsigned long live_regs_mask;
+  unsigned long func_type;
+  int fp_offset = 0;
+
+  func_type = arm_current_func_type ();
 
   /* Naked functions don't have prologues.  */
-  if (arm_naked_function_p (current_function_decl))
+  if (IS_NAKED (func_type))
     return;
 
-  if (current_function_anonymous_args && current_function_pretend_args_size)
-    store_arg_regs = 1;
+  /* Compute which register we will have to save onto the stack.  */
+  live_regs_mask = arm_compute_save_reg_mask ();
 
-  if (! volatile_func)
+  ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
+
+  if (frame_pointer_needed)
     {
-      for (reg = 0; reg <= 10; reg++)
-       if (regs_ever_live[reg] && ! call_used_regs[reg])
-         live_regs_mask |= 1 << reg;
+      if (IS_INTERRUPT (func_type))
+       {
+         /* Interrupt functions must not corrupt any registers.
+            Creating a frame pointer however, corrupts the IP
+            register, so we must push it first.  */
+         insn = emit_multi_reg_push (1 << IP_REGNUM);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+      else if (IS_NESTED (func_type))
+       {
+         /* The Static chain register is the same as the IP register
+            used as a scratch register during stack frame creation.
+            To get around this need to find somewhere to store IP
+            whilst the frame is being created.  We try the following
+            places in order:
+            
+              1. The last argument register.
+              2. A slot on the stack above the frame.  (This only
+                 works if the function is not a varargs function).
+                 
+            If neither of these places is available, we abort (for now).
 
-      if (! TARGET_APCS_FRAME
-         && ! frame_pointer_needed
-         && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
-         && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
-       live_regs_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
-      
-      if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
-       live_regs_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
+            Note - we only need to tell the dwarf2 backend about the SP
+            adjustment in the second variant; the static chain register
+            doesn't need to be unwound, as it doesn't contain a value
+            inherited from the caller.  */
 
-      if (regs_ever_live[LR_REGNUM])
-       live_regs_mask |= 1 << LR_REGNUM;
-    }
+         if (regs_ever_live[3] == 0)
+           {
+             insn = gen_rtx_REG (SImode, 3);
+             insn = gen_rtx_SET (SImode, insn, ip_rtx);
+             insn = emit_insn (insn);
+           }
+         else if (current_function_pretend_args_size == 0)
+           {
+             rtx dwarf;
+             insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
+             insn = gen_rtx_MEM (SImode, insn);
+             insn = gen_rtx_SET (VOIDmode, insn, ip_rtx);
+             insn = emit_insn (insn);
+
+             fp_offset = 4;
+
+             /* Just tell the dwarf backend that we adjusted SP.  */
+             dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
+                                  gen_rtx_PLUS (SImode, stack_pointer_rtx,
+                                                GEN_INT (-fp_offset)));
+             RTX_FRAME_RELATED_P (insn) = 1;
+             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                                   dwarf, REG_NOTES (insn));
+           }
+         else
+           /* FIXME - the way to handle this situation is to allow
+              the pretend args to be dumped onto the stack, then
+              reuse r3 to save IP.  This would involve moving the
+              copying of SP into IP until after the pretend args
+              have been dumped, but this is not too hard.  */
+           /* [See e.g. gcc.c-torture/execute/nest-stdar-1.c.]  */
+           error ("Unable to find a temporary location for static chain register");
+       }
 
-  if (frame_pointer_needed)
-    {
-      live_regs_mask |= 0xD800;
-      insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM),
-                                  stack_pointer_rtx));
+      if (fp_offset)
+       {
+         insn = gen_rtx_PLUS (SImode, stack_pointer_rtx, GEN_INT (fp_offset));
+         insn = gen_rtx_SET  (SImode, ip_rtx, insn);
+       }
+      else
+       insn = gen_movsi (ip_rtx, stack_pointer_rtx);
+      
+      insn = emit_insn (insn);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
 
   if (current_function_pretend_args_size)
     {
-      if (store_arg_regs)
+      /* Push the argument registers, or reserve space for them.  */
+      if (current_function_anonymous_args)
        insn = emit_multi_reg_push
          ((0xf0 >> (current_function_pretend_args_size / 4)) & 0xf);
       else
@@ -7245,21 +7960,17 @@ arm_expand_prologue ()
 
   if (live_regs_mask)
     {
-      /* If we have to push any regs, then we must push lr as well, or
-        we won't get a proper return.  */
-      live_regs_mask |= 1 << LR_REGNUM;
       insn = emit_multi_reg_push (live_regs_mask);
       RTX_FRAME_RELATED_P (insn) = 1;
     }
-      
-  /* For now the integer regs are still pushed in output_arm_epilogue ().  */
 
-  if (! volatile_func)
+  if (! IS_VOLATILE (func_type))
     {
+      /* Save any floating point call-saved registers used by this function.  */
       if (arm_fpu_arch == FP_SOFT2)
        {
          for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
-           if (regs_ever_live[reg] && ! call_used_regs[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);
@@ -7274,7 +7985,7 @@ arm_expand_prologue ()
 
          for (reg = LAST_ARM_FP_REGNUM; reg >= FIRST_ARM_FP_REGNUM; reg --)
            {
-             if (regs_ever_live[reg] && ! call_used_regs[reg])
+             if (regs_ever_live[reg] && !call_used_regs[reg])
                {
                  if (start_reg - reg == 3)
                    {
@@ -7304,20 +8015,60 @@ arm_expand_prologue ()
 
   if (frame_pointer_needed)
     {
-      insn = GEN_INT (-(4 + current_function_pretend_args_size));
-      insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
-                                   gen_rtx_REG (SImode, IP_REGNUM),
-                                   insn));
+      /* Create the new frame pointer.  */
+      insn = GEN_INT (-(4 + current_function_pretend_args_size + 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)
+           {
+             insn = gen_rtx_REG (SImode, 3);
+             insn = gen_rtx_SET (SImode, ip_rtx, insn);
+             insn = emit_insn (insn);
+           }
+         else /* if (current_function_pretend_args_size == 0) */
+           {
+             insn = gen_rtx_PLUS (SImode, hard_frame_pointer_rtx, GEN_INT (4));
+             insn = gen_rtx_MEM (SImode, insn);
+             insn = gen_rtx_SET (SImode, ip_rtx, insn);
+             insn = emit_insn (insn);
+           }
+       }
     }
 
+  amount = GEN_INT (-(get_frame_size ()
+                     + current_function_outgoing_args_size));
+
   if (amount != const0_rtx)
     {
+      /* This add can produce multiple insns for a large constant, so we
+        need to get tricky.  */
+      rtx last = get_last_insn ();
       insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
                                    amount));
-      RTX_FRAME_RELATED_P (insn) = 1;
-      emit_insn (gen_rtx_CLOBBER (VOIDmode, 
-                                 gen_rtx_MEM (BLKmode, stack_pointer_rtx)));
+      do
+       {
+         last = last ? NEXT_INSN (last) : get_insns ();
+         RTX_FRAME_RELATED_P (last) = 1;
+       }
+      while (last != insn);
+
+      /* If the frame pointer is needed, emit a special barrier that
+        will prevent the scheduler from moving stores to the frame
+        before the stack adjustment.  */
+      if (frame_pointer_needed)
+       {
+         rtx unspec = gen_rtx_UNSPEC (SImode,
+                                      gen_rtvec (2, stack_pointer_rtx,
+                                                 hard_frame_pointer_rtx),
+                                      UNSPEC_PRLG_STK);
+
+         insn = emit_insn (gen_rtx_CLOBBER (VOIDmode,
+                                     gen_rtx_MEM (BLKmode, unspec)));
+       }
     }
 
   /* If we are profiling, make sure no instructions are scheduled before
@@ -7325,6 +8076,14 @@ arm_expand_prologue ()
      scheduling in the prolog.  */
   if (profile_flag || profile_block_flag || TARGET_NO_SCHED_PRO)
     emit_insn (gen_blockage ());
+
+  /* If the link register is being kept alive, with the return address in it,
+     then make sure that it does not get reused by the ce2 pass.  */
+  if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
+    {
+      emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
+      cfun->machine->lr_save_eliminated = 1;
+    }
 }
 \f
 /* If CODE is 'd', then the X is a condition operand and the instruction
@@ -7363,7 +8122,22 @@ arm_print_operand (stream, x, code)
 
     case '?':
       if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
-       fputs (arm_condition_codes[arm_current_cc], stream);
+       {
+         if (TARGET_THUMB || current_insn_predicate != NULL)
+           abort ();
+
+         fputs (arm_condition_codes[arm_current_cc], stream);
+       }
+      else if (current_insn_predicate)
+       {
+         enum arm_cond_code code;
+
+         if (TARGET_THUMB)
+           abort ();
+
+         code = get_arm_condition_code (current_insn_predicate);
+         fputs (arm_condition_codes[code], stream);
+       }
       return;
 
     case 'N':
@@ -7379,7 +8153,7 @@ arm_print_operand (stream, x, code)
       if (GET_CODE (x) == CONST_INT)
        {
          HOST_WIDE_INT val;
-         val = ARM_SIGN_EXTEND (~ INTVAL (x));
+         val = ARM_SIGN_EXTEND (~INTVAL (x));
          fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
        }
       else
@@ -7400,11 +8174,11 @@ arm_print_operand (stream, x, code)
     case 'S':
       {
        HOST_WIDE_INT val;
-       const char * shift = shift_op (x, & val);
+       const char * shift = shift_op (x, &val);
 
        if (shift)
          {
-           fprintf (stream, ", %s ", shift_op (x, & val));
+           fprintf (stream, ", %s ", shift_op (x, &val));
            if (val == -1)
              arm_print_operand (stream, XEXP (x, 1), 0);
            else
@@ -7474,7 +8248,7 @@ arm_print_operand (stream, x, code)
       return;
 
     case 'd':
-      if (! x)
+      if (!x)
        return;
       
       if (TARGET_ARM)
@@ -7485,7 +8259,7 @@ arm_print_operand (stream, x, code)
       return;
 
     case 'D':
-      if (! x)
+      if (!x)
        return;
 
       if (TARGET_ARM)
@@ -7598,7 +8372,6 @@ get_arm_condition_code (comparison)
        }
 
     case CC_Zmode:
-    case CCFPmode:
       switch (comp_code)
        {
        case NE: return ARM_NE;
@@ -7607,12 +8380,27 @@ get_arm_condition_code (comparison)
        }
 
     case CCFPEmode:
+    case CCFPmode:
+      /* These encodings assume that AC=1 in the FPA system control
+        byte.  This allows us to handle all cases except UNEQ and
+        LTGT.  */
       switch (comp_code)
        {
        case GE: return ARM_GE;
        case GT: return ARM_GT;
        case LE: return ARM_LS;
        case LT: return ARM_MI;
+       case NE: return ARM_NE;
+       case EQ: return ARM_EQ;
+       case ORDERED: return ARM_VC;
+       case UNORDERED: return ARM_VS;
+       case UNLT: return ARM_LT;
+       case UNLE: return ARM_LE;
+       case UNGT: return ARM_HI;
+       case UNGE: return ARM_PL;
+         /* UNEQ and LTGT do not have a representation.  */
+       case UNEQ: /* Fall through.  */
+       case LTGT: /* Fall through.  */
        default: abort ();
        }
 
@@ -7768,11 +8556,10 @@ arm_final_prescan_insn (insn)
       int then_not_else = TRUE;
       rtx this_insn = start_insn, label = 0;
 
+      /* If the jump cannot be done with one instruction, we cannot 
+        conditionally execute the instruction in the inverse case.  */
       if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
        {
-         /* The code below is wrong for these, and I haven't time to
-            fix it now.  So we just do the safe thing and return.  This
-            whole function needs re-writing anyway.  */
          jump_clobbers = 1;
          return;
        }
@@ -7904,8 +8691,8 @@ arm_final_prescan_insn (insn)
              /* Fail if a conditional return is undesirable (eg on a
                 StrongARM), but still allow this if optimizing for size.  */
              else if (GET_CODE (scanbody) == RETURN
-                      && ! use_return_insn (TRUE)
-                      && ! optimize_size)
+                      && !use_return_insn (TRUE)
+                      && !optimize_size)
                fail = TRUE;
              else if (GET_CODE (scanbody) == RETURN
                       && seeking_return)
@@ -7924,14 +8711,17 @@ arm_final_prescan_insn (insn)
                      break;
                    }
                }
+             else
+               fail = TRUE;    /* Unrecognized jump (eg epilogue).  */
+
              break;
 
            case INSN:
              /* Instructions using or affecting the condition codes make it
                 fail.  */
              scanbody = PATTERN (this_insn);
-             if (! (GET_CODE (scanbody) == SET
-                    || GET_CODE (scanbody) == PARALLEL)
+             if (!(GET_CODE (scanbody) == SET
+                   || GET_CODE (scanbody) == PARALLEL)
                  || get_attr_conds (this_insn) != CONDS_NOCOND)
                fail = TRUE;
              break;
@@ -7956,7 +8746,7 @@ arm_final_prescan_insn (insn)
              if (!this_insn)
                {
                  /* Oh, dear! we ran off the end.. give up */
-                 recog (PATTERN (insn), insn, NULL_PTR);
+                 recog (PATTERN (insn), insn, NULL);
                  arm_ccfsm_state = 0;
                  arm_target_insn = NULL;
                  return;
@@ -7994,7 +8784,7 @@ arm_final_prescan_insn (insn)
         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_PTR);
+      recog (PATTERN (insn), insn, NULL);
     }
 }
 
@@ -8048,7 +8838,7 @@ arm_debugger_arg_offset (value, addr)
   
   /* If we are using the stack pointer to point at the
      argument, then an offset of 0 is correct.  */
-  if ((TARGET_THUMB || ! frame_pointer_needed)
+  if ((TARGET_THUMB || !frame_pointer_needed)
       && REGNO (addr) == SP_REGNUM)
     return 0;
   
@@ -8109,6 +8899,100 @@ arm_debugger_arg_offset (value, addr)
   return value;
 }
 
+#define def_builtin(NAME, TYPE, CODE) \
+  builtin_function ((NAME), (TYPE), (CODE), BUILT_IN_MD, NULL)
+
+void
+arm_init_builtins ()
+{
+  tree endlink = void_list_node;
+  tree int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
+  tree pchar_type_node = build_pointer_type (char_type_node);
+
+  tree int_ftype_int, void_ftype_pchar;
+
+  /* void func (void *) */
+  void_ftype_pchar
+    = build_function_type (void_type_node,
+                          tree_cons (NULL_TREE, pchar_type_node, endlink));
+
+  /* int func (int) */
+  int_ftype_int
+    = build_function_type (integer_type_node, int_endlink);
+
+  /* Initialize arm V5 builtins.  */
+  if (arm_arch5)
+    def_builtin ("__builtin_clz", int_ftype_int, ARM_BUILTIN_CLZ);
+
+  /* Initialize arm V5E builtins.  */
+  if (arm_arch5e)
+    def_builtin ("__builtin_prefetch", void_ftype_pchar,
+                ARM_BUILTIN_PREFETCH);
+}
+
+/* Expand an expression EXP that calls a built-in function,
+   with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
+
+rtx
+arm_expand_builtin (exp, target, subtarget, mode, ignore)
+     tree exp;
+     rtx target;
+     rtx subtarget ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int ignore ATTRIBUTE_UNUSED;
+{
+  enum insn_code icode;
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg0;
+  rtx op0, pat;
+  enum machine_mode tmode, mode0;
+  int fcode = DECL_FUNCTION_CODE (fndecl);
+
+  switch (fcode)
+    {
+    default:
+      break;
+      
+    case ARM_BUILTIN_CLZ:
+      icode = CODE_FOR_clz;
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+      tmode = insn_data[icode].operand[0].mode;
+      mode0 = insn_data[icode].operand[1].mode;
+
+      if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
+       op0 = copy_to_mode_reg (mode0, op0);
+      if (target == 0
+         || GET_MODE (target) != tmode
+         || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+      pat = GEN_FCN (icode) (target, op0);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+
+    case ARM_BUILTIN_PREFETCH:
+      icode = CODE_FOR_prefetch;
+      arg0 = TREE_VALUE (arglist);
+      op0 = expand_expr (arg0, NULL_RTX, VOIDmode, 0);
+
+      op0 = gen_rtx_MEM (SImode, copy_to_mode_reg (Pmode, op0));
+
+      pat = GEN_FCN (icode) (op0);
+      if (! pat)
+       return 0;
+      emit_insn (pat);
+      return target;
+    }
+  
+  /* @@@ Should really do something sensible here.  */
+  return NULL_RTX;
+}
 \f
 /* Recursively search through all of the blocks in a function
    checking to see if any of the variables created in that
@@ -8125,7 +9009,7 @@ replace_symbols_in_block (block, orig, new)
     {
       tree sym;
       
-      if (! TREE_USED (block))
+      if (!TREE_USED (block))
        continue;
 
       for (sym = BLOCK_VARS (block); sym; sym = TREE_CHAIN (sym))
@@ -8134,11 +9018,11 @@ replace_symbols_in_block (block, orig, new)
              || DECL_IGNORED_P (sym)
              || TREE_CODE (sym) != VAR_DECL
              || DECL_EXTERNAL (sym)
-             || ! rtx_equal_p (DECL_RTL (sym), orig)
+             || !rtx_equal_p (DECL_RTL (sym), orig)
              )
            continue;
 
-         DECL_RTL (sym) = new;
+         SET_DECL_RTL (sym, new);
        }
       
       replace_symbols_in_block (BLOCK_SUBBLOCKS (block), orig, new);
@@ -8158,7 +9042,7 @@ number_of_first_bit_set (mask)
 
   for (bit = 0;
        (mask & (1 << bit)) == 0;
-       ++ bit)
+       ++bit)
     continue;
 
   return bit;
@@ -8196,7 +9080,7 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
        abort ();
 
       regs_to_pop |= 1 << LR_REGNUM;
-      ++ pops_needed;
+      ++pops_needed;
     }
 
   if (TARGET_BACKTRACE)
@@ -8219,9 +9103,9 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
   /* Otherwise if we are not supporting interworking and we have not created
      a backtrace structure and the function was not entered in ARM mode then
      just pop the return address straight into the PC.  */
-  else if (   ! TARGET_INTERWORK
-          && ! TARGET_BACKTRACE
-          && ! is_called_in_ARM_mode (current_function_decl))
+  else if (!TARGET_INTERWORK
+          && !TARGET_BACKTRACE
+          && !is_called_in_ARM_mode (current_function_decl))
     {
       if (eh_ofs)
        {
@@ -8293,7 +9177,7 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
 
   /* If we have any popping registers left over, remove them.  */
   if (available > 0)
-    regs_available_for_popping &= ~ available;
+    regs_available_for_popping &= ~available;
   
   /* Otherwise if we need another popping register we can use
      the fourth argument register.  */
@@ -8321,7 +9205,7 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
          /* The fourth argument register is available.  */
          regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
          
-         -- pops_needed;
+         --pops_needed;
        }
     }
 
@@ -8332,14 +9216,14 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
   if (reg_containing_return_addr == -1)
     {
       /* The return address was popped into the lowest numbered register.  */
-      regs_to_pop &= ~ (1 << LR_REGNUM);
+      regs_to_pop &= ~(1 << LR_REGNUM);
       
       reg_containing_return_addr =
        number_of_first_bit_set (regs_available_for_popping);
 
       /* Remove this register for the mask of available registers, so that
          the return address will not be corrupted by futher pops.  */
-      regs_available_for_popping &= ~ (1 << reg_containing_return_addr);
+      regs_available_for_popping &= ~(1 << reg_containing_return_addr);
     }
 
   /* If we popped other registers then handle them here.  */
@@ -8355,8 +9239,8 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
                   ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
 
       /* (Temporarily) remove it from the mask of popped registers.  */
-      regs_available_for_popping &= ~ (1 << frame_pointer);
-      regs_to_pop &= ~ (1 << ARM_HARD_FRAME_POINTER_REGNUM);
+      regs_available_for_popping &= ~(1 << frame_pointer);
+      regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
       
       if (regs_available_for_popping)
        {
@@ -8416,9 +9300,9 @@ thumb_exit (f, reg_containing_return_addr, eh_ofs)
 
       asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
 
-      regs_to_pop &= ~ (1 << move_to);
+      regs_to_pop &= ~(1 << move_to);
 
-      -- pops_needed;
+      --pops_needed;
     }
   
   /* If we still have not popped everything then we must have only
@@ -8467,7 +9351,7 @@ thumb_pushpop (f, mask, push)
   int regno;
   int lo_mask = mask & 0xFF;
 
-  if (lo_mask == 0 && ! push && (mask & (1 << 15)))
+  if (lo_mask == 0 && !push && (mask & (1 << 15)))
     {
       /* Special case.  Do not generate a POP PC statement here, do it in
         thumb_exit() */
@@ -8478,7 +9362,7 @@ thumb_pushpop (f, mask, push)
   fprintf (f, "\t%s\t{", push ? "push" : "pop");
 
   /* Look at the low registers first.  */
-  for (regno = 0; regno <= LAST_LO_REGNUM; regno ++, lo_mask >>= 1)
+  for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
     {
       if (lo_mask & 1)
        {
@@ -8526,10 +9410,9 @@ void
 thumb_final_prescan_insn (insn)
      rtx insn;
 {
-  extern int * insn_addresses;
-
   if (flag_print_asm_name)
-    asm_fprintf (asm_out_file, "%@ 0x%04x\n", insn_addresses[INSN_UID (insn)]);
+    asm_fprintf (asm_out_file, "%@ 0x%04x\n",
+                INSN_ADDRESSES (INSN_UID (insn)));
 }
 
 int
@@ -8557,7 +9440,7 @@ thumb_far_jump_used_p (int in_prologue)
   rtx insn;
 
   /* This test is only important for leaf functions.  */
-  /* assert (! leaf_function_p ()); */
+  /* assert (!leaf_function_p ()); */
   
   /* If we have already decided that far jumps may be used,
      do not bother checking again, and always return true even if
@@ -8570,7 +9453,7 @@ thumb_far_jump_used_p (int in_prologue)
   /* If this function is not being called from the prologue/epilogue
      generation code then it must be being called from the
      INITIAL_ELIMINATION_OFFSET macro.  */
-  if (! in_prologue)
+  if (!in_prologue)
     {
       /* In this case we know that we are being asked about the elimination
         of the arg pointer register.  If that register is not being used,
@@ -8592,7 +9475,7 @@ thumb_far_jump_used_p (int in_prologue)
         hope that this does not occur too often.  */
       if (regs_ever_live [ARG_POINTER_REGNUM])
        cfun->machine->arg_pointer_live = 1;
-      else if (! cfun->machine->arg_pointer_live)
+      else if (!cfun->machine->arg_pointer_live)
        return 0;
     }
 
@@ -8637,6 +9520,7 @@ is_called_in_ARM_mode (func)
 }
 
 /* The bits which aren't usefully expanded as rtl. */
+
 const char *
 thumb_unexpanded_epilogue ()
 {
@@ -8651,15 +9535,15 @@ thumb_unexpanded_epilogue ()
     return "";
 
   for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno]
-       && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+    if (regs_ever_live[regno] && !call_used_regs[regno]
+       && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
       live_regs_mask |= 1 << regno;
 
   for (regno = 8; regno < 13; regno++)
     {
-      if (regs_ever_live[regno] && ! call_used_regs[regno]
-         && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
-       high_regs_pushed ++;
+      if (regs_ever_live[regno] && !call_used_regs[regno]
+         && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+       high_regs_pushed++;
     }
 
   /* The prolog may have pushed some high registers to use as
@@ -8701,11 +9585,12 @@ thumb_unexpanded_epilogue ()
       if (mask == 0)
        /* Oh dear!  We have no low registers into which we can pop
            high registers!  */
-       fatal ("No low registers available for popping high registers");
+       internal_error
+         ("no low registers available for popping high registers");
       
       for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
-       if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]
-           && ! (TARGET_SINGLE_PIC_BASE && (next_hi_reg == arm_pic_register)))
+       if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
+           && !(TARGET_SINGLE_PIC_BASE && (next_hi_reg == arm_pic_register)))
          break;
 
       while (high_regs_pushed)
@@ -8734,17 +9619,17 @@ thumb_unexpanded_epilogue ()
                               regno);
                  
                  for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
-                   if (regs_ever_live[next_hi_reg] && 
-                       call_used_regs[next_hi_reg]
-                       && ! (TARGET_SINGLE_PIC_BASE 
-                             && (next_hi_reg == arm_pic_register)))
+                   if (regs_ever_live[next_hi_reg]
+                       && !call_used_regs[next_hi_reg]
+                       && !(TARGET_SINGLE_PIC_BASE 
+                            && (next_hi_reg == arm_pic_register)))
                      break;
                }
            }
        }
     }
 
-  had_to_push_lr = (live_regs_mask || ! leaf_function
+  had_to_push_lr = (live_regs_mask || !leaf_function
                    || thumb_far_jump_used_p (1));
   
   if (TARGET_BACKTRACE
@@ -8760,8 +9645,8 @@ thumb_unexpanded_epilogue ()
   if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
     {
       if (had_to_push_lr
-         && ! is_called_in_ARM_mode (current_function_decl)
-         && ! eh_ofs)
+         && !is_called_in_ARM_mode (current_function_decl)
+         && !eh_ofs)
        live_regs_mask |= 1 << PC_REGNUM;
 
       /* Either no argument registers were pushed or a backtrace
@@ -8785,7 +9670,7 @@ thumb_unexpanded_epilogue ()
   else
     {
       /* Pop everything but the return address.  */
-      live_regs_mask &= ~ (1 << PC_REGNUM);
+      live_regs_mask &= ~(1 << PC_REGNUM);
       
       if (live_regs_mask)
        thumb_pushpop (asm_out_file, live_regs_mask, FALSE);
@@ -8815,10 +9700,10 @@ static void
 arm_mark_machine_status (p)
      struct function * p;
 {
-  struct machine_function *machine = p->machine;
+  machine_function *machine = p->machine;
 
-  ggc_mark_rtx (machine->ra_rtx);
-  ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
+  if (machine)
+    ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
 }
 
 static void
@@ -8826,7 +9711,22 @@ arm_init_machine_status (p)
      struct function * p;
 {
   p->machine =
-    (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
+    (machine_function *) xcalloc (1, sizeof (machine_function));
+
+#if ARM_FT_UNKNOWWN != 0  
+  ((machine_function *) p->machine)->func_type = ARM_FT_UNKNOWN;
+#endif
+}
+
+static void
+arm_free_machine_status (p)
+     struct function * p;
+{
+  if (p->machine)
+    {
+      free (p->machine);
+      p->machine = NULL;
+    }
 }
 
 /* Return an RTX indicating where the return address to the
@@ -8836,37 +9736,17 @@ arm_return_addr (count, frame)
      int count;
      rtx frame ATTRIBUTE_UNUSED;
 {
-  rtx reg;
-
   if (count != 0)
     return NULL_RTX;
 
-  reg = cfun->machine->ra_rtx;
-  
-  if (reg == NULL)
+  if (TARGET_APCS_32)
+    return get_hard_reg_initial_val (Pmode, LR_REGNUM);
+  else
     {
-      rtx init;
-      
-      /* No rtx yet.  Invent one, and initialize it for r14 (lr) in 
-        the prologue.  */
-      reg = gen_reg_rtx (Pmode);
-      cfun->machine->ra_rtx = reg;
-      
-      if (! TARGET_APCS_32)
-       init = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
+      rtx lr = gen_rtx_AND (Pmode, gen_rtx_REG (Pmode, LR_REGNUM),
                            GEN_INT (RETURN_ADDR_MASK26));
-      else
-       init = gen_rtx_REG (Pmode, LR_REGNUM);
-
-      init = gen_rtx_SET (VOIDmode, reg, init);
-
-      /* Emit the insn to the prologue with the other argument copies.  */
-      push_topmost_sequence ();
-      emit_insn_after (init, get_insns ());
-      pop_topmost_sequence ();
+      return get_func_hard_reg_initial_val (cfun, lr);
     }
-
-  return reg;
 }
 
 /* Do anything needed before RTL is emitted for each function.  */
@@ -8876,6 +9756,7 @@ arm_init_expanders ()
   /* Arrange to initialize and mark the machine per-function status.  */
   init_machine_status = arm_init_machine_status;
   mark_machine_status = arm_mark_machine_status;
+  free_machine_status = arm_free_machine_status;
 }
 
 /* Generate the rest of a function's prologue.  */
@@ -8884,11 +9765,20 @@ thumb_expand_prologue ()
 {
   HOST_WIDE_INT amount = (get_frame_size ()
                          + current_function_outgoing_args_size);
+  unsigned long func_type;
+
+  func_type = arm_current_func_type ();
   
   /* Naked functions don't have prologues.  */
-  if (arm_naked_function_p (current_function_decl))
+  if (IS_NAKED (func_type))
     return;
 
+  if (IS_INTERRUPT (func_type))
+    {
+      error ("Interrupt Service Routines cannot be coded in Thumb mode.");
+      return;
+    }
+
   if (frame_pointer_needed)
     emit_insn (gen_movsi (hard_frame_pointer_rtx, stack_pointer_rtx));
 
@@ -8898,7 +9788,7 @@ thumb_expand_prologue ()
       
       if (amount < 512)
        emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
-                              GEN_INT (- amount)));
+                              GEN_INT (-amount)));
       else
        {
          int regno;
@@ -8920,10 +9810,10 @@ thumb_expand_prologue ()
             it now.  */
          for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
            if (regs_ever_live[regno]
-               && ! call_used_regs[regno] /* Paranoia */
-               && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))
-               && ! (frame_pointer_needed
-                     && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
+               && !call_used_regs[regno] /* Paranoia */
+               && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register))
+               && !(frame_pointer_needed
+                    && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
              break;
 
          if (regno > LAST_LO_REGNUM) /* Very unlikely */
@@ -8937,7 +9827,7 @@ thumb_expand_prologue ()
              emit_insn (gen_movsi (spare, reg));
 
              /* Decrement the stack.  */
-             emit_insn (gen_movsi (reg, GEN_INT (- amount)));
+             emit_insn (gen_movsi (reg, GEN_INT (-amount)));
              emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
                                     reg));
 
@@ -8954,7 +9844,7 @@ thumb_expand_prologue ()
            {
              reg = gen_rtx (REG, SImode, regno);
 
-             emit_insn (gen_movsi (reg, GEN_INT (- amount)));
+             emit_insn (gen_movsi (reg, GEN_INT (-amount)));
              emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
                                     reg));
            }
@@ -8970,9 +9860,9 @@ thumb_expand_epilogue ()
 {
   HOST_WIDE_INT amount = (get_frame_size ()
                          + current_function_outgoing_args_size);
-
-  /* Naked functions don't have epilogues.  */
-  if (arm_naked_function_p (current_function_decl))
+  
+  /* Naked functions don't have prologues.  */
+  if (IS_NAKED (arm_current_func_type ()))
     return;
 
   if (frame_pointer_needed)
@@ -9008,10 +9898,9 @@ output_thumb_prologue (f)
 {
   int live_regs_mask = 0;
   int high_regs_pushed = 0;
-  int store_arg_regs = 0;
   int regno;
 
-  if (arm_naked_function_p (current_function_decl))
+  if (IS_NAKED (arm_current_func_type ()))
     return;
 
   if (is_called_in_ARM_mode (current_function_decl))
@@ -9026,7 +9915,7 @@ output_thumb_prologue (f)
       
       /* Generate code sequence to switch us into Thumb mode.  */
       /* The .code 32 directive has already been emitted by
-        ASM_DECLARE_FUNCITON_NAME */
+        ASM_DECLARE_FUNCTION_NAME.  */
       asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
       asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
 
@@ -9049,12 +9938,9 @@ output_thumb_prologue (f)
       asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
     }
     
-  if (current_function_anonymous_args && current_function_pretend_args_size)
-    store_arg_regs = 1;
-
   if (current_function_pretend_args_size)
     {
-      if (store_arg_regs)
+      if (current_function_anonymous_args)
        {
          int num_pushes;
          
@@ -9064,7 +9950,7 @@ output_thumb_prologue (f)
          
          for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
               regno <= LAST_ARG_REGNUM;
-              regno ++)
+              regno++)
            asm_fprintf (f, "%r%s", regno,
                         regno == LAST_ARG_REGNUM ? "" : ", ");
 
@@ -9076,12 +9962,12 @@ output_thumb_prologue (f)
                     current_function_pretend_args_size);
     }
 
-  for (regno = 0; regno <= LAST_LO_REGNUM; regno ++)
-    if (regs_ever_live[regno] && ! call_used_regs[regno]
-       && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+  for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
+    if (regs_ever_live[regno] && !call_used_regs[regno]
+       && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
       live_regs_mask |= 1 << regno;
 
-  if (live_regs_mask || ! leaf_function_p () || thumb_far_jump_used_p (1))
+  if (live_regs_mask || !leaf_function_p () || thumb_far_jump_used_p (1))
     live_regs_mask |= 1 << LR_REGNUM;
 
   if (TARGET_BACKTRACE)
@@ -9180,9 +10066,9 @@ output_thumb_prologue (f)
 
   for (regno = 8; regno < 13; regno++)
     {
-      if (regs_ever_live[regno] && ! call_used_regs[regno]
-         && ! (TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
-       high_regs_pushed ++;
+      if (regs_ever_live[regno] && !call_used_regs[regno]
+         && !(TARGET_SINGLE_PIC_BASE && (regno == arm_pic_register)))
+       high_regs_pushed++;
     }
 
   if (high_regs_pushed)
@@ -9193,9 +10079,9 @@ output_thumb_prologue (f)
 
       for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
        {
-         if (regs_ever_live[next_hi_reg] && ! call_used_regs[next_hi_reg]
-             && ! (TARGET_SINGLE_PIC_BASE
-                   && (next_hi_reg == arm_pic_register)))
+         if (regs_ever_live[next_hi_reg] && !call_used_regs[next_hi_reg]
+             && !(TARGET_SINGLE_PIC_BASE
+                  && (next_hi_reg == arm_pic_register)))
            break;
        }
 
@@ -9205,7 +10091,7 @@ output_thumb_prologue (f)
        {
          /* Desperation time -- this probably will never happen.  */
          if (regs_ever_live[LAST_ARG_REGNUM]
-             || ! call_used_regs[LAST_ARG_REGNUM])
+             || !call_used_regs[LAST_ARG_REGNUM])
            asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, LAST_ARG_REGNUM);
          mask = 1 << LAST_ARG_REGNUM;
        }
@@ -9218,21 +10104,21 @@ output_thumb_prologue (f)
                {
                  asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
                  
-                 high_regs_pushed --;
+                 high_regs_pushed--;
                  
                  if (high_regs_pushed)
                    for (next_hi_reg--; next_hi_reg > LAST_LO_REGNUM;
                         next_hi_reg--)
                      {
                        if (regs_ever_live[next_hi_reg]
-                           && ! call_used_regs[next_hi_reg]
-                           && ! (TARGET_SINGLE_PIC_BASE 
-                                 && (next_hi_reg == arm_pic_register)))
+                           && !call_used_regs[next_hi_reg]
+                           && !(TARGET_SINGLE_PIC_BASE 
+                                && (next_hi_reg == arm_pic_register)))
                          break;
                      }
                  else
                    {
-                     mask &= ~ ((1 << regno) - 1);
+                     mask &= ~((1 << regno) - 1);
                      break;
                    }
                }
@@ -9243,7 +10129,7 @@ output_thumb_prologue (f)
 
       if (pushable_regs == 0
          && (regs_ever_live[LAST_ARG_REGNUM]
-             || ! call_used_regs[LAST_ARG_REGNUM]))
+             || !call_used_regs[LAST_ARG_REGNUM]))
        asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
     }
 }
@@ -9254,7 +10140,7 @@ output_thumb_prologue (f)
 
 const char *
 thumb_load_double_from_address (operands)
-     rtx * operands;
+     rtx *operands;
 {
   rtx addr;
   rtx base;
@@ -9263,13 +10149,10 @@ thumb_load_double_from_address (operands)
   rtx arg2;
   
   if (GET_CODE (operands[0]) != REG)
-    fatal ("thumb_load_double_from_address: destination is not a register");
+    abort ();
   
   if (GET_CODE (operands[1]) != MEM)
-    {
-      debug_rtx (operands[1]);
-      fatal ("thumb_load_double_from_address: source is not a computed memory address");
-    }
+    abort ();
 
   /* Get the memory address.  */
   addr = XEXP (operands[1], 0);
@@ -9312,7 +10195,7 @@ thumb_load_double_from_address (operands)
        base = arg1, offset = arg2;
   
       if (GET_CODE (base) != REG)
-       fatal ("thumb_load_double_from_address: base is not a register");
+       abort ();
 
       /* Catch the case of <address> = <reg> + <reg> */
       if (GET_CODE (offset) == REG)
@@ -9369,8 +10252,7 @@ thumb_load_double_from_address (operands)
       break;
       
     default:
-      debug_rtx (operands[1]);
-      fatal ("thumb_load_double_from_address: Unhandled address calculation");
+      abort ();
       break;
     }
   
@@ -9388,38 +10270,38 @@ thumb_output_move_mem_multiple (n, operands)
   switch (n)
     {
     case 2:
-      if (REGNO (operands[2]) > REGNO (operands[3]))
+      if (REGNO (operands[4]) > REGNO (operands[5]))
        {
-         tmp = operands[2];
-         operands[2] = operands[3];
-         operands[3] = tmp;
+         tmp = operands[4];
+         operands[4] = operands[5];
+         operands[5] = tmp;
        }
-      output_asm_insn ("ldmia\t%1!, {%2, %3}", operands);
-      output_asm_insn ("stmia\t%0!, {%2, %3}", operands);
+      output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
+      output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
       break;
 
     case 3:
-      if (REGNO (operands[2]) > REGNO (operands[3]))
+      if (REGNO (operands[4]) > REGNO (operands[5]))
        {
-         tmp = operands[2];
-         operands[2] = operands[3];
-         operands[3] = tmp;
+         tmp = operands[4];
+         operands[4] = operands[5];
+         operands[5] = tmp;
        }
-      if (REGNO (operands[3]) > REGNO (operands[4]))
+      if (REGNO (operands[5]) > REGNO (operands[6]))
        {
-         tmp = operands[3];
-         operands[3] = operands[4];
-         operands[4] = tmp;
+         tmp = operands[5];
+         operands[5] = operands[6];
+         operands[6] = tmp;
        }
-      if (REGNO (operands[2]) > REGNO (operands[3]))
+      if (REGNO (operands[4]) > REGNO (operands[5]))
        {
-         tmp = operands[2];
-         operands[2] = operands[3];
-         operands[3] = tmp;
+         tmp = operands[4];
+         operands[4] = operands[5];
+         operands[5] = tmp;
        }
       
-      output_asm_insn ("ldmia\t%1!, {%2, %3, %4}", operands);
-      output_asm_insn ("stmia\t%0!, {%2, %3, %4}", operands);
+      output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
+      output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
       break;
 
     default:
@@ -9442,13 +10324,13 @@ thumb_expand_movstrqi (operands)
 
   while (len >= 12)
     {
-      emit_insn (gen_movmem12b (out, in));
+      emit_insn (gen_movmem12b (out, in, out, in));
       len -= 12;
     }
   
   if (len >= 8)
     {
-      emit_insn (gen_movmem8b (out, in));
+      emit_insn (gen_movmem8b (out, in, out, in));
       len -= 8;
     }
   
@@ -9588,11 +10470,8 @@ aof_pic_entry (x)
       /* We mark this here and not in arm_add_gc_roots() to avoid
         polluting even more code with ifdefs, and because it never
         contains anything useful until we assign to it here.  */
-      ggc_add_rtx_root (& aof_pic_label, 1);
-      /* This needs to persist throughout the compilation.  */
-      end_temporary_allocation ();
+      ggc_add_rtx_root (&aof_pic_label, 1);
       aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
-      resume_temporary_allocation ();
     }
 
   for (offset = 0, chainp = &aof_pic_chain; *chainp;
This page took 0.150474 seconds and 5 git commands to generate.