OSDN Git Service

* hooks.c (hook_tree_bool_false): New.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index c7d828e..babf1a8 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for HPPA.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002 Free Software Foundation, Inc.
    Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
 
 This file is part of GNU CC.
@@ -32,15 +32,60 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "flags.h"
 #include "tree.h"
-#include "reload.h"
+#include "except.h"
 #include "expr.h"
+#include "optabs.h"
+#include "libfuncs.h"
+#include "reload.h"
 #include "c-tree.h"
+#include "integrate.h"
 #include "function.h"
 #include "obstack.h"
 #include "toplev.h"
 #include "ggc.h"
 #include "recog.h"
+#include "predict.h"
 #include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+
+static int hppa_use_dfa_pipeline_interface PARAMS ((void));
+
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hppa_use_dfa_pipeline_interface
+
+static int
+hppa_use_dfa_pipeline_interface ()
+{
+  return 1;
+}
+
+/* Return nonzero if there is a bypass for the output of 
+   OUT_INSN and the fp store IN_INSN.  */
+int
+hppa_fpstore_bypass_p (out_insn, in_insn)
+     rtx out_insn, in_insn;
+{
+  enum machine_mode store_mode;
+  enum machine_mode other_mode;
+  rtx set;
+
+  if (recog_memoized (in_insn) < 0
+      || get_attr_type (in_insn) != TYPE_FPSTORE
+      || recog_memoized (out_insn) < 0)
+    return 0;
+
+  store_mode = GET_MODE (SET_SRC (PATTERN (in_insn)));
+
+  set = single_set (out_insn);
+  if (!set)
+    return 0;
+
+  other_mode = GET_MODE (SET_SRC (set));
+
+  return (GET_MODE_SIZE (store_mode) == GET_MODE_SIZE (other_mode));
+}
+  
 
 #ifndef DO_FRAME_NOTES
 #ifdef INCOMING_RETURN_ADDR_RTX
@@ -50,9 +95,7 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #endif
 
-static void pa_init_machine_status PARAMS ((struct function *));
-static void pa_mark_machine_status PARAMS ((struct function *));
-static void pa_free_machine_status PARAMS ((struct function *));
+static inline rtx force_mode PARAMS ((enum machine_mode, rtx));
 static void pa_combine_instructions PARAMS ((rtx));
 static int pa_can_combine_p PARAMS ((rtx, rtx, rtx, int, rtx, rtx, rtx));
 static int forward_branch_p PARAMS ((rtx));
@@ -61,10 +104,18 @@ static void pa_add_gc_roots PARAMS ((void));
 static void mark_deferred_plabels PARAMS ((void *));
 static void compute_zdepwi_operands PARAMS ((unsigned HOST_WIDE_INT, unsigned *));
 static int compute_movstrsi_length PARAMS ((rtx));
+static bool pa_assemble_integer PARAMS ((rtx, unsigned int, int));
 static void remove_useless_addtr_insns PARAMS ((rtx, int));
-static rtx store_reg PARAMS ((int, int, int));
-static rtx load_reg PARAMS ((int, int, int));
-static rtx set_reg_plus_d PARAMS ((int, int, int));
+static void store_reg PARAMS ((int, int, int));
+static void store_reg_modify PARAMS ((int, int, int));
+static void load_reg PARAMS ((int, int, int));
+static void set_reg_plus_d PARAMS ((int, int, int, int));
+static void pa_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
+static int pa_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static int pa_adjust_priority PARAMS ((rtx, int));
+static int pa_issue_rate PARAMS ((void));
+static void pa_select_section PARAMS ((tree, int, unsigned HOST_WIDE_INT))
+     ATTRIBUTE_UNUSED;
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
@@ -104,11 +155,42 @@ struct deferred_plabel
   char *name;
 } *deferred_plabels = 0;
 int n_deferred_plabels = 0;
-
+\f
+/* Initialize the GCC target structure.  */
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.dword\t"
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
+#undef TARGET_ASM_INTEGER
+#define TARGET_ASM_INTEGER pa_assemble_integer
+
+#undef TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE pa_output_function_prologue
+#undef TARGET_ASM_FUNCTION_EPILOGUE
+#define TARGET_ASM_FUNCTION_EPILOGUE pa_output_function_epilogue
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST pa_adjust_cost
+#undef TARGET_SCHED_ADJUST_PRIORITY
+#define TARGET_SCHED_ADJUST_PRIORITY pa_adjust_priority
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE pa_issue_rate
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+\f
 void
 override_options ()
 {
-  /* Default to 7100LC scheduling.  */
+  /* Default to 8000 scheduling.  */
   if (pa_cpu_string && ! strcmp (pa_cpu_string, "7100"))
     {
       pa_cpu_string = "7100";
@@ -119,8 +201,7 @@ override_options ()
       pa_cpu_string = "700";
       pa_cpu = PROCESSOR_700;
     }
-  else if (pa_cpu_string == NULL
-         || ! strcmp (pa_cpu_string, "7100LC"))
+  else if (pa_cpu_string && ! strcmp (pa_cpu_string, "7100LC"))
     {
       pa_cpu_string = "7100LC";
       pa_cpu = PROCESSOR_7100LC;
@@ -130,14 +211,20 @@ override_options ()
       pa_cpu_string = "7200";
       pa_cpu = PROCESSOR_7200;
     }
-  else if (pa_cpu_string && ! strcmp (pa_cpu_string, "8000"))
+  else if (pa_cpu_string && ! strcmp (pa_cpu_string, "7300"))
+    {
+      pa_cpu_string = "7300";
+      pa_cpu = PROCESSOR_7300;
+    }
+  else if (pa_cpu_string == NULL
+          || ! strcmp (pa_cpu_string, "8000"))
     {
       pa_cpu_string = "8000";
       pa_cpu = PROCESSOR_8000;
     }
   else
     {
-      warning ("Unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, and 8000\n", pa_cpu_string);
+      warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
     }
 
   /* Set the instruction set architecture.  */
@@ -162,9 +249,17 @@ override_options ()
     }
   else if (pa_arch_string)
     {
-      warning ("Unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
+      warning ("unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
     }
 
+  /* Unconditional branches in the delay slot are not compatible with dwarf2
+     call frame information.  There is no benefit in using this optimization
+     on PA8000 and later processors.  */
+  if (pa_cpu >= PROCESSOR_8000
+      || (! USING_SJLJ_EXCEPTIONS && flag_exceptions)
+      || flag_unwind_tables)
+    target_flags &= ~MASK_JUMP_IN_DELAY;
+
   if (flag_pic && TARGET_PORTABLE_RUNTIME)
     {
       warning ("PIC code generation is not supported in the portable runtime model\n");
@@ -178,7 +273,7 @@ override_options ()
   if (! TARGET_GAS && write_symbols != NO_DEBUG)
     {
       warning ("-g is only supported when using GAS on this processor,");
-      warning ("-g option disabled.");
+      warning ("-g option disabled");
       write_symbols = NO_DEBUG;
     }
 
@@ -187,48 +282,22 @@ override_options ()
   if (flag_pic == 1 || TARGET_64BIT)
     flag_pic = 2;
 
-  /* Register global variables with the garbage collector.  */
-  pa_add_gc_roots ();
-
-  /* Arrange to save and restore machine status around nested functions.  */
-  init_machine_status = pa_init_machine_status;
-  mark_machine_status = pa_mark_machine_status;
-  free_machine_status = pa_free_machine_status;
-}
-
-/* Functions to initialize pic_offset_table_save_rtx.
-   These will be called, via pointer variables,
-   from push_function_context and pop_function_context.  */
-
-static void
-pa_init_machine_status (p)
-     struct function *p;
-{
-  p->machine = (machine_function *) xmalloc (sizeof (machine_function));
-
-  p->machine->pic_offset_table_save_rtx = NULL_RTX;
-}
-
-static void
-pa_mark_machine_status (p)
-     struct function *p;
-{
-  if (p->machine)
-    ggc_mark_rtx (p->machine->pic_offset_table_save_rtx);
-}
+  /* We can't guarantee that .dword is available for 32-bit targets.  */
+  if (UNITS_PER_WORD == 4)
+    targetm.asm_out.aligned_op.di = NULL;
 
-static void
-pa_free_machine_status (p)
-     struct function *p;
-{
-  if (p->machine == NULL)
-    return;
+  /* The unaligned ops are only available when using GAS.  */
+  if (!TARGET_GAS)
+    {
+      targetm.asm_out.unaligned_op.hi = NULL;
+      targetm.asm_out.unaligned_op.si = NULL;
+      targetm.asm_out.unaligned_op.di = NULL;
+    }
 
-  free (p->machine);
-  p->machine = NULL;
+  /* Register global variables with the garbage collector.  */
+  pa_add_gc_roots ();
 }
 
-
 /* Return non-zero only if OP is a register of mode MODE,
    or CONST0_RTX.  */
 int
@@ -261,7 +330,7 @@ symbolic_expression_p (x)
      register rtx x;
 {
 
-  /* Strip off any HIGH. */
+  /* Strip off any HIGH.  */
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
 
@@ -342,6 +411,32 @@ reg_or_0_or_nonsymb_mem_operand (op, mode)
   return 0;
 }
 
+/* Return 1 if the operand is a register operand or a non-symbolic memory
+   operand after reload.  This predicate is used for branch patterns that
+   internally handle register reloading.  We need to accept non-symbolic
+   memory operands after reload to ensure that the pattern is still valid
+   if reload didn't find a hard register for the operand.  */
+
+int
+reg_before_reload_operand (op, mode)
+    register rtx op;
+    enum machine_mode mode;
+{
+  /* Don't accept a SUBREG since it will need a reload.  */
+  if (GET_CODE (op) == SUBREG)
+    return 0;
+
+  if (register_operand (op, mode))
+    return 1;
+
+  if (reload_completed
+      && memory_operand (op, mode)
+      && ! symbolic_memory_operand (op, mode))
+    return 1;
+
+  return 0;
+}
+
 /* Accept any constant that can be moved in one instructions into a
    general register.  */
 int
@@ -393,12 +488,14 @@ move_operand (op, mode)
       && ((GET_CODE (XEXP (op, 0)) == MULT
           && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
           && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT
-          && INTVAL (XEXP (XEXP (op, 0), 1)) == GET_MODE_SIZE (mode)
+          && INTVAL (XEXP (XEXP (op, 0), 1))
+             == (HOST_WIDE_INT) GET_MODE_SIZE (mode)
           && GET_CODE (XEXP (op, 1)) == REG)
          || (GET_CODE (XEXP (op, 1)) == MULT
              &&GET_CODE (XEXP (XEXP (op, 1), 0)) == REG
              && GET_CODE (XEXP (XEXP (op, 1), 1)) == CONST_INT
-             && INTVAL (XEXP (XEXP (op, 1), 1)) == GET_MODE_SIZE (mode)
+             && INTVAL (XEXP (XEXP (op, 1), 1))
+                == (HOST_WIDE_INT) GET_MODE_SIZE (mode)
              && GET_CODE (XEXP (op, 0)) == REG)))
     return 1;
 
@@ -511,7 +608,7 @@ arith_double_operand (op, mode)
                  == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
 }
 
-/* Return truth value of whether OP is a integer which fits the
+/* Return truth value of whether OP is an integer which fits the
    range constraining immediate operands in three-address insns, or
    is an integer register.  */
 
@@ -533,7 +630,7 @@ ireg_operand (op, mode)
   return (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32);
 }
 
-/* Return truth value of whether OP is a integer which fits the
+/* Return truth value of whether OP is an integer which fits the
    range constraining immediate operands in three-address insns.  */
 
 int
@@ -568,7 +665,7 @@ uint32_operand (op, mode)
 #if HOST_BITS_PER_WIDE_INT > 32
   /* All allowed constants will fit a CONST_INT.  */
   return (GET_CODE (op) == CONST_INT
-         && (INTVAL (op) >= 0 && INTVAL (op) < 0x100000000L));
+         && (INTVAL (op) >= 0 && INTVAL (op) < (HOST_WIDE_INT) 1 << 32));
 #else
   return (GET_CODE (op) == CONST_INT
          || (GET_CODE (op) == CONST_DOUBLE
@@ -584,7 +681,9 @@ arith5_operand (op, mode)
   return register_operand (op, mode) || int5_operand (op, mode);
 }
 
-/* True iff zdepi can be used to generate this CONST_INT.  */
+/* True iff zdepi can be used to generate this CONST_INT.
+   zdepi first sign extends a 5 bit signed number to a given field
+   length, then places this field anywhere in a zero.  */
 int
 zdepi_cint_p (x)
      unsigned HOST_WIDE_INT x;
@@ -749,7 +848,7 @@ legitimize_pic_address (orig, mode, reg)
       if (GET_CODE (orig) == CONST_INT)
        {
          if (INT_14_BITS (orig))
-           return plus_constant_for_output (base, INTVAL (orig));
+           return plus_constant (base, INTVAL (orig));
          orig = force_reg (Pmode, orig);
        }
       pic_ref = gen_rtx_PLUS (Pmode, base, orig);
@@ -819,7 +918,7 @@ hppa_legitimize_address (x, oldx, mode)
   if (flag_pic)
     return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
 
-  /* Strip off CONST. */
+  /* Strip off CONST.  */
   if (GET_CODE (x) == CONST)
     x = XEXP (x, 0);
 
@@ -946,7 +1045,7 @@ hppa_legitimize_address (x, oldx, mode)
        reg2 = force_reg (Pmode, force_operand (reg2, 0));
 
       /* Figure out what the base and index are.  */
-        
+
       if (GET_CODE (reg1) == REG
          && REG_POINTER (reg1))
        {
@@ -1037,13 +1136,13 @@ hppa_legitimize_address (x, oldx, mode)
 
       /* Add the result to our base register and return.  */
       return force_reg (Pmode, gen_rtx_PLUS (Pmode, base, reg1));
-      
+
     }
 
   /* Uh-oh.  We might have an address for x[n-100000].  This needs
      special handling to avoid creating an indexed memory address
      with x-100000 as the base.
-    
+
      If the constant part is small enough, then it's still safe because
      there is a guard page at the beginning and end of the data segment.
 
@@ -1072,7 +1171,7 @@ hppa_legitimize_address (x, oldx, mode)
                      (const (plus (symbol_ref) (const_int))))
 
             Where const_int is small.  In that case the const
-            expression is a valid pointer for indexing. 
+            expression is a valid pointer for indexing.
 
             If const_int is big, but can be divided evenly by shadd_const
             and added to (reg).  This allows more scaled indexed addresses.  */
@@ -1171,11 +1270,27 @@ hppa_address_cost (X)
   return 4;
 }
 
+/* Ensure mode of ORIG, a REG rtx, is MODE.  Returns either ORIG or a
+   new rtx with the correct mode.  */
+static inline rtx
+force_mode (mode, orig)
+     enum machine_mode mode;
+     rtx orig;
+{
+  if (mode == GET_MODE (orig))
+    return orig;
+
+  if (REGNO (orig) >= FIRST_PSEUDO_REGISTER)
+    abort ();
+
+  return gen_rtx_REG (mode, REGNO (orig));
+}
+
 /* Emit insns to move operands[1] into operands[0].
 
    Return 1 if we have written out everything that needs to be done to
    do the move.  Otherwise, return 0 and the caller will emit the move
-   normally. 
+   normally.
 
    Note SCRATCH_REG may not be in the proper mode depending on how it
    will be used.  This routine is resposible for creating a new copy
@@ -1205,7 +1320,7 @@ emit_move_sequence (operands, mode, scratch_reg)
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand0),
                                 reg_equiv_mem [REGNO (SUBREG_REG (operand0))],
                                 SUBREG_BYTE (operand0));
-      operand0 = alter_subreg (temp);
+      operand0 = alter_subreg (&temp);
     }
 
   if (scratch_reg
@@ -1222,7 +1337,7 @@ emit_move_sequence (operands, mode, scratch_reg)
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand1),
                                 reg_equiv_mem [REGNO (SUBREG_REG (operand1))],
                                 SUBREG_BYTE (operand1));
-      operand1 = alter_subreg (temp);
+      operand1 = alter_subreg (&temp);
     }
 
   if (scratch_reg && reload_in_progress && GET_CODE (operand0) == MEM
@@ -1235,7 +1350,7 @@ emit_move_sequence (operands, mode, scratch_reg)
     operand1 = gen_rtx_MEM (GET_MODE (operand1), tem);
 
   /* Handle secondary reloads for loads/stores of FP registers from
-     REG+D addresses where D does not fit in 5 bits, including 
+     REG+D addresses where D does not fit in 5 bits, including
      (subreg (mem (addr))) cases.  */
   if (fp_reg_operand (operand0, mode)
       && ((GET_CODE (operand1) == MEM
@@ -1251,7 +1366,7 @@ emit_move_sequence (operands, mode, scratch_reg)
       /* SCRATCH_REG will hold an address and maybe the actual data.  We want
         it in WORD_MODE regardless of what mode it was originally given
         to us.  */
-      scratch_reg = gen_rtx_REG (word_mode, REGNO (scratch_reg));
+      scratch_reg = force_mode (word_mode, scratch_reg);
 
       /* D might not fit in 14 bits either; for such cases load D into
         scratch reg.  */
@@ -1283,7 +1398,7 @@ emit_move_sequence (operands, mode, scratch_reg)
       /* SCRATCH_REG will hold an address and maybe the actual data.  We want
         it in WORD_MODE regardless of what mode it was originally given
         to us.  */
-      scratch_reg = gen_rtx_REG (word_mode, REGNO (scratch_reg));
+      scratch_reg = force_mode (word_mode, scratch_reg);
 
       /* D might not fit in 14 bits either; for such cases load D into
         scratch reg.  */
@@ -1321,7 +1436,7 @@ emit_move_sequence (operands, mode, scratch_reg)
       /* SCRATCH_REG will hold an address and maybe the actual data.  We want
         it in WORD_MODE regardless of what mode it was originally given
         to us.  */
-      scratch_reg = gen_rtx_REG (word_mode, REGNO (scratch_reg));
+      scratch_reg = force_mode (word_mode, scratch_reg);
 
       /* Force the constant into memory and put the address of the
         memory location into scratch_reg.  */
@@ -1352,9 +1467,9 @@ emit_move_sequence (operands, mode, scratch_reg)
        {
          /* We are reloading the address into the scratch register, so we
             want to make sure the scratch register is a full register.  */
-         scratch_reg = gen_rtx_REG (word_mode, REGNO (scratch_reg));
+         scratch_reg = force_mode (word_mode, scratch_reg);
 
-         emit_move_insn (scratch_reg, XEXP (XEXP (operand1, 0), 1));   
+         emit_move_insn (scratch_reg, XEXP (XEXP (operand1, 0), 1));
          emit_move_insn (scratch_reg, gen_rtx_fmt_ee (GET_CODE (XEXP (operand1,
                                                                        0)),
                                                       Pmode,
@@ -1366,8 +1481,8 @@ emit_move_sequence (operands, mode, scratch_reg)
             we want to load it in the same width as the original MEM,
             which must be the same as the width of the ultimate destination,
             OPERAND0.  */
-         scratch_reg = gen_rtx_REG (GET_MODE (operand0), REGNO (scratch_reg));
-         
+         scratch_reg = force_mode (GET_MODE (operand0), scratch_reg);
+
          emit_move_insn (scratch_reg, gen_rtx_MEM (GET_MODE (operand0),
                                                    scratch_reg));
        }
@@ -1375,7 +1490,8 @@ emit_move_sequence (operands, mode, scratch_reg)
        {
          /* We want to load the scratch register using the same mode as
             the ultimate destination.  */
-         scratch_reg = gen_rtx_REG (GET_MODE (operand0), REGNO (scratch_reg));
+         scratch_reg = force_mode (GET_MODE (operand0), scratch_reg);
+
          emit_move_insn (scratch_reg, operand1);
        }
 
@@ -1389,7 +1505,8 @@ emit_move_sequence (operands, mode, scratch_reg)
   else if (register_operand (operand0, mode))
     {
       if (register_operand (operand1, mode)
-         || (GET_CODE (operand1) == CONST_INT && INT_14_BITS (operand1))
+         || (GET_CODE (operand1) == CONST_INT
+             && cint_ok_for_move (INTVAL (operand1)))
          || (operand1 == CONST0_RTX (mode))
          || (GET_CODE (operand1) == HIGH
              && !symbolic_operand (XEXP (operand1, 0), VOIDmode))
@@ -1462,7 +1579,7 @@ emit_move_sequence (operands, mode, scratch_reg)
                  /* SCRATCH_REG will hold an address and maybe the actual
                     data.  We want it in WORD_MODE regardless of what mode it
                     was originally given to us.  */
-                 scratch_reg = gen_rtx_REG (word_mode, REGNO (scratch_reg));
+                 scratch_reg = force_mode (word_mode, scratch_reg);
                }
              else if (flag_pic)
                scratch_reg = gen_reg_rtx (Pmode);
@@ -1485,7 +1602,7 @@ emit_move_sequence (operands, mode, scratch_reg)
                  /* Force the function label into memory.  */
                  temp = force_const_mem (mode, operand1);
                }
-               
+
 
              /* Get the address of the memory location.  PIC-ify it if
                 necessary.  */
@@ -1520,7 +1637,7 @@ emit_move_sequence (operands, mode, scratch_reg)
                  /* TEMP will hold an address and maybe the actual
                     data.  We want it in WORD_MODE regardless of what mode it
                     was originally given to us.  */
-                 temp = gen_rtx_REG (word_mode, REGNO (temp));
+                 temp = force_mode (word_mode, temp);
                }
              else
                temp = gen_reg_rtx (Pmode);
@@ -1559,13 +1676,13 @@ emit_move_sequence (operands, mode, scratch_reg)
                  /* TEMP will hold an address and maybe the actual
                     data.  We want it in WORD_MODE regardless of what mode it
                     was originally given to us.  */
-                 temp = gen_rtx_REG (word_mode, REGNO (temp));
+                 temp = force_mode (word_mode, temp);
                }
              else
                temp = gen_reg_rtx (mode);
 
              /* Loading a SYMBOL_REF into a register makes that register
-                safe to be used as the base in an indexed address. 
+                safe to be used as the base in an indexed address.
 
                 Don't mark hard registers though.  That loses.  */
              if (GET_CODE (operand0) == REG
@@ -1591,23 +1708,28 @@ emit_move_sequence (operands, mode, scratch_reg)
       else if (GET_CODE (operand1) != CONST_INT
               || ! cint_ok_for_move (INTVAL (operand1)))
        {
+         rtx extend = NULL_RTX;
          rtx temp;
-         int need_zero_extend = 0;
 
          if (TARGET_64BIT && GET_CODE (operand1) == CONST_INT
+             && HOST_BITS_PER_WIDE_INT > 32
              && GET_MODE_BITSIZE (GET_MODE (operand0)) > 32)
            {
              HOST_WIDE_INT val = INTVAL (operand1);
-             HOST_WIDE_INT nval = INTVAL (operand1);
-
-             /* If the value is the same after a 32->64bit sign
-                extension, then we can use it as-is.  Else we will
-                need to sign extend the constant from 32->64bits
-                then zero extend the result from 32->64bits.  */
-             nval = ((val & 0xffffffff) ^ (~0x7fffffff)) + 0x80000000;
+             HOST_WIDE_INT nval;
+
+             /* Extract the low order 32 bits of the value and sign extend.
+                If the new value is the same as the original value, we can
+                can use the original value as-is.  If the new value is
+                different, we use it and insert the most-significant 32-bits
+                of the original value into the final result.  */
+             nval = ((val & (((HOST_WIDE_INT) 2 << 31) - 1))
+                     ^ ((HOST_WIDE_INT) 1 << 31)) - ((HOST_WIDE_INT) 1 << 31);
              if (val != nval)
                {
-                 need_zero_extend = 1;
+#if HOST_BITS_PER_WIDE_INT > 32
+                 extend = GEN_INT (val >> 32);
+#endif
                  operand1 = GEN_INT (nval);
                }
            }
@@ -1617,19 +1739,44 @@ emit_move_sequence (operands, mode, scratch_reg)
          else
            temp = gen_reg_rtx (mode);
 
-         emit_insn (gen_rtx_SET (VOIDmode, temp,
-                                 gen_rtx_HIGH (mode, operand1)));
-         operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
-         emit_move_insn (operands[0], operands[1]);
+         if (GET_CODE (operand1) == CONST_INT)
+           {
+             /* Directly break constant into low and high parts.  This
+                provides better optimization opportunities because various
+                passes recognize constants split with PLUS but not LO_SUM.
+                We use a 14-bit signed low part except when the addition
+                of 0x4000 to the high part might change the sign of the
+                high part.  */
+             HOST_WIDE_INT value = INTVAL (operand1);
+             HOST_WIDE_INT low = value & 0x3fff;
+             HOST_WIDE_INT high = value & ~ 0x3fff;
+
+             if (low >= 0x2000)
+               {
+                 if (high == 0x7fffc000 || (mode == HImode && high == 0x4000))
+                   high += 0x2000;
+                 else
+                   high += 0x4000;
+               }
+
+             low = value - high;
 
-         if (need_zero_extend)
+             emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (high)));
+             operands[1] = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+           }
+         else
            {
-             emit_insn (gen_zero_extendsidi2 (operands[0],
-                                              gen_rtx_SUBREG (SImode,
-                                                              operands[0],
-                                                              0)));
+             emit_insn (gen_rtx_SET (VOIDmode, temp,
+                                     gen_rtx_HIGH (mode, operand1)));
+             operands[1] = gen_rtx_LO_SUM (mode, temp, operand1);
            }
-       
+
+         emit_move_insn (operands[0], operands[1]);
+
+         if (extend != NULL_RTX)
+           emit_insn (gen_insv (operands[0], GEN_INT (32), const0_rtx,
+                                extend));
+
          return 1;
        }
     }
@@ -1816,7 +1963,7 @@ compute_zdepdi_operands (imm, op)
       /* Find the width of the bitstring in IMM.  */
       for (len = 5; len < HOST_BITS_PER_WIDE_INT; len++)
        {
-         if ((imm & ((unsigned HOST_WIDE_INT)1 << len)) == 0)
+         if ((imm & ((unsigned HOST_WIDE_INT) 1 << len)) == 0)
            break;
        }
 
@@ -1899,7 +2046,7 @@ output_move_double (operands)
              return "{stws|stw},ma %1,-8(%0)\n\tstw %R1,12(%0)";
            }
          else
-           abort();
+           abort ();
        }
       else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
        {
@@ -1919,7 +2066,7 @@ output_move_double (operands)
              return "{stws|stw},mb %1,-8(%0)\n\tstw %R1,4(%0)";
            }
          else
-           abort();
+           abort ();
        }
     }
   if (optype1 == MEMOP)
@@ -1943,7 +2090,7 @@ output_move_double (operands)
                 save a register file writeback)  */
              if (GET_CODE (addr) == POST_INC)
                return "{ldws|ldw},ma 8(%1),%0\n\tldw -4(%1),%R0";
-             return "{ldws|ldw},ma -8(%1),%0\n\tldw 12(%1),%R0}";
+             return "{ldws|ldw},ma -8(%1),%0\n\tldw 12(%1),%R0";
            }
          else
            {
@@ -2033,14 +2180,14 @@ output_move_double (operands)
   if (optype0 == REGOP)
     latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
   else if (optype0 == OFFSOP)
-    latehalf[0] = adj_offsettable_operand (operands[0], 4);
+    latehalf[0] = adjust_address (operands[0], SImode, 4);
   else
     latehalf[0] = operands[0];
 
   if (optype1 == REGOP)
     latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
   else if (optype1 == OFFSOP)
-    latehalf[1] = adj_offsettable_operand (operands[1], 4);
+    latehalf[1] = adjust_address (operands[1], SImode, 4);
   else if (optype1 == CNSTOP)
     split_double (operands[1], &operands[1], &latehalf[1]);
   else
@@ -2056,10 +2203,10 @@ output_move_double (operands)
        can create such insns.
 
        mem in this case will be either register indirect or register
-       indirect plus a valid offset. 
+       indirect plus a valid offset.
 
        register -> register move where REGNO(dst) == REGNO(src + 1)
-       someone (Tim/Tege?) claimed this can happen for parameter loads. 
+       someone (Tim/Tege?) claimed this can happen for parameter loads.
 
      Handle mem -> register case first.  */
   if (optype0 == REGOP
@@ -2176,7 +2323,7 @@ find_addr_reg (addr)
    OPERANDS[2] is a register for temporary storage.
    OPERANDS[4] is the size as a CONST_INT
    OPERANDS[3] is a register for temporary storage.
-   OPERANDS[5] is the alignment safe to use, as a CONST_INT. 
+   OPERANDS[5] is the alignment safe to use, as a CONST_INT.
    OPERANDS[6] is another temporary register.   */
 
 const char *
@@ -2285,8 +2432,8 @@ compute_movstrsi_length (insn)
      rtx insn;
 {
   rtx pat = PATTERN (insn);
-  int align = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));
-  unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 5), 0));
+  unsigned int align = INTVAL (XEXP (XVECEXP (pat, 0, 7), 0));
+  unsigned long n_bytes = INTVAL (XEXP (XVECEXP (pat, 0, 6), 0));
   unsigned int n_insns = 0;
 
   /* We can't move more than four bytes at a time because the PA
@@ -2334,7 +2481,7 @@ output_and (operands)
          break;
 
       if (ms0 != 32)
-       abort();
+       abort ();
 
       if (ls1 == 32)
        {
@@ -2372,22 +2519,22 @@ output_64bit_and (operands)
   if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
     {
       unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
-      unsigned HOST_WIDE_INT ls0, ls1, ms0, p, len;
+      int ls0, ls1, ms0, p, len;
 
       for (ls0 = 0; ls0 < HOST_BITS_PER_WIDE_INT; ls0++)
-       if ((mask & ((unsigned HOST_WIDE_INT)1 << ls0)) == 0)
+       if ((mask & ((unsigned HOST_WIDE_INT) 1 << ls0)) == 0)
          break;
 
       for (ls1 = ls0; ls1 < HOST_BITS_PER_WIDE_INT; ls1++)
-       if ((mask & ((unsigned HOST_WIDE_INT)1 << ls1)) != 0)
+       if ((mask & ((unsigned HOST_WIDE_INT) 1 << ls1)) != 0)
          break;
 
       for (ms0 = ls1; ms0 < HOST_BITS_PER_WIDE_INT; ms0++)
-       if ((mask & ((unsigned HOST_WIDE_INT)1 << ms0)) == 0)
+       if ((mask & ((unsigned HOST_WIDE_INT) 1 << ms0)) == 0)
          break;
 
       if (ms0 != HOST_BITS_PER_WIDE_INT)
-       abort();
+       abort ();
 
       if (ls1 == HOST_BITS_PER_WIDE_INT)
        {
@@ -2435,7 +2582,7 @@ output_ior (operands)
       break;
 
   if (bs1 != 32 && ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask)
-    abort();
+    abort ();
 
   p = 31 - bs0;
   len = bs1 - bs0;
@@ -2452,22 +2599,22 @@ output_64bit_ior (operands)
      rtx *operands;
 {
   unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
-  unsigned HOST_WIDE_INT bs0, bs1, p, len;
+  int bs0, bs1, p, len;
 
   if (INTVAL (operands[2]) == 0)
     return "copy %1,%0";
 
   for (bs0 = 0; bs0 < HOST_BITS_PER_WIDE_INT; bs0++)
-    if ((mask & ((unsigned HOST_WIDE_INT)1 << bs0)) != 0)
+    if ((mask & ((unsigned HOST_WIDE_INT) 1 << bs0)) != 0)
       break;
 
   for (bs1 = bs0; bs1 < HOST_BITS_PER_WIDE_INT; bs1++)
-    if ((mask & ((unsigned HOST_WIDE_INT)1 << bs1)) == 0)
+    if ((mask & ((unsigned HOST_WIDE_INT) 1 << bs1)) == 0)
       break;
 
   if (bs1 != HOST_BITS_PER_WIDE_INT
       && ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask)
-    abort();
+    abort ();
 
   p = 63 - bs0;
   len = bs1 - bs0;
@@ -2477,11 +2624,32 @@ output_64bit_ior (operands)
   return "depdi -1,%2,%3,%0";
 }
 \f
+/* Target hook for assembling integer objects.  This code handles
+   aligned SI and DI integers specially, since function references must
+   be preceded by P%.  */
+
+static bool
+pa_assemble_integer (x, size, aligned_p)
+     rtx x;
+     unsigned int size;
+     int aligned_p;
+{
+  if (size == UNITS_PER_WORD && aligned_p
+      && function_label_operand (x, VOIDmode))
+    {
+      fputs (size == 8? "\t.dword\tP%" : "\t.word\tP%", asm_out_file);
+      output_addr_const (asm_out_file, x);
+      fputc ('\n', asm_out_file);
+      return true;
+    }
+  return default_assemble_integer (x, size, aligned_p);
+}
+\f
 /* Output an ascii string.  */
 void
 output_ascii (file, p, size)
      FILE *file;
-     const unsigned char *p;
+     const char *p;
      int size;
 {
   int i;
@@ -2503,7 +2671,7 @@ output_ascii (file, p, size)
       int io = 0;
       for (io = 0, co = 0; io < MIN (4, size - i); io++)
        {
-         register unsigned int c = p[i + io];
+         register unsigned int c = (unsigned char) p[i + io];
 
          if (c == '\"' || c == '\\')
            partial_output[co++] = '\\';
@@ -2529,7 +2697,7 @@ output_ascii (file, p, size)
          fputs ("\"\n\t.STRING \"", file);
          chars_output = 0;
        }
-      fwrite (partial_output, 1, co, file);
+      fwrite (partial_output, 1, (size_t) co, file);
       chars_output += co;
       co = 0;
     }
@@ -2586,7 +2754,7 @@ remove_useless_addtr_insns (insns, check_notes)
              fcmp_count++;
              continue;
            }
-           
+
          tmp = PATTERN (insn);
          /* If this is an fbranch instruction, bump the fbranch counter.  */
          if (GET_CODE (tmp) == SET
@@ -2676,8 +2844,8 @@ remove_useless_addtr_insns (insns, check_notes)
                  /* Reverse our condition.  */
                  tmp = PATTERN (insn);
                  PUT_CODE (XEXP (tmp, 1),
-                   reverse_condition_maybe_unordered (GET_CODE (XEXP (tmp,
-                     1))));
+                           (reverse_condition_maybe_unordered
+                            (GET_CODE (XEXP (tmp, 1)))));
                }
            }
        }
@@ -2687,8 +2855,8 @@ remove_useless_addtr_insns (insns, check_notes)
 
 }
 \f
-/* You may have trouble believing this, but this is the 32 bit HP-PA stack
-   layout.  Wow.
+/* You may have trouble believing this, but this is the 32 bit HP-PA
+   stack layout.  Wow.
 
    Offset              Contents
 
@@ -2750,7 +2918,7 @@ remove_useless_addtr_insns (insns, check_notes)
 
 */
 
-/* Global variables set by FUNCTION_PROLOGUE.  */
+/* Global variables set by output_function_prologue().  */
 /* Size of frame.  Need to know this to emit return insns from
    leaf procedures.  */
 static int actual_fsize;
@@ -2762,18 +2930,18 @@ static int local_fsize, save_fregs;
    Note in DISP > 8k case, we will leave the high part of the address
    in %r1.  There is code in expand_hppa_{prologue,epilogue} that knows this.*/
 
-static rtx
+static void
 store_reg (reg, disp, base)
      int reg, disp, base;
 {
-  rtx i, dest, src, basereg;
+  rtx insn, dest, src, basereg;
 
   src = gen_rtx_REG (word_mode, reg);
   basereg = gen_rtx_REG (Pmode, base);
   if (VAL_14_BITS_P (disp))
     {
       dest = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
-      i = emit_move_insn (dest, src);
+      insn = emit_move_insn (dest, src);
     }
   else
     {
@@ -2782,39 +2950,101 @@ store_reg (reg, disp, base)
       rtx tmpreg = gen_rtx_REG (Pmode, 1);
       emit_move_insn (tmpreg, high);
       dest = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
-      i = emit_move_insn (dest, src);
+      insn = emit_move_insn (dest, src);
+      if (DO_FRAME_NOTES)
+       {
+         REG_NOTES (insn)
+           = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+               gen_rtx_SET (VOIDmode,
+                            gen_rtx_MEM (word_mode,
+                                         gen_rtx_PLUS (word_mode, basereg,
+                                                       delta)),
+                             src),
+                REG_NOTES (insn));
+       }
     }
-  return i;
+
+  if (DO_FRAME_NOTES)
+    RTX_FRAME_RELATED_P (insn) = 1;
 }
 
-/* Emit RTL to set REG to the value specified by BASE+DISP.
-   Handle case where DISP > 8k by using the add_high_const patterns.
+/* Emit RTL to store REG at the memory location specified by BASE and then
+   add MOD to BASE.  MOD must be <= 8k.  */
 
-   Note in DISP > 8k case, we will leave the high part of the address
-   in %r1.  There is code in expand_hppa_{prologue,epilogue} that knows this.*/
+static void
+store_reg_modify (base, reg, mod)
+     int base, reg, mod;
+{
+  rtx insn, basereg, srcreg, delta;
 
-static rtx
-set_reg_plus_d (reg, base, disp)
-     int reg, base, disp;
+  if (! VAL_14_BITS_P (mod))
+    abort ();
+
+  basereg = gen_rtx_REG (Pmode, base);
+  srcreg = gen_rtx_REG (word_mode, reg);
+  delta = GEN_INT (mod);
+
+  insn = emit_insn (gen_post_store (basereg, srcreg, delta));
+  if (DO_FRAME_NOTES)
+    {
+      RTX_FRAME_RELATED_P (insn) = 1;
+
+      /* RTX_FRAME_RELATED_P must be set on each frame related set
+        in a parallel with more than one element.  Don't set
+        RTX_FRAME_RELATED_P in the first set if reg is temporary
+        register 1. The effect of this operation is recorded in
+        the initial copy.  */
+      if (reg != 1)
+       {
+         RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
+         RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
+       }
+      else
+       {
+         /* The first element of a PARALLEL is always processed if it is
+            a SET.  Thus, we need an expression list for this case.  */
+         REG_NOTES (insn)
+           = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+               gen_rtx_SET (VOIDmode, basereg,
+                            gen_rtx_PLUS (word_mode, basereg, delta)),
+                REG_NOTES (insn));
+       }
+    }
+}
+
+/* Emit RTL to set REG to the value specified by BASE+DISP.  Handle case
+   where DISP > 8k by using the add_high_const patterns.  NOTE indicates
+   whether to add a frame note or not.
+
+   In the DISP > 8k case, we leave the high part of the address in %r1.
+   There is code in expand_hppa_{prologue,epilogue} that knows about this.  */
+
+static void
+set_reg_plus_d (reg, base, disp, note)
+     int reg, base, disp, note;
 {
-  rtx i;
+  rtx insn;
 
   if (VAL_14_BITS_P (disp))
     {
-      i = emit_move_insn (gen_rtx_REG (Pmode, reg),
-                         plus_constant (gen_rtx_REG (Pmode, base), disp));
+      insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
+                            plus_constant (gen_rtx_REG (Pmode, base), disp));
     }
   else
     {
+      rtx basereg = gen_rtx_REG (Pmode, base);
       rtx delta = GEN_INT (disp);
+
       emit_move_insn (gen_rtx_REG (Pmode, 1),
-                     gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, base),
+                     gen_rtx_PLUS (Pmode, basereg,
                                    gen_rtx_HIGH (Pmode, delta)));
-      i = emit_move_insn (gen_rtx_REG (Pmode, reg),
-                         gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 1),
-                                         delta));
+      insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
+                            gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 1),
+                                            delta));
     }
-  return i;
+
+  if (DO_FRAME_NOTES && note)
+    RTX_FRAME_RELATED_P (insn) = 1;
 }
 
 int
@@ -2831,6 +3061,18 @@ compute_frame_size (size, fregs_live)
      of them at the same time.  */
   fsize = size + (size || frame_pointer_needed ? STARTING_FRAME_OFFSET : 0);
 
+  /* If the current function calls __builtin_eh_return, then we need
+     to allocate stack space for registers that will hold data for
+     the exception handler.  */
+  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+    {
+      unsigned int i;
+
+      for (i = 0; EH_RETURN_DATA_REGNO (i) != INVALID_REGNUM; ++i)
+       continue;
+      fsize += i * UNITS_PER_WORD;
+    }
+
   /* Account for space used by the callee general register saves.  */
   for (i = 18; i >= 3; i--)
     if (regs_ever_live[i])
@@ -2860,15 +3102,32 @@ compute_frame_size (size, fregs_live)
      allocated for any function that makes calls or otherwise allocates
      stack space.  */
   if (!current_function_is_leaf || fsize)
-    fsize += 32;
+    fsize += TARGET_64BIT ? 16 : 32;
 
   return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
 }
 
+/* Generate the assembly code for function entry.  FILE is a stdio
+   stream to output the code to.  SIZE is an int: how many units of
+   temporary storage to allocate.
+
+   Refer to the array `regs_ever_live' to determine which registers to
+   save; `regs_ever_live[I]' is nonzero if register number I is ever
+   used in the function.  This function is responsible for knowing
+   which registers should not be saved even if used.  */
+
+/* On HP-PA, move-double insns between fpu and cpu need an 8-byte block
+   of memory.  If any fpu reg is used in the function, we allocate
+   such a block here, at the bottom of the frame, just in case it's needed.
+
+   If this function is a leaf procedure, then we may choose not
+   to do a "save" insn.  The decision about whether or not
+   to do this is made in regclass.c.  */
+
 void
-output_function_prologue (file, size)
+pa_output_function_prologue (file, size)
      FILE *file;
-     int size ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
   /* The function's label and associated .PROC must never be
      separated and must be output *after* any profiling declarations
@@ -2904,19 +3163,22 @@ output_function_prologue (file, size)
 
   fputs ("\n\t.ENTRY\n", file);
 
-  /* If we're using GAS and not using the portable runtime model, then
-     we don't need to accumulate the total number of code bytes.  */
-  if (TARGET_GAS && ! TARGET_PORTABLE_RUNTIME)
+  /* If we're using GAS and SOM, and not using the portable runtime model,
+     then we don't need to accumulate the total number of code bytes.  */
+  if ((TARGET_GAS && TARGET_SOM && ! TARGET_PORTABLE_RUNTIME)
+      /* FIXME: we can't handle long calls for TARGET_64BIT.  */
+      || TARGET_64BIT)
     total_code_bytes = 0;
   else if (INSN_ADDRESSES_SET_P ())
     {
       unsigned int old_total = total_code_bytes;
 
-      total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn()));
+      total_code_bytes += INSN_ADDRESSES (INSN_UID (get_last_insn ()));
       total_code_bytes += FUNCTION_BOUNDARY / BITS_PER_UNIT;
 
       /* Be prepared to handle overflows.  */
-      total_code_bytes = old_total > total_code_bytes ? -1 : total_code_bytes;
+      if (old_total > total_code_bytes)
+       total_code_bytes = -1;
     }
   else
     total_code_bytes = -1;
@@ -2924,26 +3186,13 @@ output_function_prologue (file, size)
   remove_useless_addtr_insns (get_insns (), 0);
 }
 
-#if DO_FRAME_NOTES
-#define FRP(INSN) \
-  do                                   \
-    {                                  \
-      rtx insn = INSN;                 \
-      RTX_FRAME_RELATED_P (insn) = 1;  \
-    }                                  \
-  while (0)
-#else
-#define FRP (INSN) INSN
-#endif
-
 void
 hppa_expand_prologue ()
 {
-  extern char call_used_regs[];
   int size = get_frame_size ();
   int merge_sp_adjust_with_store = 0;
   int i, offset;
-  rtx tmpreg, size_rtx;
+  rtx insn, tmpreg;
 
   gr_saved = 0;
   fr_saved = 0;
@@ -2961,13 +3210,12 @@ hppa_expand_prologue ()
 
   /* Compute a few things we will use often.  */
   tmpreg = gen_rtx_REG (word_mode, 1);
-  size_rtx = GEN_INT (actual_fsize);
 
   /* Save RP first.  The calling conventions manual states RP will
      always be stored into the caller's frame at sp - 20 or sp - 16
      depending on which ABI is in use.  */
-  if (regs_ever_live[2])
-    FRP (store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM));
+  if (regs_ever_live[2] || current_function_calls_eh_return)
+    store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
 
   /* Allocate the local frame and set up the frame pointer if needed.  */
   if (actual_fsize != 0)
@@ -2976,36 +3224,30 @@ hppa_expand_prologue ()
        {
          /* Copy the old frame pointer temporarily into %r1.  Set up the
             new stack pointer, then store away the saved old frame pointer
-            into the stack at sp+actual_fsize and at the same time update
-            the stack pointer by actual_fsize bytes.  Two versions, first
+            into the stack at sp and at the same time update the stack
+            pointer by actual_fsize bytes.  Two versions, first
             handles small (<8k) frames.  The second handles large (>=8k)
             frames.  */
-         emit_move_insn (tmpreg, frame_pointer_rtx);
-         FRP (emit_move_insn (frame_pointer_rtx, stack_pointer_rtx));
-         if (VAL_14_BITS_P (actual_fsize))
+         insn = emit_move_insn (tmpreg, frame_pointer_rtx);
+         if (DO_FRAME_NOTES)
            {
-             rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
-                                                   size_rtx));
-             if (DO_FRAME_NOTES)
-               {
-                 rtvec vec;
-                 RTX_FRAME_RELATED_P (insn) = 1;
-                 vec = gen_rtvec (2,
-                                  gen_rtx_SET (VOIDmode,
-                                               gen_rtx_MEM (word_mode,
-                                                            stack_pointer_rtx),
-                                               frame_pointer_rtx),
-                                  gen_rtx_SET (VOIDmode,
-                                               stack_pointer_rtx,
-                                               gen_rtx_PLUS (word_mode,
-                                                             stack_pointer_rtx,
-                                                             size_rtx)));
-                 REG_NOTES (insn)
-                   = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                        gen_rtx_SEQUENCE (VOIDmode, vec),
-                                        REG_NOTES (insn));
-               }
+             /* We need to record the frame pointer save here since the
+                new frame pointer is set in the following insn.  */
+             RTX_FRAME_RELATED_P (insn) = 1;
+             REG_NOTES (insn)
+               = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                   gen_rtx_SET (VOIDmode,
+                                gen_rtx_MEM (word_mode, stack_pointer_rtx),
+                                frame_pointer_rtx),
+                   REG_NOTES (insn));
            }
+
+         insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+         if (DO_FRAME_NOTES)
+           RTX_FRAME_RELATED_P (insn) = 1;
+
+         if (VAL_14_BITS_P (actual_fsize))
+           store_reg_modify (STACK_POINTER_REGNUM, 1, actual_fsize);
          else
            {
              /* It is incorrect to store the saved frame pointer at *sp,
@@ -3016,37 +3258,16 @@ hppa_expand_prologue ()
                 finish allocating the new frame.  */
              int adjust1 = 8192 - 64;
              int adjust2 = actual_fsize - adjust1;
-             rtx delta = GEN_INT (adjust1);
-             rtx insn = emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
-                                                   delta));
-             if (DO_FRAME_NOTES)
-               {
-                 rtvec vec;
-                 RTX_FRAME_RELATED_P (insn) = 1;
-                 vec = gen_rtvec (2,
-                                  gen_rtx_SET (VOIDmode,
-                                               gen_rtx_MEM (word_mode,
-                                                            stack_pointer_rtx),
-                                               frame_pointer_rtx),
-                                  gen_rtx_SET (VOIDmode,
-                                               stack_pointer_rtx,
-                                               gen_rtx_PLUS (word_mode,
-                                                             stack_pointer_rtx,
-                                                             delta)));
-                 REG_NOTES (insn)
-                   = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
-                                        gen_rtx_SEQUENCE (VOIDmode, vec),
-                                        REG_NOTES (insn));
-               }
 
-             FRP (set_reg_plus_d (STACK_POINTER_REGNUM,
-                                  STACK_POINTER_REGNUM,
-                                  adjust2));
+             store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
+             set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                             adjust2, 1);
            }
+
          /* Prevent register spills from being scheduled before the
             stack pointer is raised.  Necessary as we will be storing
             registers using the frame pointer as a base register, and
-            we happen to set fp before raising sp.  */ 
+            we happen to set fp before raising sp.  */
          emit_insn (gen_blockage ());
        }
       /* no frame pointer needed.  */
@@ -3061,9 +3282,8 @@ hppa_expand_prologue ()
          /* Can not optimize.  Adjust the stack frame by actual_fsize
             bytes.  */
          else
-           FRP (set_reg_plus_d (STACK_POINTER_REGNUM,
-                                STACK_POINTER_REGNUM,
-                                actual_fsize));
+           set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                           actual_fsize, 1);
        }
     }
 
@@ -3073,10 +3293,30 @@ hppa_expand_prologue ()
      was done earlier.  */
   if (frame_pointer_needed)
     {
-      for (i = 18, offset = local_fsize; i >= 4; i--)
+      offset = local_fsize;
+
+      /* Saving the EH return data registers in the frame is the simplest
+        way to get the frame unwind information emitted.  We put them
+        just before the general registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+       {
+         unsigned int i, regno;
+
+         for (i = 0; ; ++i)
+           {
+             regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+
+             store_reg (regno, offset, FRAME_POINTER_REGNUM);
+             offset += UNITS_PER_WORD;
+           }
+       }
+
+      for (i = 18; i >= 4; i--)
        if (regs_ever_live[i] && ! call_used_regs[i])
          {
-           FRP (store_reg (i, offset, FRAME_POINTER_REGNUM));
+           store_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
            gr_saved++;
          }
@@ -3086,21 +3326,45 @@ hppa_expand_prologue ()
   /* No frame pointer needed.  */
   else
     {
-      for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+      offset = local_fsize - actual_fsize;
+
+      /* Saving the EH return data registers in the frame is the simplest
+         way to get the frame unwind information emitted.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+       {
+         unsigned int i, regno;
+
+         for (i = 0; ; ++i)
+           {
+             regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+
+             /* If merge_sp_adjust_with_store is nonzero, then we can
+                optimize the first save.  */
+             if (merge_sp_adjust_with_store)
+               {
+                 store_reg_modify (STACK_POINTER_REGNUM, regno, -offset);
+                 merge_sp_adjust_with_store = 0;
+               }
+             else
+               store_reg (regno, offset, STACK_POINTER_REGNUM);
+             offset += UNITS_PER_WORD;
+           }
+       }
+
+      for (i = 18; i >= 3; i--)
        if (regs_ever_live[i] && ! call_used_regs[i])
          {
            /* If merge_sp_adjust_with_store is nonzero, then we can
               optimize the first GR save.  */
            if (merge_sp_adjust_with_store)
              {
-               rtx delta = GEN_INT (-offset);
+               store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
                merge_sp_adjust_with_store = 0;
-               FRP (emit_insn (gen_post_store (stack_pointer_rtx,
-                                               gen_rtx_REG (word_mode, i),
-                                               delta)));
              }
            else
-             FRP (store_reg (i, offset, STACK_POINTER_REGNUM));
+             store_reg (i, offset, STACK_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
            gr_saved++;
          }
@@ -3108,9 +3372,8 @@ hppa_expand_prologue ()
       /* If we wanted to merge the SP adjustment with a GR save, but we never
         did any GR saves, then just emit the adjustment here.  */
       if (merge_sp_adjust_with_store)
-       FRP (set_reg_plus_d (STACK_POINTER_REGNUM,
-                            STACK_POINTER_REGNUM,
-                            actual_fsize));
+       set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                       actual_fsize, 1);
     }
 
   /* The hppa calling conventions say that %r19, the pic offset
@@ -3128,12 +3391,20 @@ hppa_expand_prologue ()
   /* Floating point register store.  */
   if (save_fregs)
     {
+      rtx base;
+
       /* First get the frame or stack pointer to the start of the FP register
         save area.  */
       if (frame_pointer_needed)
-       FRP (set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset));
+       {
+         set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
+         base = frame_pointer_rtx;
+       }
       else
-       FRP (set_reg_plus_d (1, STACK_POINTER_REGNUM, offset));
+       {
+         set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
+         base = stack_pointer_rtx;
+       }
 
       /* Now actually save the FP registers.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3141,37 +3412,73 @@ hppa_expand_prologue ()
          if (regs_ever_live[i]
              || (! TARGET_64BIT && regs_ever_live[i + 1]))
            {
-             rtx addr, reg;
+             rtx addr, insn, reg;
              addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
              reg = gen_rtx_REG (DFmode, i);
-             FRP (emit_move_insn (addr, reg));
+             insn = emit_move_insn (addr, reg);
+             if (DO_FRAME_NOTES)
+               {
+                 RTX_FRAME_RELATED_P (insn) = 1;
+                 if (TARGET_64BIT)
+                   {
+                     rtx mem = gen_rtx_MEM (DFmode,
+                                            plus_constant (base, offset));
+                     REG_NOTES (insn)
+                       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                            gen_rtx_SET (VOIDmode, mem, reg),
+                                            REG_NOTES (insn));
+                   }
+                 else
+                   {
+                     rtx meml = gen_rtx_MEM (SFmode,
+                                             plus_constant (base, offset));
+                     rtx memr = gen_rtx_MEM (SFmode,
+                                             plus_constant (base, offset + 4));
+                     rtx regl = gen_rtx_REG (SFmode, i);
+                     rtx regr = gen_rtx_REG (SFmode, i + 1);
+                     rtx setl = gen_rtx_SET (VOIDmode, meml, regl);
+                     rtx setr = gen_rtx_SET (VOIDmode, memr, regr);
+                     rtvec vec;
+
+                     RTX_FRAME_RELATED_P (setl) = 1;
+                     RTX_FRAME_RELATED_P (setr) = 1;
+                     vec = gen_rtvec (2, setl, setr);
+                     REG_NOTES (insn)
+                       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                                            gen_rtx_SEQUENCE (VOIDmode, vec),
+                                            REG_NOTES (insn));
+                   }
+               }
+             offset += GET_MODE_SIZE (DFmode);
              fr_saved++;
            }
        }
     }
-}
 
-/* ?!? Do we want frame notes in the epilogue yet?  */
-#undef DO_FRAME_NOTES
-#define DO_FRAME_NOTES 0
-#undef FRP
-#define FRP(INSN) INSN
+  /* FIXME: expand_call and expand_millicode_call need to be fixed to
+     prevent insns with frame notes being scheduled in the delay slot
+     of calls.  This causes problems because the dwarf2 output code
+     processes the insn list serially.  For now, limit the migration
+     of prologue insns with a blockage.  */
+  if (DO_FRAME_NOTES)
+    emit_insn (gen_blockage ());
+}
 
 /* Emit RTL to load REG from the memory location specified by BASE+DISP.
    Handle case where DISP > 8k by using the add_high_const patterns.  */
 
-static rtx
+static void
 load_reg (reg, disp, base)
      int reg, disp, base;
 {
-  rtx i, src, dest, basereg;
+  rtx src, dest, basereg;
 
   dest = gen_rtx_REG (word_mode, reg);
   basereg = gen_rtx_REG (Pmode, base);
   if (VAL_14_BITS_P (disp))
     {
       src = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
-      i = emit_move_insn (dest, src);
+      emit_move_insn (dest, src);
     }
   else
     {
@@ -3180,15 +3487,22 @@ load_reg (reg, disp, base)
       rtx tmpreg = gen_rtx_REG (Pmode, 1);
       emit_move_insn (tmpreg, high);
       src = gen_rtx_MEM (word_mode, gen_rtx_LO_SUM (Pmode, tmpreg, delta));
-      i = emit_move_insn (dest, src);
+      emit_move_insn (dest, src);
     }
-  return i;
 }
 
-void
-output_function_epilogue (file, size)
+/* This function generates the assembly code for function exit.
+   Args are as for output_function_prologue ().
+
+   The function epilogue should not depend on the current stack
+   pointer!  It should use the frame pointer only.  This is mandatory
+   because of alloca; we also take advantage of it to omit stack
+   adjustments before returning.  */
+
+static void
+pa_output_function_epilogue (file, size)
      FILE *file;
-     int size ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT size ATTRIBUTE_UNUSED;
 {
   rtx insn = get_last_insn ();
 
@@ -3230,13 +3544,13 @@ hppa_expand_epilogue ()
 
   /* Try to restore RP early to avoid load/use interlocks when
      RP gets used in the return (bv) instruction.  This appears to still
-     be necessary even when we schedule the prologue and epilogue. */
-  if (regs_ever_live [2])
+     be necessary even when we schedule the prologue and epilogue.  */
+  if (regs_ever_live [2] || current_function_calls_eh_return)
     {
       ret_off = TARGET_64BIT ? -16 : -20;
       if (frame_pointer_needed)
        {
-         FRP (load_reg (2, ret_off, FRAME_POINTER_REGNUM));
+         load_reg (2, ret_off, FRAME_POINTER_REGNUM);
          ret_off = 0;
        }
       else
@@ -3244,7 +3558,7 @@ hppa_expand_epilogue ()
          /* No frame pointer, and stack is smaller than 8k.  */
          if (VAL_14_BITS_P (ret_off - actual_fsize))
            {
-             FRP (load_reg (2, ret_off - actual_fsize, STACK_POINTER_REGNUM));
+             load_reg (2, ret_off - actual_fsize, STACK_POINTER_REGNUM);
              ret_off = 0;
            }
        }
@@ -3253,16 +3567,62 @@ hppa_expand_epilogue ()
   /* General register restores.  */
   if (frame_pointer_needed)
     {
-      for (i = 18, offset = local_fsize; i >= 4; i--)
+      offset = local_fsize;
+
+      /* If the current function calls __builtin_eh_return, then we need
+         to restore the saved EH data registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+       {
+         unsigned int i, regno;
+
+         for (i = 0; ; ++i)
+           {
+             regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+
+             load_reg (regno, offset, FRAME_POINTER_REGNUM);
+             offset += UNITS_PER_WORD;
+           }
+       }
+
+      for (i = 18; i >= 4; i--)
        if (regs_ever_live[i] && ! call_used_regs[i])
          {
-           FRP (load_reg (i, offset, FRAME_POINTER_REGNUM));
+           load_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
          }
     }
   else
     {
-      for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
+      offset = local_fsize - actual_fsize;
+
+      /* If the current function calls __builtin_eh_return, then we need
+         to restore the saved EH data registers.  */
+      if (DO_FRAME_NOTES && current_function_calls_eh_return)
+       {
+         unsigned int i, regno;
+
+         for (i = 0; ; ++i)
+           {
+             regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+
+             /* Only for the first load.
+                merge_sp_adjust_with_load holds the register load
+                with which we will merge the sp adjustment.  */
+             if (merge_sp_adjust_with_load == 0
+                 && local_fsize == 0
+                 && VAL_14_BITS_P (-actual_fsize))
+               merge_sp_adjust_with_load = regno;
+             else
+               load_reg (regno, offset, STACK_POINTER_REGNUM);
+             offset += UNITS_PER_WORD;
+           }
+       }
+
+      for (i = 18; i >= 3; i--)
        {
          if (regs_ever_live[i] && ! call_used_regs[i])
            {
@@ -3274,7 +3634,7 @@ hppa_expand_epilogue ()
                  && VAL_14_BITS_P (-actual_fsize))
                merge_sp_adjust_with_load = i;
              else
-               FRP (load_reg (i, offset, STACK_POINTER_REGNUM));
+               load_reg (i, offset, STACK_POINTER_REGNUM);
              offset += UNITS_PER_WORD;
            }
        }
@@ -3288,9 +3648,9 @@ hppa_expand_epilogue ()
     {
       /* Adjust the register to index off of.  */
       if (frame_pointer_needed)
-       FRP (set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset));
+       set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
       else
-       FRP (set_reg_plus_d (1, STACK_POINTER_REGNUM, offset));
+       set_reg_plus_d (1, STACK_POINTER_REGNUM, offset, 0);
 
       /* Actually do the restores now.  */
       for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
@@ -3299,7 +3659,7 @@ hppa_expand_epilogue ()
          {
            rtx src = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
            rtx dest = gen_rtx_REG (DFmode, i);
-           FRP (emit_move_insn (dest, src));
+           emit_move_insn (dest, src);
          }
     }
 
@@ -3310,101 +3670,76 @@ hppa_expand_epilogue ()
      restores are finished.  */
   emit_insn (gen_blockage ());
 
-  /* Reset stack pointer (and possibly frame pointer).  The stack 
+  /* Reset stack pointer (and possibly frame pointer).  The stack
      pointer is initially set to fp + 64 to avoid a race condition.  */
   if (frame_pointer_needed)
     {
       rtx delta = GEN_INT (-64);
-      FRP (set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64));
-      FRP (emit_insn (gen_pre_load (frame_pointer_rtx, 
-                                   stack_pointer_rtx,
-                                   delta)));
+
+      set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64, 0);
+      emit_insn (gen_pre_load (frame_pointer_rtx, stack_pointer_rtx, delta));
     }
   /* If we were deferring a callee register restore, do it now.  */
   else if (merge_sp_adjust_with_load)
     {
       rtx delta = GEN_INT (-actual_fsize);
       rtx dest = gen_rtx_REG (word_mode, merge_sp_adjust_with_load);
-      FRP (emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta)));
+
+      emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
     }
   else if (actual_fsize != 0)
-    FRP (set_reg_plus_d (STACK_POINTER_REGNUM,
-                        STACK_POINTER_REGNUM,
-                        - actual_fsize));
+    set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                   - actual_fsize, 0);
 
   /* If we haven't restored %r2 yet (no frame pointer, and a stack
      frame greater than 8k), do so now.  */
   if (ret_off != 0)
-    FRP (load_reg (2, ret_off, STACK_POINTER_REGNUM));
-}
+    load_reg (2, ret_off, STACK_POINTER_REGNUM);
 
-/* Set up a callee saved register for the pic offset table register.  */
-void
-hppa_init_pic_save ()
-{
-  rtx insn, picreg;
+  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+    {
+      rtx sa = EH_RETURN_STACKADJ_RTX;
 
-  picreg = gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM);
-  PIC_OFFSET_TABLE_SAVE_RTX = gen_reg_rtx (Pmode);
-  insn = gen_rtx_SET (VOIDmode, PIC_OFFSET_TABLE_SAVE_RTX, picreg);
+      emit_insn (gen_blockage ());
+      emit_insn (TARGET_64BIT
+                ? gen_subdi3 (stack_pointer_rtx, stack_pointer_rtx, sa)
+                : gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, sa));
+    }
+}
 
-  /* Emit the insn at the beginning of the function after the prologue.  */
-  if (tail_recursion_reentry)
-    emit_insn_before (insn, tail_recursion_reentry);
-  else
-    /* We must have been called via PROFILE_HOOK.  */
-    emit_insn (insn);
+rtx
+hppa_pic_save_rtx ()
+{
+  return get_hard_reg_initial_val (word_mode, PIC_OFFSET_TABLE_REGNUM);
 }
 
 void
 hppa_profile_hook (label_no)
-     int label_no ATTRIBUTE_UNUSED;
+     int label_no;
 {
-  rtx call_insn;
+  rtx begin_label_rtx, call_insn;
+  char begin_label_name[16];
 
-  /* No profiling for inline functions.  We don't want extra calls to
-     _mcount when the inline function is expanded.  Even if that made
-     sense, it wouldn't work here as there is no function label for
-     the inline expansion.  */
-  if (DECL_INLINE (cfun->decl))
-    return;
+  ASM_GENERATE_INTERNAL_LABEL (begin_label_name, FUNC_BEGIN_PROLOG_LABEL,
+                              label_no);
+  begin_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (begin_label_name));
 
   if (TARGET_64BIT)
     emit_move_insn (arg_pointer_rtx,
                    gen_rtx_PLUS (word_mode, virtual_outgoing_args_rtx,
                                  GEN_INT (64)));
 
-  if (flag_pic && PIC_OFFSET_TABLE_SAVE_RTX == NULL_RTX)
-    hppa_init_pic_save ();
-
   emit_move_insn (gen_rtx_REG (word_mode, 26), gen_rtx_REG (word_mode, 2));
 
 #ifndef NO_PROFILE_COUNTERS
   {
     rtx count_label_rtx, addr, r24;
-    char label_name[16];
+    char count_label_name[16];
 
-    ASM_GENERATE_INTERNAL_LABEL (label_name, "LP", label_no);
-    count_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (label_name));
+    ASM_GENERATE_INTERNAL_LABEL (count_label_name, "LP", label_no);
+    count_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (count_label_name));
 
-    if (flag_pic)
-      {
-       rtx tmpreg;
-
-       current_function_uses_pic_offset_table = 1;
-       tmpreg = gen_rtx_REG (Pmode, 1);
-       emit_move_insn (tmpreg,
-                       gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
-                                     gen_rtx_HIGH (Pmode, count_label_rtx)));
-       addr = gen_rtx_MEM (Pmode,
-                           gen_rtx_LO_SUM (Pmode, tmpreg, count_label_rtx));
-      }
-    else
-      {
-       rtx tmpreg = gen_rtx_REG (Pmode, 1);
-       emit_move_insn (tmpreg, gen_rtx_HIGH (Pmode, count_label_rtx));
-       addr = gen_rtx_LO_SUM (Pmode, tmpreg, count_label_rtx);
-      }
+    addr = force_reg (Pmode, count_label_rtx);
     r24 = gen_rtx_REG (Pmode, 24);
     emit_move_insn (r24, addr);
 
@@ -3412,7 +3747,7 @@ hppa_profile_hook (label_no)
     call_insn =
       emit_call_insn (gen_call_profiler (gen_rtx_SYMBOL_REF (Pmode, "_mcount"),
                                         GEN_INT (TARGET_64BIT ? 24 : 12),
-                                        XEXP (DECL_RTL (cfun->decl), 0)));
+                                        begin_label_rtx));
 
     use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), r24);
   }
@@ -3421,7 +3756,7 @@ hppa_profile_hook (label_no)
   call_insn =
     emit_call_insn (gen_call_profiler (gen_rtx_SYMBOL_REF (Pmode, "_mcount"),
                                       GEN_INT (TARGET_64BIT ? 16 : 8),
-                                      XEXP (DECL_RTL (cfun->decl), 0)));
+                                      begin_label_rtx));
 #endif
 
   /* Indicate the _mcount call cannot throw, nor will it execute a
@@ -3435,7 +3770,7 @@ hppa_profile_hook (label_no)
       if (TARGET_64BIT)
        use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
 
-      emit_move_insn (pic_offset_table_rtx, PIC_OFFSET_TABLE_SAVE_RTX);
+      emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
     }
 }
 
@@ -3443,7 +3778,10 @@ hppa_profile_hook (label_no)
    the current frame, after the prologue.  FRAMEADDR is the
    frame pointer of the COUNT frame.
 
-   We want to ignore any export stub remnants here.
+   We want to ignore any export stub remnants here.  To handle this,
+   we examine the code at the return address, and if it is an export
+   stub, we return a memory rtx for the stub return address stored
+   at frame-24.
 
    The value returned is used in two different ways:
 
@@ -3458,42 +3796,36 @@ hppa_profile_hook (label_no)
 
    This function handles most instances of case 2; however, it will
    fail if we did not originally have stub code on the return path
-   but will need code on the new return path.  This can happen if
+   but will need stub code on the new return path.  This can happen if
    the caller & callee are both in the main program, but the new
-   return location is in a shared library.
-
-   To handle this correctly we need to set the return pointer at
-   frame-20 to point to a return stub frame-24 to point to the
-   location we wish to return to.  */
+   return location is in a shared library.  */
 
 rtx
 return_addr_rtx (count, frameaddr)
-     int count ATTRIBUTE_UNUSED;
+     int count;
      rtx frameaddr;
 {
   rtx label;
+  rtx rp;
   rtx saved_rp;
   rtx ins;
 
-  if (TARGET_64BIT)
-    return gen_rtx_MEM (Pmode, plus_constant (frameaddr, -16));
+  if (count != 0)
+    return NULL_RTX;
 
-  if (TARGET_NO_SPACE_REGS)
-    return gen_rtx_MEM (Pmode, plus_constant (frameaddr, -20));
+  rp = get_hard_reg_initial_val (Pmode, 2);
 
-  /* First, we start off with the normal return address pointer from
-     -20[frameaddr].  */
+  if (TARGET_64BIT || TARGET_NO_SPACE_REGS)
+    return rp;
 
   saved_rp = gen_reg_rtx (Pmode);
-  emit_move_insn (saved_rp, plus_constant (frameaddr, -20));
+  emit_move_insn (saved_rp, rp);
 
   /* Get pointer to the instruction stream.  We have to mask out the
      privilege level from the two low order bits of the return address
      pointer here so that ins will point to the start of the first
      instruction that would have been executed if we returned.  */
-  ins = copy_to_reg (gen_rtx_AND (Pmode,
-                                 copy_to_reg (gen_rtx_MEM (Pmode, saved_rp)),
-                                 MASK_RETURN_ADDR));
+  ins = copy_to_reg (gen_rtx_AND (Pmode, rp, MASK_RETURN_ADDR));
   label = gen_label_rtx ();
 
   /* Check the instruction stream at the normal return address for the
@@ -3507,39 +3839,39 @@ return_addr_rtx (count, frameaddr)
      If it is an export stub, than our return address is really in
      -24[frameaddr].  */
 
-  emit_cmp_insn (gen_rtx_MEM (SImode, ins),
-                GEN_INT (0x4bc23fd1),
-                NE, NULL_RTX, SImode, 1, 0);
+  emit_cmp_insn (gen_rtx_MEM (SImode, ins), GEN_INT (0x4bc23fd1), NE,
+                NULL_RTX, SImode, 1);
   emit_jump_insn (gen_bne (label));
 
   emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 4)),
-                GEN_INT (0x004010a1),
-                NE, NULL_RTX, SImode, 1, 0);
+                GEN_INT (0x004010a1), NE, NULL_RTX, SImode, 1);
   emit_jump_insn (gen_bne (label));
 
   emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 8)),
-                GEN_INT (0x00011820),
-                NE, NULL_RTX, SImode, 1, 0);
+                GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1);
   emit_jump_insn (gen_bne (label));
 
   emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)),
-                GEN_INT (0xe0400002),
-                NE, NULL_RTX, SImode, 1, 0);
+                GEN_INT (0xe0400002), NE, NULL_RTX, SImode, 1);
 
-  /* If there is no export stub then just use our initial guess of
-     -20[frameaddr].  */
+  /* If there is no export stub then just use the value saved from
+     the return pointer register.  */
 
   emit_jump_insn (gen_bne (label));
 
-  /* Here we know that our return address pointer points to an export
+  /* Here we know that our return address points to an export
      stub.  We don't want to return the address of the export stub,
-     but rather the return address that leads back into user code.
-     That return address is stored at -24[frameaddr].  */
+     but rather the return address of the export stub.  That return
+     address is stored at -24[frameaddr].  */
 
-  emit_move_insn (saved_rp, plus_constant (frameaddr, -24));
+  emit_move_insn (saved_rp,
+                 gen_rtx_MEM (Pmode,
+                              memory_address (Pmode,
+                                              plus_constant (frameaddr,
+                                                             -24))));
 
   emit_label (label);
-  return gen_rtx_MEM (Pmode, memory_address (Pmode, saved_rp));
+  return saved_rp;
 }
 
 /* This is only valid once reload has completed because it depends on
@@ -3586,7 +3918,7 @@ gen_cmp_fp (code, operand0, operand1)
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
 
-int
+static int
 pa_adjust_cost (insn, link, dep_insn, cost)
      rtx insn;
      rtx link;
@@ -3595,8 +3927,9 @@ pa_adjust_cost (insn, link, dep_insn, cost)
 {
   enum attr_type attr_type;
 
-  /* Don't adjust costs for a pa8000 chip.  */
-  if (pa_cpu >= PROCESSOR_8000)
+  /* Don't adjust costs for a pa8000 chip, also do not adjust any
+     true dependencies as they are described with bypasses now.  */
+  if (pa_cpu >= PROCESSOR_8000 || REG_NOTE_KIND (link) == 0)
     return cost;
 
   if (! recog_memoized (insn))
@@ -3604,60 +3937,7 @@ pa_adjust_cost (insn, link, dep_insn, cost)
 
   attr_type = get_attr_type (insn);
 
-  if (REG_NOTE_KIND (link) == 0)
-    {
-      /* Data dependency; DEP_INSN writes a register that INSN reads some
-        cycles later.  */
-
-      if (attr_type == TYPE_FPSTORE)
-       {
-         rtx pat = PATTERN (insn);
-         rtx dep_pat = PATTERN (dep_insn);
-         if (GET_CODE (pat) == PARALLEL)
-           {
-             /* This happens for the fstXs,mb patterns.  */
-             pat = XVECEXP (pat, 0, 0);
-           }
-         if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
-           /* If this happens, we have to extend this to schedule
-              optimally.  Return 0 for now.  */
-         return 0;
-
-         if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
-           {
-             if (! recog_memoized (dep_insn))
-               return 0;
-             /* DEP_INSN is writing its result to the register
-                being stored in the fpstore INSN.  */
-             switch (get_attr_type (dep_insn))
-               {
-               case TYPE_FPLOAD:
-                 /* This cost 3 cycles, not 2 as the md says for the
-                    700 and 7100.  */
-                 return cost + 1;
-
-               case TYPE_FPALU:
-               case TYPE_FPMULSGL:
-               case TYPE_FPMULDBL:
-               case TYPE_FPDIVSGL:
-               case TYPE_FPDIVDBL:
-               case TYPE_FPSQRTSGL:
-               case TYPE_FPSQRTDBL:
-                 /* In these important cases, we save one cycle compared to
-                    when flop instruction feed each other.  */
-                 return cost - 1;
-
-               default:
-                 return cost;
-               }
-           }
-       }
-
-      /* For other data dependencies, the default cost specified in the
-        md is correct.  */
-      return cost;
-    }
-  else if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
+  if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
     {
       /* Anti dependency; DEP_INSN reads a register that INSN writes some
         cycles later.  */
@@ -3693,7 +3973,7 @@ pa_adjust_cost (insn, link, dep_insn, cost)
                     preceding arithmetic operation has finished if
                     the target of the fpload is any of the sources
                     (or destination) of the arithmetic operation.  */
-                 return cost - 1;
+                 return insn_default_latency (dep_insn) - 1;
 
                default:
                  return 0;
@@ -3728,7 +4008,7 @@ pa_adjust_cost (insn, link, dep_insn, cost)
                     preceding divide or sqrt operation has finished if
                     the target of the ALU flop is any of the sources
                     (or destination) of the divide or sqrt operation.  */
-                 return cost - 2;
+                 return insn_default_latency (dep_insn) - 2;
 
                default:
                  return 0;
@@ -3773,8 +4053,12 @@ pa_adjust_cost (insn, link, dep_insn, cost)
                  /* A fpload can't be issued until one cycle before a
                     preceding arithmetic operation has finished if
                     the target of the fpload is the destination of the
-                    arithmetic operation.  */
-                 return cost - 1;
+                    arithmetic operation. 
+
+                    Exception: For PA7100LC, PA7200 and PA7300, the cost
+                    is 3 cycles, unless they bundle together.   We also
+                    pay the penalty if the second insn is a fpload.  */
+                 return insn_default_latency (dep_insn) - 1;
 
                default:
                  return 0;
@@ -3809,7 +4093,7 @@ pa_adjust_cost (insn, link, dep_insn, cost)
                     preceding divide or sqrt operation has finished if
                     the target of the ALU flop is also the target of
                     the divide or sqrt operation.  */
-                 return cost - 2;
+                 return insn_default_latency (dep_insn) - 2;
 
                default:
                  return 0;
@@ -3824,6 +4108,61 @@ pa_adjust_cost (insn, link, dep_insn, cost)
     abort ();
 }
 
+/* Adjust scheduling priorities.  We use this to try and keep addil
+   and the next use of %r1 close together.  */
+static int
+pa_adjust_priority (insn, priority)
+     rtx insn;
+     int priority;
+{
+  rtx set = single_set (insn);
+  rtx src, dest;
+  if (set)
+    {
+      src = SET_SRC (set);
+      dest = SET_DEST (set);
+      if (GET_CODE (src) == LO_SUM
+         && symbolic_operand (XEXP (src, 1), VOIDmode)
+         && ! read_only_operand (XEXP (src, 1), VOIDmode))
+       priority >>= 3;
+
+      else if (GET_CODE (src) == MEM
+              && GET_CODE (XEXP (src, 0)) == LO_SUM
+              && symbolic_operand (XEXP (XEXP (src, 0), 1), VOIDmode)
+              && ! read_only_operand (XEXP (XEXP (src, 0), 1), VOIDmode))
+       priority >>= 1;
+
+      else if (GET_CODE (dest) == MEM
+              && GET_CODE (XEXP (dest, 0)) == LO_SUM
+              && symbolic_operand (XEXP (XEXP (dest, 0), 1), VOIDmode)
+              && ! read_only_operand (XEXP (XEXP (dest, 0), 1), VOIDmode))
+       priority >>= 3;
+    }
+  return priority;
+}
+
+/* The 700 can only issue a single insn at a time.
+   The 7XXX processors can issue two insns at a time.
+   The 8000 can issue 4 insns at a time.  */
+static int
+pa_issue_rate ()
+{
+  switch (pa_cpu)
+    {
+    case PROCESSOR_700:                return 1;
+    case PROCESSOR_7100:       return 2;
+    case PROCESSOR_7100LC:     return 2;
+    case PROCESSOR_7200:       return 2;
+    case PROCESSOR_7300:       return 2;
+    case PROCESSOR_8000:       return 4;
+
+    default:
+      abort ();
+    }
+}
+
+
+
 /* Return any length adjustment needed by INSN which already has its length
    computed as LENGTH.   Return zero if no adjustment is necessary.
 
@@ -3854,7 +4193,7 @@ pa_adjust_insn_length (insn, length)
       else
        return 0;
     }
-  /* Jumps inside switch tables which have unfilled delay slots 
+  /* Jumps inside switch tables which have unfilled delay slots
      also need adjustment.  */
   else if (GET_CODE (insn) == JUMP_INSN
           && simplejump_p (insn)
@@ -3890,7 +4229,7 @@ pa_adjust_insn_length (insn, length)
        return 4;
       /* Adjust dbra insn with short backwards conditional branch with
         unfilled delay slot -- only for case where counter is in a
-        general register register. */
+        general register register.  */
       else if (GET_CODE (pat) == PARALLEL
               && GET_CODE (XVECEXP (pat, 0, 1)) == SET
               && GET_CODE (XEXP (XVECEXP (pat, 0, 1), 0)) == REG
@@ -3932,10 +4271,10 @@ print_operand (file, x, code)
     case 'R':
       /* Print out the second register name of a register pair.
         I.e., R (6) => 7.  */
-      fputs (reg_names[REGNO (x)+1], file);
+      fputs (reg_names[REGNO (x) + 1], file);
       return;
     case 'r':
-      /* A register or zero. */
+      /* A register or zero.  */
       if (x == const0_rtx
          || (x == CONST0_RTX (DFmode))
          || (x == CONST0_RTX (SFmode)))
@@ -3946,7 +4285,7 @@ print_operand (file, x, code)
       else
        break;
     case 'f':
-      /* A register or zero (floating point). */
+      /* A register or zero (floating point).  */
       if (x == const0_rtx
          || (x == CONST0_RTX (DFmode))
          || (x == CONST0_RTX (SFmode)))
@@ -4022,8 +4361,8 @@ print_operand (file, x, code)
          abort ();
        }
       return;
-    /* For floating point comparisons. Note that the output predicates are the
-       complement of the desired mode. */
+    /* For floating point comparisons.  Note that the output
+       predicates are the complement of the desired mode.  */
     case 'Y':
       switch (GET_CODE (x))
        {
@@ -4116,45 +4455,45 @@ print_operand (file, x, code)
     case 'k':
       if (GET_CODE (x) == CONST_INT)
        {
-         fprintf (file, "%d", ~INTVAL (x));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~INTVAL (x));
          return;
        }
-      abort();
+      abort ();
     case 'Q':
       if (GET_CODE (x) == CONST_INT)
        {
-         fprintf (file, "%d", 64 - (INTVAL (x) & 63));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - (INTVAL (x) & 63));
          return;
        }
-      abort();
+      abort ();
     case 'L':
       if (GET_CODE (x) == CONST_INT)
        {
-         fprintf (file, "%d", 32 - (INTVAL (x) & 31));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - (INTVAL (x) & 31));
          return;
        }
-      abort();
+      abort ();
     case 'O':
       if (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0)
        {
          fprintf (file, "%d", exact_log2 (INTVAL (x)));
          return;
        }
-      abort();
+      abort ();
     case 'p':
       if (GET_CODE (x) == CONST_INT)
        {
-         fprintf (file, "%d", 63 - (INTVAL (x) & 63));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 63 - (INTVAL (x) & 63));
          return;
        }
-      abort();
+      abort ();
     case 'P':
       if (GET_CODE (x) == CONST_INT)
        {
-         fprintf (file, "%d", 31 - (INTVAL (x) & 31));
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 31 - (INTVAL (x) & 31));
          return;
        }
-      abort();
+      abort ();
     case 'I':
       if (GET_CODE (x) == CONST_INT)
        fputs ("i", file);
@@ -4274,7 +4613,7 @@ print_operand (file, x, code)
     output_addr_const (file, x);
 }
 
-/* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF. */
+/* output a SYMBOL_REF or a CONST expression involving a SYMBOL_REF.  */
 
 void
 output_global_address (file, x, round_constant)
@@ -4315,7 +4654,7 @@ output_global_address (file, x, round_constant)
          output_addr_const (file, base);
        }
       else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
-       offset = INTVAL (XEXP (XEXP (x, 0),1));
+       offset = INTVAL (XEXP (XEXP (x, 0), 1));
       else abort ();
 
       /* How bogus.  The compiler is apparently responsible for
@@ -4348,7 +4687,7 @@ output_global_address (file, x, round_constant)
       if (!read_only_operand (base, VOIDmode) && !flag_pic)
        fputs ("-$global$", file);
       if (offset)
-       fprintf (file,"%s%d", sep, offset);
+       fprintf (file, "%s%d", sep, offset);
     }
   else
     output_addr_const (file, x);
@@ -4372,8 +4711,8 @@ output_deferred_plabels (file)
   for (i = 0; i < n_deferred_plabels; i++)
     {
       ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (deferred_plabels[i].internal_label));
-      assemble_integer (gen_rtx_SYMBOL_REF (VOIDmode,
-                                           deferred_plabels[i].name), 4, 1);
+      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, deferred_plabels[i].name),
+                       TARGET_64BIT ? 8 : 4, TARGET_64BIT ? 64 : 32, 1);
     }
 }
 
@@ -4382,9 +4721,9 @@ output_deferred_plabels (file)
 
 enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 };
 static void import_milli                       PARAMS ((enum millicodes));
-static char imported[(int)end1000];
+static char imported[(int) end1000];
 static const char * const milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
-static char import_string[] = ".IMPORT $$....,MILLICODE";
+static const char import_string[] = ".IMPORT $$....,MILLICODE";
 #define MILLI_START 10
 
 static void
@@ -4393,17 +4732,17 @@ import_milli (code)
 {
   char str[sizeof (import_string)];
 
-  if (!imported[(int)code])
+  if (!imported[(int) code])
     {
-      imported[(int)code] = 1;
+      imported[(int) code] = 1;
       strcpy (str, import_string);
-      strncpy (str + MILLI_START, milli_names[(int)code], 4);
+      strncpy (str + MILLI_START, milli_names[(int) code], 4);
       output_asm_insn (str, 0);
     }
 }
 
 /* The register constraints have put the operands and return value in
-   the proper registers. */
+   the proper registers.  */
 
 const char *
 output_mul_insn (unsignedp, insn)
@@ -4414,15 +4753,15 @@ output_mul_insn (unsignedp, insn)
   return output_millicode_call (insn, gen_rtx_SYMBOL_REF (Pmode, "$$mulI"));
 }
 
-/* Emit the rtl for doing a division by a constant. */
+/* Emit the rtl for doing a division by a constant.  */
 
 /* Do magic division millicodes exist for this value? */
-static int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
-                            1, 1};
+static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
+                                1, 1};
 
 /* We'll use an array to keep track of the magic millicodes and
    whether or not we've used them already. [n][0] is signed, [n][1] is
-   unsigned. */
+   unsigned.  */
 
 static int div_milli[16][2];
 
@@ -4447,6 +4786,8 @@ emit_hpdiv_const (operands, unsignedp)
       && INTVAL (operands[2]) < 16
       && magic_milli[INTVAL (operands[2])])
     {
+      rtx ret = gen_rtx_REG (SImode, TARGET_64BIT ? 2 : 31);
+
       emit_move_insn (gen_rtx_REG (SImode, 26), operands[1]);
       emit
        (gen_rtx
@@ -4460,7 +4801,7 @@ emit_hpdiv_const (operands, unsignedp)
                     gen_rtx_CLOBBER (VOIDmode, operands[3]),
                     gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 26)),
                     gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 25)),
-                    gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, 31)))));
+                    gen_rtx_CLOBBER (VOIDmode, ret))));
       emit_move_insn (operands[0], gen_rtx_REG (SImode, 29));
       return 1;
     }
@@ -4491,18 +4832,20 @@ output_div_insn (operands, unsignedp, insn)
        }
       if (unsignedp)
        {
-         sprintf (buf, "$$divU_%d", INTVAL (operands[0]));
+         sprintf (buf, "$$divU_");
+         sprintf (buf + 7, HOST_WIDE_INT_PRINT_DEC, INTVAL (operands[0]));
          return output_millicode_call (insn,
                                        gen_rtx_SYMBOL_REF (SImode, buf));
        }
       else
        {
-         sprintf (buf, "$$divI_%d", INTVAL (operands[0]));
+         sprintf (buf, "$$divI_");
+         sprintf (buf + 7, HOST_WIDE_INT_PRINT_DEC, INTVAL (operands[0]));
          return output_millicode_call (insn,
                                        gen_rtx_SYMBOL_REF (SImode, buf));
        }
     }
-  /* Divisor isn't a special constant. */
+  /* Divisor isn't a special constant.  */
   else
     {
       if (unsignedp)
@@ -4520,7 +4863,7 @@ output_div_insn (operands, unsignedp, insn)
     }
 }
 
-/* Output a $$rem millicode to do mod. */
+/* Output a $$rem millicode to do mod.  */
 
 const char *
 output_mod_insn (unsignedp, insn)
@@ -4671,6 +5014,13 @@ secondary_reload_class (class, mode, in)
       || (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
     return GENERAL_REGS;
 
+  /* A SAR<->FP register copy requires a secondary register (GPR) as
+     well as secondary memory.  */
+  if (regno >= 0 && regno < FIRST_PSEUDO_REGISTER
+      && ((REGNO_REG_CLASS (regno) == SHIFT_REGS && FP_REG_CLASS_P (class))
+         || (class == SHIFT_REGS && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
+    return GENERAL_REGS;
+
   if (GET_CODE (in) == HIGH)
     in = XEXP (in, 0);
 
@@ -4698,7 +5048,7 @@ secondary_reload_class (class, mode, in)
         is_symbolic = 0;
         break;
     }
-  
+
   if (!flag_pic
       && is_symbolic
       && read_only_operand (in, VOIDmode))
@@ -4723,7 +5073,7 @@ function_arg_padding (mode, type)
        size = int_size_in_bytes (type) * BITS_PER_UNIT;
       else
        return upward;          /* Don't know if this is right, but */
-                               /* same as old definition. */
+                               /* same as old definition.  */
     }
   else
     size = GET_MODE_BITSIZE (mode);
@@ -4758,7 +5108,7 @@ hppa_builtin_saveregs ()
   if (TARGET_64BIT)
     {
       int i, off;
-      
+
       /* Adjust for varargs/stdarg differences.  */
       if (argadj)
        offset = plus_constant (current_function_arg_offset_rtx, -argadj);
@@ -4773,7 +5123,7 @@ hppa_builtin_saveregs ()
                        gen_rtx_REG (word_mode, i));
 
       /* The incoming args pointer points just beyond the flushback area;
-        normally this is not a serious concern.  Howver, when we are doing
+        normally this is not a serious concern.  However, when we are doing
         varargs/stdargs we want to make the arg pointer point to the start
         of the incoming argument area.  */
       emit_move_insn (virtual_incoming_args_rtx,
@@ -4785,11 +5135,12 @@ hppa_builtin_saveregs ()
                                        offset, 0, 0, OPTAB_LIB_WIDEN));
     }
 
-  /* Store general registers on the stack. */
+  /* Store general registers on the stack.  */
   dest = gen_rtx_MEM (BLKmode,
                      plus_constant (current_function_internal_arg_pointer,
                                     -16));
-  MEM_ALIAS_SET (dest) = get_varargs_alias_set ();
+  set_mem_alias_set (dest, get_varargs_alias_set ());
+  set_mem_align (dest, BITS_PER_WORD);
   move_block_from_reg (23, dest, 4, 4 * UNITS_PER_WORD);
 
   /* move_block_from_reg will emit code to store the argument registers
@@ -4803,13 +5154,6 @@ hppa_builtin_saveregs ()
      last argument register store.  So we emit a blockage insn here.  */
   emit_insn (gen_blockage ());
 
-  if (current_function_check_memory_usage)
-    emit_library_call (chkr_set_right_libfunc, 1, VOIDmode, 3,
-                      dest, ptr_mode,
-                      GEN_INT (4 * UNITS_PER_WORD), TYPE_MODE (sizetype),
-                      GEN_INT (MEMORY_USE_RW),
-                      TYPE_MODE (integer_type_node));
-
   return copy_to_reg (expand_binop (Pmode, add_optab,
                                    current_function_internal_arg_pointer,
                                    offset, 0, 0, OPTAB_LIB_WIDEN));
@@ -4835,14 +5179,14 @@ hppa_va_arg (valist, type)
   if (TARGET_64BIT)
     {
       /* Every argument in PA64 is passed by value (including large structs).
-         Arguments with size greater than 8 must be aligned 0 MOD 16. */
+         Arguments with size greater than 8 must be aligned 0 MOD 16.  */
 
       size = int_size_in_bytes (type);
       if (size > UNITS_PER_WORD)
         {
           t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
                      build_int_2 (2 * UNITS_PER_WORD - 1, 0));
-          t = build (BIT_AND_EXPR, TREE_TYPE (t), t, 
+          t = build (BIT_AND_EXPR, TREE_TYPE (t), t,
                      build_int_2 (-2 * UNITS_PER_WORD, -1));
           t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
           TREE_SIDE_EFFECTS (t) = 1;
@@ -4860,7 +5204,7 @@ hppa_va_arg (valist, type)
   /* "Large" types are passed by reference.  */
   if (size > 8)
     {
-      t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist, 
+      t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
                 build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
       TREE_SIDE_EFFECTS (t) = 1;
 
@@ -4883,7 +5227,7 @@ hppa_va_arg (valist, type)
 
       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
       TREE_SIDE_EFFECTS (t) = 1;
-      
+
       ofs = (8 - size) % 4;
       if (ofs)
        {
@@ -5086,22 +5430,32 @@ output_cbranch (operands, nullify, length, negated, insn)
          xoperands[1] = operands[1];
          xoperands[2] = operands[2];
          xoperands[3] = operands[3];
-         xoperands[4] = gen_label_rtx ();
-
-         output_asm_insn ("{bl|b,l} .+8,%%r1\n\taddil L'%l0-%l4,%%r1",
-                          xoperands);
-         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
-                                    CODE_LABEL_NUMBER (xoperands[4]));
-         output_asm_insn ("ldo R'%l0-%l4(%%r1),%%r1\n\tbv %%r0(%%r1)",
-                          xoperands);
+         if (TARGET_SOM || ! TARGET_GAS)
+           xoperands[4] = gen_label_rtx ();
+
+         output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
+         if (TARGET_SOM || ! TARGET_GAS)
+           {
+             output_asm_insn ("addil L'%l0-%l4,%%r1", xoperands);
+             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                        CODE_LABEL_NUMBER (xoperands[4]));
+             output_asm_insn ("ldo R'%l0-%l4(%%r1),%%r1", xoperands);
+           }
+         else
+           {
+             output_asm_insn ("addil L'%l0-$PIC_pcrel$0+4,%%r1", xoperands);
+             output_asm_insn ("ldo R'%l0-$PIC_pcrel$0+8(%%r1),%%r1",
+                              xoperands);
+           }
+         output_asm_insn ("bv %%r0(%%r1)", xoperands);
        }
 
        /* Now restore the value of %r1 in the delay slot.  We're not
           optimizing so we know nothing else can be in the delay slot.  */
        return "ldw -16(%%r30),%%r1";
-       
+
       default:
-       abort();
+       abort ();
     }
   return buf;
 }
@@ -5248,7 +5602,7 @@ output_bb (operands, nullify, length, negated, insn, which)
        break;
 
       default:
-       abort();
+       abort ();
     }
   return buf;
 }
@@ -5396,7 +5750,7 @@ output_bvb (operands, nullify, length, negated, insn, which)
        break;
 
       default:
-       abort();
+       abort ();
     }
   return buf;
 }
@@ -5421,8 +5775,8 @@ output_dbra (operands, insn, which_alternative)
        return "ldo %1(%0),%0";
       else if (which_alternative == 1)
        {
-         output_asm_insn ("{fstws|fstw} %0,-16(%%r30)",operands);
-         output_asm_insn ("ldw -16(%%r30),%4",operands);
+         output_asm_insn ("{fstws|fstw} %0,-16(%%r30)", operands);
+         output_asm_insn ("ldw -16(%%r30),%4", operands);
          output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(%%r30)", operands);
          return "{fldws|fldw} -16(%%r30),%0";
        }
@@ -5478,7 +5832,7 @@ output_dbra (operands, insn, which_alternative)
            return "addi,%N2 %1,%0,%0\n\tb %3";
        }
       else
-       abort();
+       abort ();
     }
   /* Deal with gross reload from FP register case.  */
   else if (which_alternative == 1)
@@ -5486,7 +5840,8 @@ output_dbra (operands, insn, which_alternative)
       /* Move loop counter from FP register to MEM then into a GR,
         increment the GR, store the GR into MEM, and finally reload
         the FP register from MEM from within the branch's delay slot.  */
-      output_asm_insn ("{fstws|fstw} %0,-16(%%r30)\n\tldw -16(%%r30),%4",operands);
+      output_asm_insn ("{fstws|fstw} %0,-16(%%r30)\n\tldw -16(%%r30),%4",
+                      operands);
       output_asm_insn ("ldo %1(%4),%4\n\tstw %4,-16(%%r30)", operands);
       if (get_attr_length (insn) == 24)
        return "{comb|cmpb},%S2 %%r0,%4,%3\n\t{fldws|fldw} -16(%%r30),%0";
@@ -5527,7 +5882,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
        return "copy %1,%0";
       else if (which_alternative == 1)
        {
-         output_asm_insn ("stw %1,-16(%%r30)",operands);
+         output_asm_insn ("stw %1,-16(%%r30)", operands);
          return "{fldws|fldw} -16(%%r30),%0";
        }
       else if (which_alternative == 2)
@@ -5585,7 +5940,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
            return "or,%N2 %1,%%r0,%0\n\tb %3";
        }
       else
-       abort();
+       abort ();
     }
   /* Deal with gross reload from FP register case.  */
   else if (which_alternative == 1)
@@ -5593,7 +5948,7 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
       /* Move loop counter from FP register to MEM then into a GR,
         increment the GR, store the GR into MEM, and finally reload
         the FP register from MEM from within the branch's delay slot.  */
-      output_asm_insn ("stw %1,-16(%%r30)",operands);
+      output_asm_insn ("stw %1,-16(%%r30)", operands);
       if (get_attr_length (insn) == 12)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\t{fldws|fldw} -16(%%r30),%0";
       else
@@ -5630,6 +5985,8 @@ output_millicode_call (insn, call_dest)
   rtx insn;
   rtx call_dest;
 {
+  int attr_length = get_attr_length (insn);
+  int seq_length = dbr_sequence_length ();
   int distance;
   rtx xoperands[4];
   rtx seq_insn;
@@ -5638,12 +5995,15 @@ output_millicode_call (insn, call_dest)
 
   /* Handle common case -- empty delay slot or no jump in the delay slot,
      and we're sure that the branch will reach the beginning of the $CODE$
-     subspace.  */
-  if ((dbr_sequence_length () == 0
-       && (get_attr_length (insn) == 8 || get_attr_length (insn) == 28))
-      || (dbr_sequence_length () != 0
+     subspace.  The within reach form of the $$sh_func_adrs call has
+     a length of 28 and attribute type of multi.  This length is the
+     same as the maximum length of an out of reach PIC call to $$div.  */
+  if ((seq_length == 0
+       && (attr_length == 8
+          || (attr_length == 28 && get_attr_type (insn) == TYPE_MULTI)))
+      || (seq_length != 0
          && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
-         && get_attr_length (insn) == 4))
+         && attr_length == 4))
     {
       xoperands[0] = call_dest;
       output_asm_insn ("{bl|b,l} %0,%3%#", xoperands);
@@ -5651,12 +6011,12 @@ output_millicode_call (insn, call_dest)
     }
 
   /* This call may not reach the beginning of the $CODE$ subspace.  */
-  if (get_attr_length (insn) > 4)
+  if (attr_length > 8)
     {
       int delay_insn_deleted = 0;
 
       /* We need to emit an inline long-call branch.  */
-      if (dbr_sequence_length () != 0
+      if (seq_length != 0
          && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
        {
          /* A non-jump insn in the delay slot.  By definition we can
@@ -5674,15 +6034,26 @@ output_millicode_call (insn, call_dest)
       if (flag_pic)
        {
          xoperands[0] = call_dest;
-         xoperands[1] = gen_label_rtx ();
+         if (TARGET_SOM || ! TARGET_GAS)
+           xoperands[1] = gen_label_rtx ();
+
          /* Get our address + 8 into %r1.  */
          output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
 
-         /* Add %r1 to the offset of our target from the next insn.  */
-         output_asm_insn ("addil L%%%0-%1,%%r1", xoperands);
-         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
-                                    CODE_LABEL_NUMBER (xoperands[1]));
-         output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
+         if (TARGET_SOM || ! TARGET_GAS)
+           {
+             /* Add %r1 to the offset of our target from the next insn.  */
+             output_asm_insn ("addil L%%%0-%1,%%r1", xoperands);
+             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                        CODE_LABEL_NUMBER (xoperands[1]));
+             output_asm_insn ("ldo R%%%0-%1(%%r1),%%r1", xoperands);
+           }
+         else
+           {
+             output_asm_insn ("addil L%%%0-$PIC_pcrel$0+4,%%r1", xoperands);
+             output_asm_insn ("ldo R%%%0-$PIC_pcrel$0+8(%%r1),%%r1",
+                              xoperands);
+           }
 
          /* Get the return address into %r31.  */
          output_asm_insn ("blr 0,%3", xoperands);
@@ -5699,7 +6070,7 @@ output_millicode_call (insn, call_dest)
       else if (TARGET_PORTABLE_RUNTIME)
        {
          xoperands[0] = call_dest;
-         /* Get the address of our target into %r29. */
+         /* Get the address of our target into %r29.  */
          output_asm_insn ("ldil L%%%0,%%r29", xoperands);
          output_asm_insn ("ldo R%%%0(%%r29),%%r29", xoperands);
 
@@ -5724,8 +6095,7 @@ output_millicode_call (insn, call_dest)
        }
 
       /* If we had a jump in the call's delay slot, output it now.  */
-      if (dbr_sequence_length () != 0
-         && !delay_insn_deleted)
+      if (seq_length != 0 && !delay_insn_deleted)
        {
          xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
          output_asm_insn ("b,n %0", xoperands);
@@ -5787,6 +6157,8 @@ output_call (insn, call_dest, sibcall)
   rtx call_dest;
   int sibcall;
 {
+  int attr_length = get_attr_length (insn);
+  int seq_length = dbr_sequence_length ();
   int distance;
   rtx xoperands[4];
   rtx seq_insn;
@@ -5794,11 +6166,10 @@ output_call (insn, call_dest, sibcall)
   /* Handle common case -- empty delay slot or no jump in the delay slot,
      and we're sure that the branch will reach the beginning of the $CODE$
      subspace.  */
-  if ((dbr_sequence_length () == 0
-       && get_attr_length (insn) == 8)
-      || (dbr_sequence_length () != 0
+  if ((seq_length == 0 && attr_length == 12)
+      || (seq_length != 0
          && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN
-         && get_attr_length (insn) == 4))
+         && attr_length == 8))
     {
       xoperands[0] = call_dest;
       xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
@@ -5807,7 +6178,7 @@ output_call (insn, call_dest, sibcall)
     }
 
   /* This call may not reach the beginning of the $CODE$ subspace.  */
-  if (get_attr_length (insn) > 8)
+  if (attr_length > 12)
     {
       int delay_insn_deleted = 0;
       rtx xoperands[2];
@@ -5820,7 +6191,7 @@ output_call (insn, call_dest, sibcall)
         and FP registers.  Also, we need move any delay slot insn
         out of the delay slot.  And finally, we can't rely on the linker
         being able to fix the call to $$dyncall!  -- Yuk!.  */
-      if (dbr_sequence_length () != 0
+      if (seq_length != 0
          && GET_CODE (NEXT_INSN (insn)) != JUMP_INSN)
        {
          /* A non-jump insn in the delay slot.  By definition we can
@@ -5920,7 +6291,8 @@ output_call (insn, call_dest, sibcall)
          if (flag_pic)
            {
              xoperands[0] = deferred_plabels[i].internal_label;
-             xoperands[1] = gen_label_rtx ();
+             if (TARGET_SOM || ! TARGET_GAS)
+               xoperands[1] = gen_label_rtx ();
 
              output_asm_insn ("addil LT%%%0,%%r19", xoperands);
              output_asm_insn ("ldw RT%%%0(%%r1),%%r22", xoperands);
@@ -5929,11 +6301,21 @@ output_call (insn, call_dest, sibcall)
              /* Get our address + 8 into %r1.  */
              output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
 
-             /* Add %r1 to the offset of dyncall from the next insn.  */
-             output_asm_insn ("addil L%%$$dyncall-%1,%%r1", xoperands);
-             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
-                                        CODE_LABEL_NUMBER (xoperands[1]));
-             output_asm_insn ("ldo R%%$$dyncall-%1(%%r1),%%r1", xoperands);
+             if (TARGET_SOM || ! TARGET_GAS)
+               {
+                 /* Add %r1 to the offset of dyncall from the next insn.  */
+                 output_asm_insn ("addil L%%$$dyncall-%1,%%r1", xoperands);
+                 ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                            CODE_LABEL_NUMBER (xoperands[1]));
+                 output_asm_insn ("ldo R%%$$dyncall-%1(%%r1),%%r1", xoperands);
+               }
+             else
+               {
+                 output_asm_insn ("addil L%%$$dyncall-$PIC_pcrel$0+4,%%r1",
+                                  xoperands);
+                 output_asm_insn ("ldo R%%$$dyncall-$PIC_pcrel$0+8(%%r1),%%r1",
+                                  xoperands);
+               }
 
              /* Get the return address into %r31.  */
              output_asm_insn ("blr %%r0,%%r31", xoperands);
@@ -5982,8 +6364,7 @@ output_call (insn, call_dest, sibcall)
        }
 
       /* If we had a jump in the call's delay slot, output it now.  */
-      if (dbr_sequence_length () != 0
-         && !delay_insn_deleted)
+      if (seq_length != 0 && !delay_insn_deleted)
        {
          xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
          output_asm_insn ("b,n %0", xoperands);
@@ -6006,11 +6387,9 @@ output_call (insn, call_dest, sibcall)
   distance = INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
               - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
 
-  /* If the branch was too far away, emit a normal call followed
-     by a nop, followed by the unconditional branch.
-
-     If the branch is close, then adjust %r2 from within the
-     call's delay slot.  */
+  /* If the branch is too far away, emit a normal call followed
+     by a nop, followed by the unconditional branch.  If the branch
+     is close, then adjust %r2 in the call's delay slot.  */
 
   xoperands[0] = call_dest;
   xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
@@ -6054,7 +6433,7 @@ hppa_encode_label (sym)
   *p++ = '@';
   strcpy (p, str);
 
-  XSTR (sym,0) = ggc_alloc_string (newstr, len);
+  XSTR (sym, 0) = ggc_alloc_string (newstr, len);
 }
 
 int
@@ -6269,7 +6648,7 @@ non_hard_reg_operand (op, mode)
 }
 
 /* Return 1 if INSN branches forward.  Should be using insn_addresses
-   to avoid walking through all the insns... */
+   to avoid walking through all the insns...  */
 static int
 forward_branch_p (insn)
      rtx insn;
@@ -6390,22 +6769,20 @@ output_parallel_addb (operands, length)
     }
 }
 
-/* Return nonzero if INSN (a jump insn) immediately follows a call to
-   a named function.  This is used to discourage creating parallel movb/addb
-   insns since a jump which immediately follows a call can execute in the
-   delay slot of the call.
+/* Return nonzero if INSN (a jump insn) immediately follows a call
+   to a named function.  This is used to avoid filling the delay slot
+   of the jump since it can usually be eliminated by modifying RP in
+   the delay slot of the call.  */
 
-   It is also used to avoid filling the delay slot of a jump which
-   immediately follows a call since the jump can usually be eliminated
-   completely by modifying RP in the delay slot of the call.  */
-   
 int
 following_call (insn)
      rtx insn;
 {
-  /* We do not parallel movb,addb or place jumps into call delay slots when
-     optimizing for the PA8000.  */
-  if (pa_cpu != PROCESSOR_8000)
+  /* We do not place jumps into call delay slots when optimizing for the
+     PA8000 processor or when generating dwarf2 call frame information.  */
+  if (pa_cpu >= PROCESSOR_8000
+      || (! USING_SJLJ_EXCEPTIONS && flag_exceptions)
+      || flag_unwind_tables)
     return 0;
 
   /* Find the previous real insn, skipping NOTEs.  */
@@ -6448,10 +6825,10 @@ following_call (insn)
    Reorg and the final jump pass can then optimize these branches and
    fill their delay slots.  We end up with smaller, more efficient code.
 
-   The jump instructions within the table are special; we must be able 
+   The jump instructions within the table are special; we must be able
    to identify them during assembly output (if the jumps don't get filled
    we need to emit a nop rather than nullifying the delay slot)).  We
-   identify jumps in switch tables by marking the SET with DImode. 
+   identify jumps in switch tables by marking the SET with DImode.
 
    We also surround the jump table itself with BEGIN_BRTAB and END_BRTAB
    insns.  This serves two purposes, first it prevents jump.c from
@@ -6747,7 +7124,7 @@ pa_combine_instructions (insns)
                      || (GET_CODE (floater) == INSN
                          && (GET_CODE (PATTERN (floater)) == USE
                              || GET_CODE (PATTERN (floater)) == CLOBBER)))
-                       
+
                    continue;
 
                  /* Anything except a regular INSN will stop our search.  */
@@ -6771,8 +7148,10 @@ pa_combine_instructions (insns)
                         done with this pass.  */
                      if (pa_can_combine_p (new, anchor, floater, 1,
                                            SET_DEST (PATTERN (floater)),
-                                           XEXP (SET_SRC (PATTERN(floater)),0),
-                                           XEXP(SET_SRC(PATTERN(floater)),1)))
+                                           XEXP (SET_SRC (PATTERN (floater)),
+                                                 0),
+                                           XEXP (SET_SRC (PATTERN (floater)),
+                                                 1)))
                        break;
                    }
                }
@@ -6850,7 +7229,7 @@ pa_can_combine_p (new, anchor, floater, reversed, dest, src1, src2)
   INSN_CODE (new) = -1;
   insn_code_number = recog_memoized (new);
   if (insn_code_number < 0
-      || !constrain_operands (1))
+      || (extract_insn (new), ! constrain_operands (1)))
     return 0;
 
   if (reversed)
@@ -6891,12 +7270,18 @@ pa_can_combine_p (new, anchor, floater, reversed, dest, src1, src2)
 
    Millicode calls always expect their arguments in the integer argument
    registers, and always return their result in %r29 (ret1).  They
-   are expected to clobber their arguments, %r1, %r29, and %r31 and
-   nothing else.
+   are expected to clobber their arguments, %r1, %r29, and the return
+   pointer which is %r31 on 32-bit and %r2 on 64-bit, and nothing else.
 
-   By considering this effects delayed reorg reorg can put insns
-   which set the argument registers into the delay slot of the millicode
-   call -- thus they act more like traditional CALL_INSNs.
+   This function tells reorg that the references to arguments and
+   millicode calls do not appear to happen until after the millicode call.
+   This allows reorg to put insns which set the argument registers into the
+   delay slot of the millicode call -- thus they act more like traditional
+   CALL_INSNs.
+
+   Note we can not consider side effects of the insn to be delayed because
+   the branch and link insn will clobber the return pointer.  If we happened
+   to use the return pointer in the delay slot of the call, then we lose.
 
    get_attr_type will try to recognize the given insn, so make sure to
    filter out things it will not accept -- SEQUENCE, USE and CLOBBER insns
@@ -6905,7 +7290,7 @@ int
 insn_refs_are_delayed (insn)
      rtx insn;
 {
-  return ((GET_CODE (insn) == INSN 
+  return ((GET_CODE (insn) == INSN
           && GET_CODE (PATTERN (insn)) != SEQUENCE
           && GET_CODE (PATTERN (insn)) != USE
           && GET_CODE (PATTERN (insn)) != CLOBBER
@@ -6916,7 +7301,7 @@ insn_refs_are_delayed (insn)
    if the parameter has any component that is passed in memory.
 
    This is new code and will be pushed to into the net sources after
-   further testing. 
+   further testing.
 
    ??? We might want to restructure this so that it looks more like other
    ports.  */
@@ -6957,7 +7342,7 @@ function_arg (cum, mode, type, named, incoming)
      particularly in their handling of FP registers.  We might
      be able to cleverly share code between them, but I'm not
      going to bother in the hope that splitting them up results
-     in code that is more easily understood. 
+     in code that is more easily understood.
 
      The 64bit code probably is very wrong for structure passing.  */
   if (TARGET_64BIT)
@@ -6970,7 +7355,7 @@ function_arg (cum, mode, type, named, incoming)
         varies based on the size of the target word.  */
       gpr_reg_base = 26 - cum->words;
       fpr_reg_base = 32 + cum->words;
-         
+
       /* If the argument is more than a word long, then we need to align
         the base registers.  Same caveats as above.  */
       if (FUNCTION_ARG_SIZE (mode, type) > 1)
@@ -6994,16 +7379,16 @@ function_arg (cum, mode, type, named, incoming)
            {
              rtx loc[8];
              int i, offset = 0, ub;
-              ub = FUNCTION_ARG_SIZE (mode, type); 
-             ub = MIN(ub,
-                       MAX(0, max_arg_words - cum->words - (cum->words & 1)));
+              ub = FUNCTION_ARG_SIZE (mode, type);
+             ub = MIN (ub,
+                       MAX (0, max_arg_words - cum->words - (cum->words & 1)));
              gpr_reg_base -= (cum->words & 1);
              for (i = 0; i < ub; i++)
                {
                  loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
                                              gen_rtx_REG (DImode,
                                                           gpr_reg_base),
-                                             GEN_INT(offset));
+                                             GEN_INT (offset));
                  gpr_reg_base -= 1;
                  offset += 8;
                }
@@ -7012,7 +7397,7 @@ function_arg (cum, mode, type, named, incoming)
              else if (ub == 1)
                return XEXP (loc[0], 0);
              else
-               return gen_rtx_PARALLEL(mode, gen_rtvec_v(ub, loc));
+               return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
            }
        }
     }
@@ -7055,22 +7440,30 @@ function_arg (cum, mode, type, named, incoming)
                                         gen_rtx_REG (DImode, gpr_reg_base),
                                         GEN_INT (8))));
     }
-  /* Determine if the register needs to be passed in both general and
+  /* Determine if the argument needs to be passed in both general and
      floating point registers.  */
-  if ((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
-      /* If we are doing soft-float with portable runtime, then there
-        is no need to worry about FP regs.  */
-      && ! TARGET_SOFT_FLOAT
-      /* The parameter must be some kind of float, else we can just
-        pass it in integer registers.  */
-      && FLOAT_MODE_P (mode)
-      /* The target function must not have a prototype.  */
-      && cum->nargs_prototype <= 0
-      /* libcalls do not need to pass items in both FP and general
-        registers.  */
-      && type != NULL_TREE
-      /* All this hair applies to outgoing args only.  */
-      && !incoming)
+  if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32)
+       /* If we are doing soft-float with portable runtime, then there
+         is no need to worry about FP regs.  */
+       && ! TARGET_SOFT_FLOAT
+       /* The parameter must be some kind of float, else we can just
+         pass it in integer registers.  */
+       && FLOAT_MODE_P (mode)
+       /* The target function must not have a prototype.  */
+       && cum->nargs_prototype <= 0
+       /* libcalls do not need to pass items in both FP and general
+         registers.  */
+       && type != NULL_TREE
+       /* All this hair applies to outgoing args only.  */
+       && ! incoming)
+      /* Also pass outgoing floating arguments in both registers in indirect
+        calls with the 32 bit ABI and the HP assembler since there is no
+        way to the specify argument locations in static functions.  */
+      || (! TARGET_64BIT
+         && ! TARGET_GAS
+         && ! incoming
+         && cum->indirect
+         && FLOAT_MODE_P (mode)))
     {
       retval
        = gen_rtx_PARALLEL
@@ -7091,6 +7484,7 @@ function_arg (cum, mode, type, named, incoming)
             to be passed in general registers.  */
          || (!TARGET_PORTABLE_RUNTIME
              && !TARGET_64BIT
+             && !TARGET_ELF32
              && cum->indirect)
          /* If the parameter is not a floating point parameter, then
             it belongs in GPRs.  */
@@ -7105,7 +7499,7 @@ function_arg (cum, mode, type, named, incoming)
 
 /* If this arg would be passed totally in registers or totally on the stack,
    then this routine should return zero. It is currently called only for
-   the 64-bit target. */
+   the 64-bit target.  */
 int
 function_arg_partial_nregs (cum, mode, type, named)
      CUMULATIVE_ARGS *cum;
@@ -7113,22 +7507,21 @@ function_arg_partial_nregs (cum, mode, type, named)
      tree type;
      int named ATTRIBUTE_UNUSED;
 {
-  int max_arg_words = 8;
-  int offset = 0;
+  unsigned int max_arg_words = 8;
+  unsigned int offset = 0;
 
-  if (FUNCTION_ARG_SIZE(mode, type) > 1 && (cum->words & 1))
+  if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
     offset = 1;
 
-  if (cum->words + offset + FUNCTION_ARG_SIZE(mode, type) <= max_arg_words)
-    /* Arg fits fully into registers. */
+  if (cum->words + offset + FUNCTION_ARG_SIZE (mode, type) <= max_arg_words)
+    /* Arg fits fully into registers.  */
     return 0;
-  else if (cum->words + offset >= max_arg_words) 
-    /* Arg fully on the stack. */
+  else if (cum->words + offset >= max_arg_words)
+    /* Arg fully on the stack.  */
     return 0;
   else
-    /* Arg is split. */
+    /* Arg is split.  */
     return max_arg_words - cum->words - offset;
-
 }
 
 
@@ -7167,7 +7560,7 @@ mark_deferred_plabels (arg)
 /* Called to register all of our global variables with the garbage
    collector.  */
 
-static void 
+static void
 pa_add_gc_roots ()
 {
   ggc_add_rtx_root (&hppa_compare_op0, 1);
@@ -7175,3 +7568,30 @@ pa_add_gc_roots ()
   ggc_add_root (&deferred_plabels, 1, sizeof (&deferred_plabels),
                &mark_deferred_plabels);
 }
+
+/* On hpux10, the linker will give an error if we have a reference
+   in the read-only data section to a symbol defined in a shared
+   library.  Therefore, expressions that might require a reloc can
+   not be placed in the read-only data section.  */
+
+static void
+pa_select_section (exp, reloc, align)
+     tree exp;
+     int reloc;
+     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED;
+{
+  if (TREE_CODE (exp) == VAR_DECL
+      && TREE_READONLY (exp)
+      && !TREE_THIS_VOLATILE (exp)
+      && DECL_INITIAL (exp)
+      && (DECL_INITIAL (exp) == error_mark_node
+          || TREE_CONSTANT (DECL_INITIAL (exp)))
+      && !reloc)
+    readonly_data_section ();
+  else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c'
+          && !(TREE_CODE (exp) == STRING_CST && flag_writable_strings)
+          && !reloc)
+    readonly_data_section ();
+  else
+    data_section ();
+}