OSDN Git Service

* hooks.c (hook_tree_bool_false): New.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index 4541ec6..babf1a8 100644 (file)
@@ -1,5 +1,6 @@
 /* Subroutines for insn-output.c for HPPA.
-   Copyright (C) 1992, 93-98, 1999 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.
@@ -27,27 +28,94 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
 #include "tree.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 "expr.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
+#define DO_FRAME_NOTES 1
+#else
+#define DO_FRAME_NOTES 0
+#endif
+#endif
 
-static void restore_unscaled_index_insn_codes          PROTO((rtx));
-static void record_unscaled_index_insn_codes           PROTO((rtx));
-static void pa_combine_instructions                    PROTO((rtx));
-static int pa_can_combine_p    PROTO((rtx, rtx, rtx, int, rtx, rtx, rtx));
-static int forward_branch_p                            PROTO((rtx));
-static int shadd_constant_p                            PROTO((int));
-static void pa_add_gc_roots                             PROTO((void));
-static void mark_deferred_plabels                       PROTO((void *));
+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));
+static int shadd_constant_p PARAMS ((int));
+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 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.  */
@@ -59,22 +127,19 @@ enum cmp_type hppa_branch_type;
 enum processor_type pa_cpu;
 
 /* String to hold which cpu we are scheduling for.  */
-char *pa_cpu_string;
+const char *pa_cpu_string;
 
 /* Which architecture we are generating code for.  */
 enum architecture_type pa_arch;
 
 /* String to hold which architecture we are generating code for.  */
-char *pa_arch_string;
-
-/* Set by the FUNCTION_PROFILER macro. */
-int hp_profile_labelno;
+const char *pa_arch_string;
 
 /* Counts for the number of callee-saved general and floating point
    registers which were saved by the current function's prologue.  */
 static int gr_saved, fr_saved;
 
-static rtx find_addr_reg ();
+static rtx find_addr_reg PARAMS ((rtx));
 
 /* Keep track of the number of bytes we have output in the CODE subspaces
    during this compilation so we'll know when to emit inline long-calls.  */
@@ -90,18 +155,42 @@ struct deferred_plabel
   char *name;
 } *deferred_plabels = 0;
 int n_deferred_plabels = 0;
-
-/* Array indexed by INSN_UIDs holding the INSN_CODE of an insn which
-   uses an unscaled indexed address before delay slot scheduling.  */
-static int *unscaled_index_insn_codes;
-
-/* Upper bound for the array.  */
-static int max_unscaled_index_insn_codes_uid;
-
+\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";
@@ -112,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;
@@ -123,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.  */
@@ -155,36 +249,55 @@ 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");
     }
 
-  if (flag_pic && (TARGET_NO_SPACE_REGS || TARGET_FAST_INDIRECT_CALLS))
+  if (flag_pic && TARGET_FAST_INDIRECT_CALLS)
    {
       warning ("PIC code generation is not compatible with fast indirect calls\n");
    }
 
-  if (flag_pic && profile_flag)
-    {
-      warning ("PIC code generation is not compatible with profiling\n");
-    }
-
   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;
     }
 
+  /* We only support the "big PIC" model now.  And we always generate PIC
+     code when in 64bit mode.  */
+  if (flag_pic == 1 || TARGET_64BIT)
+    flag_pic = 2;
+
+  /* We can't guarantee that .dword is available for 32-bit targets.  */
+  if (UNITS_PER_WORD == 4)
+    targetm.asm_out.aligned_op.di = NULL;
+
+  /* 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;
+    }
+
   /* 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
@@ -198,14 +311,15 @@ reg_or_0_operand (op, mode)
 /* Return non-zero if OP is suitable for use in a call to a named
    function.
 
-   (???) For 2.5 try to eliminate either call_operand_address or
+   For 2.5 try to eliminate either call_operand_address or
    function_label_operand, they perform very similar functions.  */
 int
 call_operand_address (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  return (CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
+  return (GET_MODE (op) == word_mode
+         && CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
 }
 
 /* Return 1 if X contains a symbolic expression.  We know these
@@ -216,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);
 
@@ -297,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
@@ -331,9 +471,15 @@ move_operand (op, mode)
     return 0;
 
   op = XEXP (op, 0);
-  if (GET_CODE (op) == LO_SUM)
-    return (register_operand (XEXP (op, 0), Pmode)
-           && CONSTANT_P (XEXP (op, 1)));
+
+  /* We consider a LO_SUM DLT reference a move_operand now since it has
+     been merged into the normal movsi/movdi patterns.  */
+  if (GET_CODE (op) == LO_SUM
+      && GET_CODE (XEXP (op, 0)) == REG
+      && REG_OK_FOR_BASE_P (XEXP (op, 0))
+      && GET_CODE (XEXP (op, 1)) == UNSPEC
+      && GET_MODE (op) == Pmode)
+    return 1;
 
   /* Since move_operand is only used for source operands, we can always
      allow scaled indexing!  */
@@ -342,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;
 
@@ -460,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.  */
 
@@ -473,7 +621,16 @@ ireg_or_int5_operand (op, mode)
          || (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
 }
 
-/* Return truth value of whether OP is a integer which fits the
+/* Return nonzero if OP is an integer register, else return zero.  */
+int
+ireg_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32);
+}
+
+/* Return truth value of whether OP is an integer which fits the
    range constraining immediate operands in three-address insns.  */
 
 int
@@ -508,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
@@ -524,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;
@@ -628,12 +787,12 @@ pc_or_label_operand (op, mode)
 rtx
 legitimize_pic_address (orig, mode, reg)
      rtx orig, reg;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
 {
   rtx pic_ref = orig;
 
   /* Labels need special handling.  */
-  if (pic_label_operand (orig))
+  if (pic_label_operand (orig, mode))
     {
       /* We do not want to go through the movXX expanders here since that
         would create recursion.
@@ -653,22 +812,15 @@ legitimize_pic_address (orig, mode, reg)
       if (reg == 0)
        abort ();
 
-      if (flag_pic == 2)
-       {
-         emit_move_insn (reg,
-                         gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
-                                       gen_rtx_HIGH (word_mode, orig)));
-         pic_ref
-           = gen_rtx_MEM (Pmode,
-                          gen_rtx_LO_SUM (Pmode, reg,
-                                          gen_rtx_UNSPEC (Pmode,
-                                                          gen_rtvec (1, orig),
-                                                          0)));
-       }
-      else
-       pic_ref = gen_rtx_MEM (Pmode,
-                              gen_rtx_PLUS (Pmode, pic_offset_table_rtx,
-                                            orig));
+      emit_move_insn (reg,
+                     gen_rtx_PLUS (word_mode, pic_offset_table_rtx,
+                                   gen_rtx_HIGH (word_mode, orig)));
+      pic_ref
+       = gen_rtx_MEM (Pmode,
+                      gen_rtx_LO_SUM (Pmode, reg,
+                                      gen_rtx_UNSPEC (Pmode,
+                                                      gen_rtvec (1, orig),
+                                                      0)));
 
       current_function_uses_pic_offset_table = 1;
       RTX_UNCHANGING_P (pic_ref) = 1;
@@ -696,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);
@@ -766,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);
 
@@ -884,8 +1036,8 @@ hppa_legitimize_address (x, oldx, mode)
       idx = NULL_RTX;
 
       /* Make sure they're both regs.  If one was a SYMBOL_REF [+ const],
-        then emit_move_sequence will turn on REGNO_POINTER_FLAG so we'll
-        know it's a base register below.  */
+        then emit_move_sequence will turn on REG_POINTER so we'll know
+        it's a base register below.  */
       if (GET_CODE (reg1) != REG)
        reg1 = force_reg (Pmode, force_operand (reg1, 0));
 
@@ -893,9 +1045,9 @@ 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
-         && REGNO_POINTER_FLAG (REGNO (reg1)))
+         && REG_POINTER (reg1))
        {
          base = reg1;
          orig_base = XEXP (XEXP (x, 0), 1);
@@ -906,7 +1058,7 @@ hppa_legitimize_address (x, oldx, mode)
                              XEXP (x, 1));
        }
       else if (GET_CODE (reg2) == REG
-              && REGNO_POINTER_FLAG (REGNO (reg2)))
+              && REG_POINTER (reg2))
        {
          base = reg2;
          orig_base = XEXP (x, 1);
@@ -984,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.
 
@@ -1019,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.  */
@@ -1118,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
@@ -1147,12 +1315,12 @@ emit_move_sequence (operands, mode, scratch_reg)
           && GET_CODE (SUBREG_REG (operand0)) == REG
           && REGNO (SUBREG_REG (operand0)) >= FIRST_PSEUDO_REGISTER)
     {
-     /* We must not alter SUBREG_WORD (operand0) since that would confuse
+     /* We must not alter SUBREG_BYTE (operand0) since that would confuse
        the code which tracks sets/uses for delete_output_reload.  */
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand0),
                                 reg_equiv_mem [REGNO (SUBREG_REG (operand0))],
-                                SUBREG_WORD (operand0));
-      operand0 = alter_subreg (temp);
+                                SUBREG_BYTE (operand0));
+      operand0 = alter_subreg (&temp);
     }
 
   if (scratch_reg
@@ -1164,12 +1332,12 @@ emit_move_sequence (operands, mode, scratch_reg)
           && GET_CODE (SUBREG_REG (operand1)) == REG
           && REGNO (SUBREG_REG (operand1)) >= FIRST_PSEUDO_REGISTER)
     {
-     /* We must not alter SUBREG_WORD (operand0) since that would confuse
+     /* We must not alter SUBREG_BYTE (operand0) since that would confuse
        the code which tracks sets/uses for delete_output_reload.  */
       rtx temp = gen_rtx_SUBREG (GET_MODE (operand1),
                                 reg_equiv_mem [REGNO (SUBREG_REG (operand1))],
-                                SUBREG_WORD (operand1));
-      operand1 = alter_subreg (temp);
+                                SUBREG_BYTE (operand1));
+      operand1 = alter_subreg (&temp);
     }
 
   if (scratch_reg && reload_in_progress && GET_CODE (operand0) == MEM
@@ -1182,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
@@ -1198,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.  */
@@ -1230,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.  */
@@ -1255,7 +1423,7 @@ emit_move_sequence (operands, mode, scratch_reg)
 
      use scratch_reg to hold the address of the memory location.
 
-     ??? The proper fix is to change PREFERRED_RELOAD_CLASS to return
+     The proper fix is to change PREFERRED_RELOAD_CLASS to return
      NO_REGS when presented with a const_int and an register class
      containing only FP registers.  Doing so unfortunately creates
      more problems than it solves.   Fix this for 2.5.  */
@@ -1268,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.  */
@@ -1282,8 +1450,9 @@ emit_move_sequence (operands, mode, scratch_reg)
       return 1;
     }
   /* Handle secondary reloads for SAR.  These occur when trying to load
-     the SAR from memory a FP register, or with a constant.  */
+     the SAR from memory, FP register, or with a constant.  */
   else if (GET_CODE (operand0) == REG
+          && REGNO (operand0) < FIRST_PSEUDO_REGISTER
           && REGNO_REG_CLASS (REGNO (operand0)) == SHIFT_REGS
           && (GET_CODE (operand1) == MEM
               || GET_CODE (operand1) == CONST_INT
@@ -1298,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,
@@ -1312,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));
        }
@@ -1321,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);
        }
 
@@ -1335,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))
@@ -1408,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);
@@ -1431,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.  */
@@ -1466,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);
@@ -1505,20 +1676,20 @@ 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
                  && REGNO (operand0) >= FIRST_PSEUDO_REGISTER)
-               REGNO_POINTER_FLAG (REGNO (operand0)) = 1;
+               REG_POINTER (operand0) = 1;
              if (REGNO (temp) >= FIRST_PSEUDO_REGISTER)
-               REGNO_POINTER_FLAG (REGNO (temp)) = 1;
+               REG_POINTER (temp) = 1;
              if (ishighonly)
                set = gen_rtx_SET (mode, operand0, temp);
              else
@@ -1537,16 +1708,76 @@ 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;
 
+         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;
+
+             /* 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)
+               {
+#if HOST_BITS_PER_WIDE_INT > 32
+                 extend = GEN_INT (val >> 32);
+#endif
+                 operand1 = GEN_INT (nval);
+               }
+           }
+
          if (reload_in_progress || reload_completed)
            temp = operand0;
          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);
+         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;
+
+             emit_insn (gen_rtx_SET (VOIDmode, temp, GEN_INT (high)));
+             operands[1] = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+           }
+         else
+           {
+             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;
        }
     }
   /* Now have insn-emit do whatever it normally does.  */
@@ -1601,8 +1832,9 @@ reloc_needed (exp)
    so SYMBOL_REF_FLAG, which is set by ENCODE_SECTION_INFO, will be true.  */
 
 int
-read_only_operand (operand)
+read_only_operand (operand, mode)
      rtx operand;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (operand) == CONST)
     operand = XEXP (XEXP (operand, 0), 0);
@@ -1622,7 +1854,7 @@ read_only_operand (operand)
 \f
 /* Return the best assembler insn template
    for moving operands[1] into operands[0] as a fullword.   */
-char *
+const char *
 singlemove_string (operands)
      rtx *operands;
 {
@@ -1668,7 +1900,7 @@ singlemove_string (operands)
 /* Compute position (in OP[1]) and width (in OP[2])
    useful for copying IMM to a register using the zdepi
    instructions.  Store the immediate value to insert in OP[0].  */
-void
+static void
 compute_zdepwi_operands (imm, op)
      unsigned HOST_WIDE_INT imm;
      unsigned *op;
@@ -1704,10 +1936,50 @@ compute_zdepwi_operands (imm, op)
   op[2] = len;
 }
 
+/* Compute position (in OP[1]) and width (in OP[2])
+   useful for copying IMM to a register using the depdi,z
+   instructions.  Store the immediate value to insert in OP[0].  */
+void
+compute_zdepdi_operands (imm, op)
+     unsigned HOST_WIDE_INT imm;
+     unsigned *op;
+{
+  HOST_WIDE_INT lsb, len;
+
+  /* Find the least significant set bit in IMM.  */
+  for (lsb = 0; lsb < HOST_BITS_PER_WIDE_INT; lsb++)
+    {
+      if ((imm & 1) != 0)
+        break;
+      imm >>= 1;
+    }
+
+  /* Choose variants based on *sign* of the 5-bit field.  */
+  if ((imm & 0x10) == 0)
+    len = ((lsb <= HOST_BITS_PER_WIDE_INT - 4)
+          ? 4 : HOST_BITS_PER_WIDE_INT - lsb);
+  else
+    {
+      /* 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)
+           break;
+       }
+
+      /* Sign extend IMM as a 5-bit value.  */
+      imm = (imm & 0xf) - 0x10;
+    }
+
+  op[0] = imm;
+  op[1] = 63 - lsb;
+  op[2] = len;
+}
+
 /* Output assembler code to perform a doubleword move insn
    with operands OPERANDS.  */
 
-char *
+const char *
 output_move_double (operands)
      rtx *operands;
 {
@@ -1774,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)
        {
@@ -1794,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)
@@ -1818,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
            {
@@ -1886,7 +2158,6 @@ output_move_double (operands)
                               xoperands);
              return "ldw 0(%R0),%0\n\tldw 4(%R0),%R0";
            }
-          
        }
     }
 
@@ -1909,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
@@ -1932,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
@@ -1984,7 +2255,7 @@ output_move_double (operands)
   return "";
 }
 \f
-char *
+const char *
 output_fp_move_double (operands)
      rtx *operands;
 {
@@ -2052,10 +2323,10 @@ 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.   */
 
-char *
+const char *
 output_block_move (operands, size_is_constant)
      rtx *operands;
      int size_is_constant ATTRIBUTE_UNUSED;
@@ -2156,13 +2427,13 @@ output_block_move (operands, size_is_constant)
    Basic structure is the same as emit_block_move, except that we
    count insns rather than emit them.  */
 
-int
+static int
 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
@@ -2188,7 +2459,7 @@ compute_movstrsi_length (insn)
 }
 \f
 
-char *
+const char *
 output_and (operands)
      rtx *operands;
 {
@@ -2210,7 +2481,7 @@ output_and (operands)
          break;
 
       if (ms0 != 32)
-       abort();
+       abort ();
 
       if (ls1 == 32)
        {
@@ -2239,7 +2510,60 @@ output_and (operands)
     return "and %1,%2,%0";
 }
 
-char *
+/* Return a string to perform a bitwise-and of operands[1] with operands[2]
+   storing the result in operands[0].  */
+const char *
+output_64bit_and (operands)
+     rtx *operands;
+{
+  if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) != 0)
+    {
+      unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
+      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)
+         break;
+
+      for (ls1 = ls0; ls1 < HOST_BITS_PER_WIDE_INT; ls1++)
+       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)
+         break;
+
+      if (ms0 != HOST_BITS_PER_WIDE_INT)
+       abort ();
+
+      if (ls1 == HOST_BITS_PER_WIDE_INT)
+       {
+         len = ls0;
+
+         if (len == 0)
+           abort ();
+
+         operands[2] = GEN_INT (len);
+         return "extrd,u %1,63,%2,%0";
+       }
+      else
+       {
+         /* We could use this `depi' for the case above as well, but `depi'
+            requires one more register file access than an `extru'.  */
+
+         p = 63 - ls0;
+         len = ls1 - ls0;
+
+         operands[2] = GEN_INT (p);
+         operands[3] = GEN_INT (len);
+         return "depdi 0,%2,%3,%0";
+       }
+    }
+  else
+    return "and %1,%2,%0";
+}
+
+const char *
 output_ior (operands)
      rtx *operands;
 {
@@ -2258,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;
@@ -2267,12 +2591,65 @@ output_ior (operands)
   operands[3] = GEN_INT (len);
   return "{depi|depwi} -1,%2,%3,%0";
 }
+
+/* Return a string to perform a bitwise-and of operands[1] with operands[2]
+   storing the result in operands[0].  */
+const char *
+output_64bit_ior (operands)
+     rtx *operands;
+{
+  unsigned HOST_WIDE_INT mask = INTVAL (operands[2]);
+  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)
+      break;
+
+  for (bs1 = bs0; bs1 < HOST_BITS_PER_WIDE_INT; bs1++)
+    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 ();
+
+  p = 63 - bs0;
+  len = bs1 - bs0;
+
+  operands[2] = GEN_INT (p);
+  operands[3] = GEN_INT (len);
+  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;
-     unsigned char *p;
+     const char *p;
      int size;
 {
   int i;
@@ -2294,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++] = '\\';
@@ -2320,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;
     }
@@ -2339,7 +2716,7 @@ output_ascii (file, p, size)
    When CHECK_NOTES is zero we can only eliminate add,tr insns
    when there's a 1:1 correspondence between fcmp and ftest/fbranch
    instructions.  */
-void
+static void
 remove_useless_addtr_insns (insns, check_notes)
      rtx insns;
      int check_notes;
@@ -2377,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
@@ -2467,7 +2844,8 @@ remove_useless_addtr_insns (insns, check_notes)
                  /* Reverse our condition.  */
                  tmp = PATTERN (insn);
                  PUT_CODE (XEXP (tmp, 1),
-                           reverse_condition (GET_CODE (XEXP (tmp, 1))));
+                           (reverse_condition_maybe_unordered
+                            (GET_CODE (XEXP (tmp, 1)))));
                }
            }
        }
@@ -2477,8 +2855,8 @@ remove_useless_addtr_insns (insns, check_notes)
 
 }
 \f
-/* You may have trouble believing this, but this is the HP-PA stack
-   layout.  Wow.
+/* You may have trouble believing this, but this is the 32 bit HP-PA
+   stack layout.  Wow.
 
    Offset              Contents
 
@@ -2540,6 +2918,12 @@ remove_useless_addtr_insns (insns, check_notes)
 
 */
 
+/* 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;
+static int local_fsize, save_fregs;
+
 /* Emit RTL to store REG at the memory location specified by BASE+DISP.
    Handle case where DISP > 8k by using the add_high_const patterns.
 
@@ -2550,82 +2934,118 @@ static void
 store_reg (reg, disp, base)
      int reg, disp, base;
 {
+  rtx insn, dest, src, basereg;
+
+  src = gen_rtx_REG (word_mode, reg);
+  basereg = gen_rtx_REG (Pmode, base);
   if (VAL_14_BITS_P (disp))
-    emit_move_insn (gen_rtx_MEM (word_mode,
-                                plus_constant (gen_rtx_REG (Pmode, base),
-                                               disp)),
-                   gen_rtx_REG (word_mode, reg));
+    {
+      dest = gen_rtx_MEM (word_mode, plus_constant (basereg, disp));
+      insn = emit_move_insn (dest, src);
+    }
   else
     {
-      emit_move_insn (gen_rtx_REG (Pmode, 1),
-                     gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, base),
-                                   gen_rtx_HIGH (Pmode, GEN_INT (disp))));
-      emit_move_insn (gen_rtx_MEM (word_mode,
-                                  gen_rtx_LO_SUM (Pmode,
-                                                  gen_rtx_REG (Pmode, 1),
-                                                  GEN_INT (disp))),
-                     gen_rtx_REG (word_mode, reg));
+      rtx delta = GEN_INT (disp);
+      rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
+      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));
+      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));
+       }
     }
-}
 
-/* 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.
+  if (DO_FRAME_NOTES)
+    RTX_FRAME_RELATED_P (insn) = 1;
+}
 
-   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.*/
+/* Emit RTL to store REG at the memory location specified by BASE and then
+   add MOD to BASE.  MOD must be <= 8k.  */
 
 static void
-load_reg (reg, disp, base)
-     int reg, disp, base;
+store_reg_modify (base, reg, mod)
+     int base, reg, mod;
 {
-  if (VAL_14_BITS_P (disp))
-    emit_move_insn (gen_rtx_REG (word_mode, reg),
-                   gen_rtx_MEM (word_mode,
-                                plus_constant (gen_rtx_REG (Pmode, base),
-                                               disp)));
-  else
+  rtx insn, basereg, srcreg, delta;
+
+  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)
     {
-      emit_move_insn (gen_rtx_REG (Pmode, 1),
-                     gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, base),
-                                   gen_rtx_HIGH (Pmode, GEN_INT (disp))));
-      emit_move_insn (gen_rtx_REG (word_mode, reg),
-                     gen_rtx_MEM (word_mode,
-                                  gen_rtx_LO_SUM (Pmode,
-                                                  gen_rtx_REG (Pmode, 1),
-                                                  GEN_INT (disp))));
+      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.
+/* 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.
 
-   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.*/
+   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)
-     int reg, base, disp;
+set_reg_plus_d (reg, base, disp, note)
+     int reg, base, disp, note;
 {
+  rtx insn;
+
   if (VAL_14_BITS_P (disp))
-    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_HIGH (Pmode, GEN_INT (disp))));
-      emit_move_insn (gen_rtx_REG (Pmode, reg),
-                     gen_rtx_LO_SUM (Pmode,
-                                     gen_rtx_REG (Pmode, 1),
-                                      GEN_INT (disp)));
+                     gen_rtx_PLUS (Pmode, basereg,
+                                   gen_rtx_HIGH (Pmode, delta)));
+      insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
+                            gen_rtx_LO_SUM (Pmode, gen_rtx_REG (Pmode, 1),
+                                            delta));
     }
-}
 
-/* Global variables set by FUNCTION_PROLOGUE.  */
-/* Size of frame.  Need to know this to emit return insns from
-   leaf procedures.  */
-static int actual_fsize;
-static int local_fsize, save_fregs;
+  if (DO_FRAME_NOTES && note)
+    RTX_FRAME_RELATED_P (insn) = 1;
+}
 
 int
 compute_frame_size (size, fregs_live)
@@ -2641,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])
@@ -2650,8 +3082,9 @@ compute_frame_size (size, fregs_live)
   fsize = (fsize + 7) & ~7;
 
   /* Account for space used by the callee floating point register saves.  */
-  for (i = 66; i >= 48; i -= 2)
-    if (regs_ever_live[i] || regs_ever_live[i + 1])
+  for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
+    if (regs_ever_live[i]
+       || (! TARGET_64BIT && regs_ever_live[i + 1]))
       {
        if (fregs_live)
          *fregs_live = 1;
@@ -2668,17 +3101,33 @@ compute_frame_size (size, fregs_live)
   /* Allocate space for the fixed frame marker.  This space must be
      allocated for any function that makes calls or otherwise allocates
      stack space.  */
-  if (! leaf_function_p () || fsize)
-    fsize += 32;
+  if (!current_function_is_leaf || fsize)
+    fsize += TARGET_64BIT ? 16 : 32;
+
   return (fsize + STACK_BOUNDARY - 1) & ~(STACK_BOUNDARY - 1);
 }
 
-rtx hp_profile_label_rtx;
-static char hp_profile_label_name[8];
+/* 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
@@ -2690,7 +3139,7 @@ output_function_prologue (file, size)
      to output the assembler directives which denote the start
      of a function.  */
   fprintf (file, "\t.CALLINFO FRAME=%d", actual_fsize);
-  if (regs_ever_live[2] || profile_flag)
+  if (regs_ever_live[2])
     fputs (",CALLS,SAVE_RP", file);
   else
     fputs (",NO_CALLS", file);
@@ -2714,43 +3163,36 @@ output_function_prologue (file, size)
 
   fputs ("\n\t.ENTRY\n", file);
 
-  /* Horrid hack.  emit_function_prologue will modify this RTL in
-     place to get the expected results.  */
-  if (profile_flag)
-    ASM_GENERATE_INTERNAL_LABEL (hp_profile_label_name, "LP",
-                                hp_profile_labelno);
-
-  /* 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)
+  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;
 
   remove_useless_addtr_insns (get_insns (), 0);
-
-  /* Restore INSN_CODEs for insn which use unscaled indexed addresses.  */
-  restore_unscaled_index_insn_codes (get_insns ());
 }
 
 void
-hppa_expand_prologue()
+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;
@@ -2768,132 +3210,81 @@ 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.  */
-  if (regs_ever_live[2] || profile_flag)
-    store_reg (2, -20, STACK_POINTER_REGNUM);
+     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] || 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)
-  {
-    if (frame_pointer_needed)
-      {
-       /* 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
-          handles small (<8k) frames.  The second handles large (>8k)
-          frames.  */
-       emit_move_insn (tmpreg, frame_pointer_rtx);
-       emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
-       if (VAL_14_BITS_P (actual_fsize))
-         emit_insn (gen_post_store (stack_pointer_rtx, tmpreg, size_rtx));
-       else
-         {
-           /* It is incorrect to store the saved frame pointer at *sp,
-              then increment sp (writes beyond the current stack boundary).
-
-              So instead use stwm to store at *sp and post-increment the
-              stack pointer as an atomic operation.  Then increment sp to
-              finish allocating the new frame.  */
-           emit_insn (gen_post_store (stack_pointer_rtx, tmpreg,
-                      GEN_INT (64)));
-           set_reg_plus_d (STACK_POINTER_REGNUM,
-                           STACK_POINTER_REGNUM,
-                           actual_fsize - 64);
-         }
-      }
-    /* no frame pointer needed.  */
-    else
-      {
-       /* In some cases we can perform the first callee register save
-          and allocating the stack frame at the same time.   If so, just
-          make a note of it and defer allocating the frame until saving
-          the callee registers.  */
-       if (VAL_14_BITS_P (-actual_fsize)
-           && local_fsize == 0
-           && ! profile_flag
-           && ! flag_pic)
-         merge_sp_adjust_with_store = 1;
-       /* Can not optimize.  Adjust the stack frame by actual_fsize bytes.  */
-       else if (actual_fsize != 0)
-         set_reg_plus_d (STACK_POINTER_REGNUM,
-                         STACK_POINTER_REGNUM,
-                         actual_fsize);
-      }
-  }
-
-  /* The hppa calling conventions say that %r19, the pic offset
-     register, is saved at sp - 32 (in this function's frame)  when
-     generating PIC code.  FIXME:  What is the correct thing to do
-     for functions which make no calls and allocate no frame?  Do
-     we need to allocate a frame, or can we just omit the save?   For
-     now we'll just omit the save.  */
-  if (actual_fsize != 0 && flag_pic)
-    store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM);
-
-  /* Profiling code.
-
-     Instead of taking one argument, the counter label, as most normal
-     mcounts do, _mcount appears to behave differently on the HPPA.  It
-     takes the return address of the caller, the address of this routine,
-     and the address of the label.  Also, it isn't magic, so
-     argument registers have to be preserved.  */
-  if (profile_flag)
-    {
-      int pc_offset, i, arg_offset, basereg, offsetadj;
-
-      pc_offset = 4 + (frame_pointer_needed
-                      ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20)
-                      : (VAL_14_BITS_P (actual_fsize) ? 4 : 8));
-
-      /* When the function has a frame pointer, use it as the base
-        register for saving/restore registers.  Else use the stack
-        pointer.  Adjust the offset according to the frame size if
-        this function does not have a frame pointer.  */
-
-      basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM
-                                    : STACK_POINTER_REGNUM;
-      offsetadj = frame_pointer_needed ? 0 : actual_fsize;
-
-      /* Horrid hack.  emit_function_prologue will modify this RTL in
-        place to get the expected results.   sprintf here is just to
-        put something in the name.  */
-      sprintf(hp_profile_label_name, "LP$%04d", -1);
-      hp_profile_label_rtx = gen_rtx_SYMBOL_REF (Pmode,
-                                                hp_profile_label_name);
-      if (current_function_returns_struct)
-       store_reg (STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg);
-      if (current_function_needs_context)
-       store_reg (STATIC_CHAIN_REGNUM, - 16 - offsetadj, basereg);
-
-      for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
-       if (regs_ever_live [i])
-         {
-           store_reg (i, arg_offset, basereg);
-           /* Deal with arg_offset not fitting in 14 bits.  */
-           pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8;
-         }
-
-      emit_move_insn (gen_rtx_REG (word_mode, 26), gen_rtx_REG (word_mode, 2));
-      emit_move_insn (tmpreg, gen_rtx_HIGH (Pmode, hp_profile_label_rtx));
-      emit_move_insn (gen_rtx_REG (Pmode, 24),
-                     gen_rtx_LO_SUM (Pmode, tmpreg, hp_profile_label_rtx));
-      /* %r25 is set from within the output pattern.  */
-      emit_insn (gen_call_profiler (GEN_INT (- pc_offset - 20)));
+  if (actual_fsize != 0)
+    {
+      if (frame_pointer_needed)
+       {
+         /* 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 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.  */
+         insn = emit_move_insn (tmpreg, frame_pointer_rtx);
+         if (DO_FRAME_NOTES)
+           {
+             /* 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));
+           }
 
-      /* Restore argument registers.  */
-      for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
-       if (regs_ever_live [i])
-         load_reg (i, arg_offset, basereg);
+         insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+         if (DO_FRAME_NOTES)
+           RTX_FRAME_RELATED_P (insn) = 1;
 
-      if (current_function_returns_struct)
-       load_reg (STRUCT_VALUE_REGNUM, -12 - offsetadj, basereg);
+         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,
+                then increment sp (writes beyond the current stack boundary).
+
+                So instead use stwm to store at *sp and post-increment the
+                stack pointer as an atomic operation.  Then increment sp to
+                finish allocating the new frame.  */
+             int adjust1 = 8192 - 64;
+             int adjust2 = actual_fsize - adjust1;
+
+             store_reg_modify (STACK_POINTER_REGNUM, 1, adjust1);
+             set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                             adjust2, 1);
+           }
 
-      if (current_function_needs_context)
-       load_reg (STATIC_CHAIN_REGNUM, -16 - offsetadj, basereg);
+         /* 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.  */
+         emit_insn (gen_blockage ());
+       }
+      /* no frame pointer needed.  */
+      else
+       {
+         /* In some cases we can perform the first callee register save
+            and allocating the stack frame at the same time.   If so, just
+            make a note of it and defer allocating the frame until saving
+            the callee registers.  */
+         if (VAL_14_BITS_P (actual_fsize) && local_fsize == 0)
+           merge_sp_adjust_with_store = 1;
+         /* Can not optimize.  Adjust the stack frame by actual_fsize
+            bytes.  */
+         else
+           set_reg_plus_d (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,
+                           actual_fsize, 1);
+       }
     }
 
   /* Normal register save.
@@ -2902,7 +3293,27 @@ 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])
          {
            store_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -2915,17 +3326,42 @@ 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)
              {
+               store_reg_modify (STACK_POINTER_REGNUM, i, -offset);
                merge_sp_adjust_with_store = 0;
-               emit_insn (gen_post_store (stack_pointer_rtx,
-                                          gen_rtx_REG (word_mode, i),
-                                          GEN_INT (-offset)));
              }
            else
              store_reg (i, offset, STACK_POINTER_REGNUM);
@@ -2936,64 +3372,137 @@ 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)
-       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
+     register, is saved at sp - 32 (in this function's frame)
+     when generating PIC code.  FIXME:  What is the correct thing
+     to do for functions which make no calls and allocate no
+     frame?  Do we need to allocate a frame, or can we just omit
+     the save?   For now we'll just omit the save.  */
+  if (flag_pic && actual_fsize != 0 && !TARGET_64BIT)
+    store_reg (PIC_OFFSET_TABLE_REGNUM, -32, STACK_POINTER_REGNUM);
+
   /* Align pointer properly (doubleword boundary).  */
   offset = (offset + 7) & ~7;
 
   /* 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)
-       set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+       {
+         set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
+         base = frame_pointer_rtx;
+       }
       else
-       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 = 66; i >= 48; i -= 2)
+      for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
        {
-         if (regs_ever_live[i] || regs_ever_live[i + 1])
+         if (regs_ever_live[i]
+             || (! TARGET_64BIT && regs_ever_live[i + 1]))
            {
-             emit_move_insn (gen_rtx_MEM (DFmode,
-                                          gen_rtx_POST_INC (DFmode, tmpreg)),
-                             gen_rtx_REG (DFmode, i));
+             rtx addr, insn, reg;
+             addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
+             reg = gen_rtx_REG (DFmode, i);
+             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++;
            }
        }
     }
 
-  /* When generating PIC code it is necessary to save/restore the
-     PIC register around each function call.  We used to do this
-     in the call patterns themselves, but that implementation
-     made incorrect assumptions about using global variables to hold
-     per-function rtl code generated in the backend.
+  /* 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 ());
+}
 
-     So instead, we copy the PIC register into a reserved callee saved
-     register in the prologue.  Then after each call we reload the PIC
-     register from the callee saved register.  We also reload the PIC
-     register from the callee saved register in the epilogue ensure the
-     PIC register is valid at function exit.
+/* 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.  */
 
-     This may (depending on the exact characteristics of the function)
-     even be more efficient. 
+static void
+load_reg (reg, disp, base)
+     int reg, disp, base;
+{
+  rtx src, dest, basereg;
 
-     Avoid this if the callee saved register wasn't used (these are
-     leaf functions).  */
-  if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM_SAVED])
-    emit_move_insn (gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM_SAVED),
-                   gen_rtx_REG (word_mode, PIC_OFFSET_TABLE_REGNUM));
+  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));
+      emit_move_insn (dest, src);
+    }
+  else
+    {
+      rtx delta = GEN_INT (disp);
+      rtx high = gen_rtx_PLUS (Pmode, basereg, gen_rtx_HIGH (Pmode, delta));
+      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));
+      emit_move_insn (dest, src);
+    }
 }
 
+/* This function generates the assembly code for function exit.
+   Args are as for output_function_prologue ().
 
-void
-output_function_epilogue (file, size)
+   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 ();
 
@@ -3020,40 +3529,64 @@ output_function_epilogue (file, size)
     fputs ("\tnop\n", file);
 
   fputs ("\t.EXIT\n\t.PROCEND\n", file);
-
-  /* Free up stuff we don't need anymore.  */
-  if (unscaled_index_insn_codes)
-    free (unscaled_index_insn_codes);
-  max_unscaled_index_insn_codes_uid = 0;
 }
 
 void
 hppa_expand_epilogue ()
 {
   rtx tmpreg;
-  int offset,i;
-  int merge_sp_adjust_with_load  = 0;
+  int offset, i;
+  int merge_sp_adjust_with_load = 0;
+  int ret_off = 0;
 
   /* We will use this often.  */
   tmpreg = gen_rtx_REG (word_mode, 1);
 
   /* 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 (frame_pointer_needed
-      && (regs_ever_live [2] || profile_flag))
-    load_reg (2, -20, FRAME_POINTER_REGNUM);
-
-  /* No frame pointer, and stack is smaller than 8k.  */
-  else if (! frame_pointer_needed
-          && VAL_14_BITS_P (actual_fsize + 20)
-          && (regs_ever_live[2] || profile_flag))
-    load_reg (2, - (actual_fsize + 20), STACK_POINTER_REGNUM);
+     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)
+       {
+         load_reg (2, ret_off, FRAME_POINTER_REGNUM);
+         ret_off = 0;
+       }
+      else
+       {
+         /* No frame pointer, and stack is smaller than 8k.  */
+         if (VAL_14_BITS_P (ret_off - actual_fsize))
+           {
+             load_reg (2, ret_off - actual_fsize, STACK_POINTER_REGNUM);
+             ret_off = 0;
+           }
+       }
+    }
 
   /* 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])
          {
            load_reg (i, offset, FRAME_POINTER_REGNUM);
@@ -3062,19 +3595,46 @@ hppa_expand_epilogue ()
     }
   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])
            {
              /* Only for the first load.
                 merge_sp_adjust_with_load holds the register load
                 with which we will merge the sp adjustment.  */
-             if (VAL_14_BITS_P (actual_fsize + 20)
+             if (merge_sp_adjust_with_load == 0
                  && local_fsize == 0
-                 && ! merge_sp_adjust_with_load)
+                 && VAL_14_BITS_P (-actual_fsize))
                merge_sp_adjust_with_load = i;
              else
-               load_reg (i, offset, STACK_POINTER_REGNUM);
+               load_reg (i, offset, STACK_POINTER_REGNUM);
              offset += UNITS_PER_WORD;
            }
        }
@@ -3088,20 +3648,19 @@ hppa_expand_epilogue ()
     {
       /* Adjust the register to index off of.  */
       if (frame_pointer_needed)
-       set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
+       set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset, 0);
       else
-       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 = 66; i >= 48; i -= 2)
-       {
-         if (regs_ever_live[i] || regs_ever_live[i + 1])
-           {
-             emit_move_insn (gen_rtx_REG (DFmode, i),
-                             gen_rtx_MEM (DFmode,
-                                          gen_rtx_POST_INC (DFmode, tmpreg)));
-           }
-       }
+      for (i = FP_SAVED_REG_LAST; i >= FP_SAVED_REG_FIRST; i -= FP_REG_STEP)
+       if (regs_ever_live[i]
+           || (! TARGET_64BIT && regs_ever_live[i + 1]))
+         {
+           rtx src = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
+           rtx dest = gen_rtx_REG (DFmode, i);
+           emit_move_insn (dest, src);
+         }
     }
 
   /* Emit a blockage insn here to keep these insns from being moved to
@@ -3110,51 +3669,119 @@ hppa_expand_epilogue ()
      This is necessary as we must not cut the stack back before all the
      restores are finished.  */
   emit_insn (gen_blockage ());
-  /* No frame pointer, but we have a stack greater than 8k.  We restore
-     %r2 very late in this case.  (All other cases are restored as early
-     as possible.)  */
-  if (! frame_pointer_needed
-      && ! VAL_14_BITS_P (actual_fsize + 20)
-      && (regs_ever_live[2] || profile_flag))
-    {
-      set_reg_plus_d (STACK_POINTER_REGNUM,
-                     STACK_POINTER_REGNUM,
-                     - actual_fsize);
-
-      /* This used to try and be clever by not depending on the value in
-        %r30 and instead use the value held in %r1 (so that the 2nd insn
-        which sets %r30 could be put in the delay slot of the return insn).
-       
-        That won't work since if the stack is exactly 8k set_reg_plus_d
-        doesn't set %r1, just %r30.  */
-      load_reg (2, - 20, STACK_POINTER_REGNUM);
-    }
-
-  /* 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.  */
-  else if (frame_pointer_needed)
+  if (frame_pointer_needed)
     {
-      set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
-      emit_insn (gen_pre_load (frame_pointer_rtx, 
-                              stack_pointer_rtx,
-                              GEN_INT (-64)));
+      rtx delta = GEN_INT (-64);
+
+      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 (! frame_pointer_needed  && merge_sp_adjust_with_load)
-    emit_insn (gen_pre_load (gen_rtx_REG (word_mode, merge_sp_adjust_with_load),
-                            stack_pointer_rtx,
-                            GEN_INT (- actual_fsize)));
+  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);
+
+      emit_insn (gen_pre_load (dest, stack_pointer_rtx, delta));
+    }
   else if (actual_fsize != 0)
-    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)
+    load_reg (2, ret_off, STACK_POINTER_REGNUM);
+
+  if (DO_FRAME_NOTES && current_function_calls_eh_return)
+    {
+      rtx sa = EH_RETURN_STACKADJ_RTX;
+
+      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));
+    }
+}
+
+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;
+{
+  rtx begin_label_rtx, call_insn;
+  char begin_label_name[16];
+
+  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)));
+
+  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 count_label_name[16];
+
+    ASM_GENERATE_INTERNAL_LABEL (count_label_name, "LP", label_no);
+    count_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (count_label_name));
+
+    addr = force_reg (Pmode, count_label_rtx);
+    r24 = gen_rtx_REG (Pmode, 24);
+    emit_move_insn (r24, addr);
+
+    /* %r25 is set from within the output pattern.  */
+    call_insn =
+      emit_call_insn (gen_call_profiler (gen_rtx_SYMBOL_REF (Pmode, "_mcount"),
+                                        GEN_INT (TARGET_64BIT ? 24 : 12),
+                                        begin_label_rtx));
+
+    use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), r24);
+  }
+#else
+    /* %r25 is set from within the output pattern.  */
+  call_insn =
+    emit_call_insn (gen_call_profiler (gen_rtx_SYMBOL_REF (Pmode, "_mcount"),
+                                      GEN_INT (TARGET_64BIT ? 16 : 8),
+                                      begin_label_rtx));
+#endif
+
+  /* Indicate the _mcount call cannot throw, nor will it execute a
+     non-local goto.  */
+  REG_NOTES (call_insn)
+    = gen_rtx_EXPR_LIST (REG_EH_REGION, constm1_rtx, REG_NOTES (call_insn));
+
+  if (flag_pic)
+    {
+      use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), pic_offset_table_rtx);
+      if (TARGET_64BIT)
+       use_reg (&CALL_INSN_FUNCTION_USAGE (call_insn), arg_pointer_rtx);
+
+      emit_move_insn (pic_offset_table_rtx, hppa_pic_save_rtx ());
+    }
 }
 
 /* Fetch the return address for the frame COUNT steps up from
    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:
 
@@ -3169,37 +3796,36 @@ hppa_expand_epilogue ()
 
    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;
 
-  saved_rp = gen_reg_rtx (Pmode);
+  if (count != 0)
+    return NULL_RTX;
 
-  /* First, we start off with the normal return address pointer from
-     -20[frameaddr].  */
+  rp = get_hard_reg_initial_val (Pmode, 2);
 
-  emit_move_insn (saved_rp, plus_constant (frameaddr, -5 * UNITS_PER_WORD));
+  if (TARGET_64BIT || TARGET_NO_SPACE_REGS)
+    return rp;
+
+  saved_rp = gen_reg_rtx (Pmode);
+  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
@@ -3213,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, -6 * UNITS_PER_WORD));
+  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
@@ -3260,7 +3886,6 @@ hppa_can_use_return_insn_p ()
 {
   return (reload_completed
          && (compute_frame_size (get_frame_size (), 0) ? 0 : 1)
-         && ! profile_flag
          && ! regs_ever_live[2]
          && ! frame_pointer_needed);
 }
@@ -3293,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;
@@ -3302,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))
@@ -3311,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.  */
@@ -3400,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;
@@ -3435,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;
@@ -3480,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;
@@ -3516,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;
@@ -3531,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.
 
@@ -3561,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)
@@ -3577,6 +4209,7 @@ pa_adjust_insn_length (insn, length)
   /* Block move pattern.  */
   else if (GET_CODE (insn) == INSN
           && GET_CODE (pat) == PARALLEL
+          && GET_CODE (XVECEXP (pat, 0, 0)) == SET
           && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 0)) == MEM
           && GET_CODE (XEXP (XVECEXP (pat, 0, 0), 1)) == MEM
           && GET_MODE (XEXP (XVECEXP (pat, 0, 0), 0)) == BLKmode
@@ -3596,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
@@ -3638,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)))
@@ -3652,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)))
@@ -3662,6 +4295,17 @@ print_operand (file, x, code)
        }
       else
        break;
+    case 'A':
+      {
+       rtx xoperands[2];
+
+       xoperands[0] = XEXP (XEXP (x, 0), 0);
+       xoperands[1] = XVECEXP (XEXP (XEXP (x, 0), 1), 0, 0);
+       output_global_address (file, xoperands[1], 0);
+        fprintf (file, "(%s)", reg_names [REGNO (xoperands[0])]);
+       return;
+      }
+
     case 'C':                  /* Plain (C)ondition */
     case 'X':
       switch (GET_CODE (x))
@@ -3717,8 +4361,8 @@ print_operand (file, x, code)
          abort ();
        }
       return;
-    /* For floating point comparisons.  Need special conditions to deal
-       with NaNs properly.  */
+    /* For floating point comparisons.  Note that the output
+       predicates are the complement of the desired mode.  */
     case 'Y':
       switch (GET_CODE (x))
        {
@@ -3727,13 +4371,29 @@ print_operand (file, x, code)
        case NE:
          fputs ("=", file);  break;
        case GT:
-         fputs ("<=", file);  break;
+         fputs ("!>", file);  break;
        case GE:
-         fputs ("<", file);  break;
+         fputs ("!>=", file);  break;
        case LT:
-         fputs (">=", file);  break;
+         fputs ("!<", file);  break;
        case LE:
+         fputs ("!<=", file);  break;
+       case LTGT:
+         fputs ("!<>", file);  break;
+       case UNLE:
          fputs (">", file);  break;
+       case UNLT:
+         fputs (">=", file);  break;
+       case UNGE:
+         fputs ("<", file);  break;
+       case UNGT:
+         fputs ("<=", file);  break;
+       case UNEQ:
+         fputs ("<>", file);  break;
+       case UNORDERED:
+         fputs ("<=>", file);  break;
+       case ORDERED:
+         fputs ("!<=>", file);  break;
        default:
          abort ();
        }
@@ -3795,31 +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 ();
+    case 'Q':
+      if (GET_CODE (x) == CONST_INT)
+       {
+         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, HOST_WIDE_INT_PRINT_DEC, 63 - (INTVAL (x) & 63));
+         return;
+       }
+      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);
@@ -3875,27 +4549,48 @@ print_operand (file, x, code)
        fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
        return;
       }
+    case 'z':
+      {
+       unsigned op[3];
+       compute_zdepdi_operands (INTVAL (x), op);
+       fprintf (file, "%d,%d,%d", op[0], op[1], op[2]);
+       return;
+      }
+    case 'c':
+      /* We can get here from a .vtable_inherit due to our
+        CONSTANT_ADDRESS_P rejecting perfectly good constant
+        addresses.  */
+      break;
     default:
       abort ();
     }
   if (GET_CODE (x) == REG)
     {
       fputs (reg_names [REGNO (x)], file);
-      if (FP_REG_P (x) && GET_MODE_SIZE (GET_MODE (x)) <= 4 && (REGNO (x) & 1) == 0)
+      if (TARGET_64BIT && FP_REG_P (x) && GET_MODE_SIZE (GET_MODE (x)) <= 4)
+       {
+         fputs ("R", file);
+         return;
+       }
+      if (FP_REG_P (x)
+         && GET_MODE_SIZE (GET_MODE (x)) <= 4
+         && (REGNO (x) & 1) == 0)
        fputs ("L", file);
     }
   else if (GET_CODE (x) == MEM)
     {
       int size = GET_MODE_SIZE (GET_MODE (x));
-      rtx base = XEXP (XEXP (x, 0), 0);
+      rtx base = NULL_RTX;
       switch (GET_CODE (XEXP (x, 0)))
        {
        case PRE_DEC:
        case POST_DEC:
+          base = XEXP (XEXP (x, 0), 0);
          fprintf (file, "-%d(%s)", size, reg_names [REGNO (base)]);
          break;
        case PRE_INC:
        case POST_INC:
+          base = XEXP (XEXP (x, 0), 0);
          fprintf (file, "%d(%s)", size, reg_names [REGNO (base)]);
          break;
        default:
@@ -3918,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)
@@ -3931,7 +4626,7 @@ output_global_address (file, x, round_constant)
   if (GET_CODE (x) == HIGH)
     x = XEXP (x, 0);
 
-  if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x))
+  if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x, VOIDmode))
     assemble_name (file, XSTR (x, 0));
   else if (GET_CODE (x) == SYMBOL_REF && !flag_pic)
     {
@@ -3940,7 +4635,7 @@ output_global_address (file, x, round_constant)
     }
   else if (GET_CODE (x) == CONST)
     {
-      char *sep = "";
+      const char *sep = "";
       int offset = 0;          /* assembler wants -$global$ at end */
       rtx base = NULL_RTX;
 
@@ -3959,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
@@ -3989,10 +4684,10 @@ output_global_address (file, x, round_constant)
        sep = "-";
       else abort ();
 
-      if (!read_only_operand (base) && !flag_pic)
+      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);
@@ -4016,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);
     }
 }
 
@@ -4025,9 +4720,10 @@ output_deferred_plabels (file)
    Keep track of which ones we have used.  */
 
 enum millicodes { remI, remU, divI, divU, mulI, mulU, end1000 };
-static char imported[(int)end1000];
-static char *milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
-static char import_string[] = ".IMPORT $$....,MILLICODE";
+static void import_milli                       PARAMS ((enum millicodes));
+static char imported[(int) end1000];
+static const char * const milli_names[] = {"remI", "remU", "divI", "divU", "mulI", "mulU"};
+static const char import_string[] = ".IMPORT $$....,MILLICODE";
 #define MILLI_START 10
 
 static void
@@ -4036,19 +4732,19 @@ 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.  */
 
-char *
+const char *
 output_mul_insn (unsignedp, insn)
      int unsignedp ATTRIBUTE_UNUSED;
      rtx insn;
@@ -4057,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];
 
@@ -4090,26 +4786,29 @@ 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
         (PARALLEL, VOIDmode,
-         gen_rtvec (5, gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, 29),
+         gen_rtvec (6, gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, 29),
                                     gen_rtx_fmt_ee (unsignedp ? UDIV : DIV,
                                                     SImode,
                                                     gen_rtx_REG (SImode, 26),
                                                     operands[2])),
+                    gen_rtx_CLOBBER (VOIDmode, operands[4]),
                     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;
     }
   return 0;
 }
 
-char *
+const char *
 output_div_insn (operands, unsignedp, insn)
      rtx *operands;
      int unsignedp;
@@ -4133,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)
@@ -4162,9 +4863,9 @@ output_div_insn (operands, unsignedp, insn)
     }
 }
 
-/* Output a $$rem millicode to do mod. */
+/* Output a $$rem millicode to do mod.  */
 
-char *
+const char *
 output_mod_insn (unsignedp, insn)
      int unsignedp;
      rtx insn;
@@ -4187,12 +4888,17 @@ void
 output_arg_descriptor (call_insn)
      rtx call_insn;
 {
-  char *arg_regs[4];
+  const char *arg_regs[4];
   enum machine_mode arg_mode;
   rtx link;
   int i, output_flag = 0;
   int regno;
 
+  /* We neither need nor want argument location descriptors for the
+     64bit runtime environment or the ELF32 environment.  */
+  if (TARGET_64BIT || TARGET_ELF32)
+    return;
+
   for (i = 0; i < 4; i++)
     arg_regs[i] = 0;
 
@@ -4273,7 +4979,7 @@ secondary_reload_class (class, mode, in)
 
   /* Trying to load a constant into a FP register during PIC code
      generation will require %r1 as a scratch register.  */
-  if (flag_pic == 2
+  if (flag_pic
       && GET_MODE_CLASS (mode) == MODE_INT
       && FP_REG_CLASS_P (class)
       && (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
@@ -4308,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);
 
@@ -4335,10 +5048,10 @@ secondary_reload_class (class, mode, in)
         is_symbolic = 0;
         break;
     }
-  
+
   if (!flag_pic
       && is_symbolic
-      && read_only_operand (in))
+      && read_only_operand (in, VOIDmode))
     return NO_REGS;
 
   if (class != R1_REGS && is_symbolic)
@@ -4360,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);
@@ -4392,11 +5105,42 @@ hppa_builtin_saveregs ()
   else
     offset = current_function_arg_offset_rtx;
 
-  /* Store general registers on the stack. */
+  if (TARGET_64BIT)
+    {
+      int i, off;
+
+      /* Adjust for varargs/stdarg differences.  */
+      if (argadj)
+       offset = plus_constant (current_function_arg_offset_rtx, -argadj);
+      else
+       offset = current_function_arg_offset_rtx;
+
+      /* We need to save %r26 .. %r19 inclusive starting at offset -64
+        from the incoming arg pointer and growing to larger addresses.  */
+      for (i = 26, off = -64; i >= 19; i--, off += 8)
+       emit_move_insn (gen_rtx_MEM (word_mode,
+                                    plus_constant (arg_pointer_rtx, off)),
+                       gen_rtx_REG (word_mode, i));
+
+      /* The incoming args pointer points just beyond the flushback area;
+        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,
+                     plus_constant (arg_pointer_rtx, -64));
+
+      /* Now return a pointer to the first anonymous argument.  */
+      return copy_to_reg (expand_binop (Pmode, add_optab,
+                                       virtual_incoming_args_rtx,
+                                       offset, 0, 0, OPTAB_LIB_WIDEN));
+    }
+
+  /* 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
@@ -4410,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));
@@ -4424,7 +5161,7 @@ hppa_builtin_saveregs ()
 
 void
 hppa_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+     int stdarg_p ATTRIBUTE_UNUSED;
      tree valist;
      rtx nextarg;
 {
@@ -4439,6 +5176,25 @@ hppa_va_arg (valist, type)
   HOST_WIDE_INT align, size, ofs;
   tree t, ptr, pptr;
 
+  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.  */
+
+      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,
+                     build_int_2 (-2 * UNITS_PER_WORD, -1));
+          t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
+          TREE_SIDE_EFFECTS (t) = 1;
+          expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+        }
+      return std_expand_builtin_va_arg (valist, type);
+    }
+
   /* Compute the rounded size of the type.  */
   align = PARM_BOUNDARY / BITS_PER_UNIT;
   size = int_size_in_bytes (type);
@@ -4448,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;
 
@@ -4464,14 +5220,14 @@ hppa_va_arg (valist, type)
       t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
                 build_int_2 (-size, -1));
 
-      /* ??? Copied from va-pa.h, but we probably don't need to align
+      /* Copied from va-pa.h, but we probably don't need to align
         to word size, since we generate and preserve that invariant.  */
       t = build (BIT_AND_EXPR, TREE_TYPE (valist), t,
                 build_int_2 ((size > 4 ? -8 : -4), -1));
 
       t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
       TREE_SIDE_EFFECTS (t) = 1;
-      
+
       ofs = (8 - size) % 4;
       if (ofs)
        {
@@ -4496,7 +5252,7 @@ hppa_va_arg (valist, type)
    output appropriate to emit the branch corresponding to all given
    parameters.  */
 
-char *
+const char *
 output_cbranch (operands, nullify, length, negated, insn)
   rtx *operands;
   int nullify, length, negated;
@@ -4542,6 +5298,8 @@ output_cbranch (operands, nullify, length, negated, insn)
          strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
        else
          strcpy (buf, "{com%I2b,|cmp%I2b,}");
+       if (GET_MODE (operands[1]) == DImode)
+         strcat (buf, "*");
        if (negated)
          strcat (buf, "%B3");
        else
@@ -4565,6 +5323,8 @@ output_cbranch (operands, nullify, length, negated, insn)
            && nullify)
          {
            strcpy (buf, "{com%I2b,|cmp%I2b,}");
+           if (GET_MODE (operands[1]) == DImode)
+             strcat (buf, "*");
            if (negated)
              strcat (buf, "%S3");
            else
@@ -4576,11 +5336,13 @@ output_cbranch (operands, nullify, length, negated, insn)
           taken and untaken branches.  */
        else if (dbr_sequence_length () == 0
                 && ! forward_branch_p (insn)
-                && insn_addresses
-                && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
-                                   - insn_addresses[INSN_UID (insn)] - 8))
+                && INSN_ADDRESSES_SET_P ()
+                && VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
+                                   - INSN_ADDRESSES (INSN_UID (insn)) - 8))
          {
            strcpy (buf, "{com%I2b,|cmp%I2b,}");
+           if (GET_MODE (operands[1]) == DImode)
+             strcat (buf, "*");
            if (negated)
              strcat (buf, "%B3 %2,%r1,%0%#");
            else
@@ -4589,6 +5351,8 @@ output_cbranch (operands, nullify, length, negated, insn)
        else
          {
            strcpy (buf, "{com%I2clr,|cmp%I2clr,}");
+           if (GET_MODE (operands[1]) == DImode)
+             strcat (buf, "*");
            if (negated)
              strcat (buf, "%S3");
            else
@@ -4612,6 +5376,15 @@ output_cbranch (operands, nullify, length, negated, insn)
          strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+20|cmp%I2b,%S3,n %2,%r1,.+20}");
        else
          strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+20|cmp%I2b,%B3,n %2,%r1,.+20}");
+       if (GET_MODE (operands[1]) == DImode)
+         {
+           if (negated)
+             strcpy (buf,
+                     "{com%I2b,*%S3,n %2,%r1,.+20|cmp%I2b,*%S3,n %2,%r1,.+20}");
+           else
+             strcpy (buf,
+                     "{com%I2b,*%B3,n %2,%r1,.+20|cmp%I2b,*%B3,n %2,%r1,.+20}");
+         }
        output_asm_insn (buf, operands);
 
        /* Output an insn to save %r1.  */
@@ -4637,6 +5410,13 @@ output_cbranch (operands, nullify, length, negated, insn)
          strcpy (buf, "{com%I2b,%S3,n %2,%r1,.+28|cmp%I2b,%S3,n %2,%r1,.+28}");
        else
          strcpy (buf, "{com%I2b,%B3,n %2,%r1,.+28|cmp%I2b,%B3,n %2,%r1,.+28}");
+       if (GET_MODE (operands[1]) == DImode)
+         {
+           if (negated)
+             strcpy (buf, "{com%I2b,*%S3,n %2,%r1,.+28|cmp%I2b,*%S3,n %2,%r1,.+28}");
+           else
+             strcpy (buf, "{com%I2b,*%B3,n %2,%r1,.+28|cmp%I2b,*%B3,n %2,%r1,.+28}");
+         }
        output_asm_insn (buf, operands);
 
        /* Output an insn to save %r1.  */
@@ -4650,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;
 }
@@ -4675,7 +5465,7 @@ output_cbranch (operands, nullify, length, negated, insn)
    varying length branches, negated branches and all combinations of the
    above.  it returns the appropriate output template to emit the branch.  */
 
-char *
+const char *
 output_bb (operands, nullify, length, negated, insn, which)
   rtx *operands ATTRIBUTE_UNUSED;
   int nullify, length, negated;
@@ -4724,6 +5514,10 @@ output_bb (operands, nullify, length, negated, insn, which)
          strcpy (buf, "{extrs,|extrw,s,}");
        else
          strcpy (buf, "bb,");
+       if (useskip && GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "extrd,s,*");
+       else if (GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "bb,*");
        if ((which == 0 && negated)
             || (which == 1 && ! negated))
          strcat (buf, ">=");
@@ -4752,6 +5546,8 @@ output_bb (operands, nullify, length, negated, insn, which)
            && nullify)
          {
            strcpy (buf, "bb,");
+           if (GET_MODE (operands[0]) == DImode)
+             strcat (buf, "*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, "<");
@@ -4767,11 +5563,13 @@ output_bb (operands, nullify, length, negated, insn, which)
           taken and untaken branches.  */
        else if (dbr_sequence_length () == 0
                 && ! forward_branch_p (insn)
-                && insn_addresses
-                && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
-                                   - insn_addresses[INSN_UID (insn)] - 8))
+                && INSN_ADDRESSES_SET_P ()
+                && VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
+                                   - INSN_ADDRESSES (INSN_UID (insn)) - 8))
          {
            strcpy (buf, "bb,");
+           if (GET_MODE (operands[0]) == DImode)
+             strcat (buf, "*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, ">=");
@@ -4785,6 +5583,8 @@ output_bb (operands, nullify, length, negated, insn, which)
        else
          {
            strcpy (buf, "{extrs,|extrw,s,}");
+           if (GET_MODE (operands[0]) == DImode)
+             strcpy (buf, "extrd,s,*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, "<");
@@ -4802,7 +5602,7 @@ output_bb (operands, nullify, length, negated, insn, which)
        break;
 
       default:
-       abort();
+       abort ();
     }
   return buf;
 }
@@ -4813,7 +5613,7 @@ output_bb (operands, nullify, length, negated, insn, which)
    of the above.  it returns the appropriate output template to emit the
    branch.  */
 
-char *
+const char *
 output_bvb (operands, nullify, length, negated, insn, which)
   rtx *operands ATTRIBUTE_UNUSED;
   int nullify, length, negated;
@@ -4862,6 +5662,10 @@ output_bvb (operands, nullify, length, negated, insn, which)
          strcpy (buf, "{vextrs,|extrw,s,}");
        else
          strcpy (buf, "{bvb,|bb,}");
+       if (useskip && GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "extrd,s,*}");
+       else if (GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "bb,*");
        if ((which == 0 && negated)
             || (which == 1 && ! negated))
          strcat (buf, ">=");
@@ -4890,6 +5694,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
            && nullify)
          {
            strcpy (buf, "{bvb,|bb,}");
+           if (GET_MODE (operands[0]) == DImode)
+             strcat (buf, "*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, "<");
@@ -4905,11 +5711,13 @@ output_bvb (operands, nullify, length, negated, insn, which)
           taken and untaken branches.  */
        else if (dbr_sequence_length () == 0
                 && ! forward_branch_p (insn)
-                && insn_addresses
-                && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
-                                   - insn_addresses[INSN_UID (insn)] - 8))
+                && INSN_ADDRESSES_SET_P ()
+                && VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
+                                   - INSN_ADDRESSES (INSN_UID (insn)) - 8))
          {
            strcpy (buf, "{bvb,|bb,}");
+           if (GET_MODE (operands[0]) == DImode)
+             strcat (buf, "*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, ">=");
@@ -4923,6 +5731,8 @@ output_bvb (operands, nullify, length, negated, insn, which)
        else
          {
            strcpy (buf, "{vextrs,|extrw,s,}");
+           if (GET_MODE (operands[0]) == DImode)
+             strcpy (buf, "extrd,s,*");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, "<");
@@ -4940,7 +5750,7 @@ output_bvb (operands, nullify, length, negated, insn, which)
        break;
 
       default:
-       abort();
+       abort ();
     }
   return buf;
 }
@@ -4949,7 +5759,7 @@ output_bvb (operands, nullify, length, negated, insn, which)
 
    Note it may perform some output operations on its own before
    returning the final output string.  */
-char *
+const char *
 output_dbra (operands, insn, which_alternative)
      rtx *operands;
      rtx insn;
@@ -4965,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";
        }
@@ -5010,9 +5820,9 @@ output_dbra (operands, insn, which_alternative)
             taken and untaken branches.  */
          else if (dbr_sequence_length () == 0
                   && ! forward_branch_p (insn)
-                  && insn_addresses
-                  && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
-                                     - insn_addresses[INSN_UID (insn)] - 8))
+                  && INSN_ADDRESSES_SET_P ()
+                  && VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
+                                     - INSN_ADDRESSES (INSN_UID (insn)) - 8))
              return "addib,%C2 %1,%0,%3%#";
 
          /* Handle normal cases.  */
@@ -5022,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)
@@ -5030,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";
@@ -5054,7 +5865,7 @@ output_dbra (operands, insn, which_alternative)
 
    Note it may perform some output operations on its own before
    returning the final output string.  */
-char *
+const char *
 output_movb (operands, insn, which_alternative, reverse_comparison)
      rtx *operands;
      rtx insn;
@@ -5071,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)
@@ -5118,9 +5929,9 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
             taken and untaken branches.  */
          else if (dbr_sequence_length () == 0
                   && ! forward_branch_p (insn)
-                  && insn_addresses
-                  && VAL_14_BITS_P (insn_addresses[INSN_UID (JUMP_LABEL (insn))]
-                                     - insn_addresses[INSN_UID (insn)] - 8))
+                  && INSN_ADDRESSES_SET_P ()
+                  && VAL_14_BITS_P (INSN_ADDRESSES (INSN_UID (JUMP_LABEL (insn)))
+                                     - INSN_ADDRESSES (INSN_UID (insn)) - 8))
            return "movb,%C2 %1,%0,%3%#";
          /* Handle normal cases.  */
          if (nullify)
@@ -5129,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)
@@ -5137,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
@@ -5169,37 +5980,43 @@ output_movb (operands, insn, which_alternative, reverse_comparison)
 
    CALL_DEST is the routine we are calling.  */
 
-char *
+const char *
 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;
 
+  xoperands[3] = gen_rtx_REG (Pmode, TARGET_64BIT ? 2 : 31);
+
   /* 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,%%r31%#", xoperands);
+      output_asm_insn ("{bl|b,l} %0,%3%#", xoperands);
       return "";
     }
 
   /* 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;
-      rtx xoperands[2];
 
       /* 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
@@ -5213,27 +6030,52 @@ output_millicode_call (insn, call_dest)
          delay_insn_deleted = 1;
        }
 
-      /* If we're allowed to use be/ble instructions, then this is the
-        best sequence to use for a long millicode call.  */
-      if (TARGET_NO_SPACE_REGS || TARGET_FAST_INDIRECT_CALLS
-         || ! (flag_pic  || TARGET_PORTABLE_RUNTIME))
+      /* PIC long millicode call sequence.  */
+      if (flag_pic)
        {
          xoperands[0] = call_dest;
-         output_asm_insn ("ldil L%%%0,%%r31", xoperands);
-         output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%%r31)", xoperands);
+         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);
+
+         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);
+
+         /* Branch to our target which is in %r1.  */
+         output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
+
+         /* Empty delay slot.  Note this insn gets fetched twice and
+            executed once.  To be safe we use a nop.  */
          output_asm_insn ("nop", xoperands);
        }
       /* Pure portable runtime doesn't allow be/ble; we also don't have
-        PIC support inhe assembler/linker, so this sequence is needed.  */
+        PIC support in the assembler/linker, so this sequence is needed.  */
       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);
 
          /* Get our return address into %r31.  */
-         output_asm_insn ("blr %%r0,%%r31", xoperands);
+         output_asm_insn ("blr %%r0,%3", xoperands);
 
          /* Jump to our target address in %r29.  */
          output_asm_insn ("bv,n %%r0(%%r29)", xoperands);
@@ -5241,36 +6083,19 @@ output_millicode_call (insn, call_dest)
          /* Empty delay slot.  Note this insn gets fetched twice and
             executed once.  To be safe we use a nop.  */
          output_asm_insn ("nop", xoperands);
-         return "";
        }
-      /* PIC long millicode call sequence.  */
+      /* If we're allowed to use be/ble instructions, then this is the
+        best sequence to use for a long millicode call.  */
       else
        {
          xoperands[0] = call_dest;
-         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);
-
-         /* Get the return address into %r31.  */
-         output_asm_insn ("blr 0,%%r31", xoperands);
-
-         /* Branch to our target which is in %r1.  */
-         output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
-
-         /* Empty delay slot.  Note this insn gets fetched twice and
-            executed once.  To be safe we use a nop.  */
+         output_asm_insn ("ldil L%%%0,%3", xoperands);
+         output_asm_insn ("{ble|be,l} R%%%0(%%sr4,%3)", xoperands);
          output_asm_insn ("nop", xoperands);
        }
 
       /* 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);
@@ -5290,8 +6115,8 @@ output_millicode_call (insn, call_dest)
   /* Use the containing sequence insn's address.  */
   seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
 
-  distance = insn_addresses[INSN_UID (JUMP_LABEL (NEXT_INSN (insn)))]
-              - insn_addresses[INSN_UID (seq_insn)] - 8;
+  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.
@@ -5302,11 +6127,11 @@ output_millicode_call (insn, call_dest)
   xoperands[0] = call_dest;
   xoperands[1] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
   if (! VAL_14_BITS_P (distance))
-    output_asm_insn ("{bl|b,l} %0,%%r31\n\tnop\n\tb,n %1", xoperands);
+    output_asm_insn ("{bl|b,l} %0,%3\n\tnop\n\tb,n %1", xoperands);
   else
     {
       xoperands[2] = gen_label_rtx ();
-      output_asm_insn ("\n\t{bl|b,l} %0,%%r31\n\tldo %1-%2(%%r31),%%r31",
+      output_asm_insn ("\n\t{bl|b,l} %0,%3\n\tldo %1-%2(%3),%3",
                       xoperands);
       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
                                 CODE_LABEL_NUMBER (xoperands[2]));
@@ -5320,20 +6145,20 @@ output_millicode_call (insn, call_dest)
 }
 
 extern struct obstack permanent_obstack;
-extern struct obstack *saveable_obstack;
-extern struct obstack *rtl_obstack;
-extern struct obstack *current_obstack;
 
 /* INSN is either a function call.  It may have an unconditional jump
    in its delay slot.
 
    CALL_DEST is the routine we are calling.  */
 
-char *
-output_call (insn, call_dest)
+const char *
+output_call (insn, call_dest, sibcall)
   rtx insn;
   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;
@@ -5341,19 +6166,19 @@ output_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)
-      || (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;
-      output_asm_insn ("{bl|b,l} %0,%%r2%#", xoperands);
+      xoperands[1] = gen_rtx_REG (word_mode, sibcall ? 0 : 2);
+      output_asm_insn ("{bl|b,l} %0,%1%#", xoperands);
       return "";
     }
 
   /* 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];
@@ -5366,7 +6191,7 @@ output_call (insn, call_dest)
         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
@@ -5422,7 +6247,7 @@ output_call (insn, call_dest)
         we don't have any direct calls in that case.  */
        {
          int i;
-         char *name = XSTR (call_dest, 0);
+         const char *name = XSTR (call_dest, 0);
 
          /* See if we have already put this function on the list
             of deferred plabels.  This list is generally small,
@@ -5436,16 +6261,8 @@ output_call (insn, call_dest)
             not found on the list, create a new entry on the list.  */
          if (deferred_plabels == NULL || i == n_deferred_plabels)
            {
-             struct obstack *ambient_obstack = current_obstack;
-             struct obstack *ambient_rtl_obstack = rtl_obstack;
              const char *real_name;
 
-             /* Any RTL we create here needs to live until the end of
-                the compilation unit and therefore must live on the
-                permanent obstack.  */
-             current_obstack = &permanent_obstack;
-             rtl_obstack = &permanent_obstack;
-
              if (deferred_plabels == 0)
                deferred_plabels = (struct deferred_plabel *)
                  xmalloc (1 * sizeof (struct deferred_plabel));
@@ -5461,10 +6278,6 @@ output_call (insn, call_dest)
                                                        strlen (name) + 1);
              strcpy (deferred_plabels[i].name, name);
 
-             /* Switch back to normal obstack allocation.  */
-             current_obstack = ambient_obstack;
-             rtl_obstack = ambient_rtl_obstack;
-
              /* Gross.  We have just implicitly taken the address of this
                 function, mark it as such.  */
              STRIP_NAME_ENCODING (real_name, name);
@@ -5478,7 +6291,8 @@ output_call (insn, call_dest)
          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);
@@ -5487,11 +6301,21 @@ output_call (insn, call_dest)
              /* 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);
@@ -5499,8 +6323,17 @@ output_call (insn, call_dest)
              /* Branch to our target which is in %r1.  */
              output_asm_insn ("bv %%r0(%%r1)", xoperands);
 
-             /* Copy the return address into %r2 also.  */
-             output_asm_insn ("copy %%r31,%%r2", xoperands);
+             if (sibcall)
+               {
+                 /* This call never returns, so we do not need to fix the
+                    return pointer.  */
+                 output_asm_insn ("nop", xoperands);
+               }
+             else
+               {
+                 /* Copy the return address into %r2 also.  */
+                 output_asm_insn ("copy %%r31,%%r2", xoperands);
+               }
            }
          else
            {
@@ -5516,14 +6349,22 @@ output_call (insn, call_dest)
              output_asm_insn ("{ble|be,l}  R%%$$dyncall(%%sr4,%%r2)",
                               xoperands);
 
-             /* Copy the return pointer into both %r31 and %r2.  */
-             output_asm_insn ("copy %%r31,%%r2", xoperands);
+             if (sibcall)
+               {
+                 /* This call never returns, so we do not need to fix the
+                    return pointer.  */
+                 output_asm_insn ("nop", xoperands);
+               }
+             else
+               {
+                 /* Copy the return address into %r2 also.  */
+                 output_asm_insn ("copy %%r31,%%r2", xoperands);
+               }
            }
        }
 
       /* 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);
@@ -5543,14 +6384,12 @@ output_call (insn, call_dest)
   /* Use the containing sequence insn's address.  */
   seq_insn = NEXT_INSN (PREV_INSN (XVECEXP (final_sequence, 0, 0)));
 
-  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.
+  distance = INSN_ADDRESSES (INSN_UID (JUMP_LABEL (NEXT_INSN (insn))))
+              - INSN_ADDRESSES (INSN_UID (seq_insn)) - 8;
 
-     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);
@@ -5575,30 +6414,26 @@ output_call (insn, call_dest)
 /* In HPUX 8.0's shared library scheme, special relocations are needed
    for function labels if they might be passed to a function
    in a shared library (because shared libraries don't live in code
-   space), and special magic is needed to construct their address.
-
-   For reasons too disgusting to describe storage for the new name
-   is allocated either on the saveable_obstack (released at function
-   exit) or on the permanent_obstack for things that can never change
-   (libcall names for example). */
+   space), and special magic is needed to construct their address.  */
 
 void
-hppa_encode_label (sym, permanent)
+hppa_encode_label (sym)
      rtx sym;
-     int permanent;
 {
-  char *str = XSTR (sym, 0);
-  int len = strlen (str);
-  char *newstr;
-
-  newstr = obstack_alloc ((permanent ? &permanent_obstack : saveable_obstack),
-                         len + 2);
+  const char *str = XSTR (sym, 0);
+  int len = strlen (str) + 1;
+  char *newstr, *p;
 
+  p = newstr = alloca (len + 1);
   if (str[0] == '*')
-    *newstr++ = *str++;
-  strcpy (newstr + 1, str);
-  *newstr = '@';
-  XSTR (sym,0) = newstr;
+    {
+      str++;
+      len--;
+    }
+  *p++ = '@';
+  strcpy (p, str);
+
+  XSTR (sym, 0) = ggc_alloc_string (newstr, len);
 }
 
 int
@@ -5672,12 +6507,12 @@ fmpyaddoperands (operands)
 
   /* SFmode limits the registers to the upper 32 of the 32bit FP regs.  */
   if (mode == SFmode
-      && (REGNO (operands[0]) < 57
-         || REGNO (operands[1]) < 57
-         || REGNO (operands[2]) < 57
-         || REGNO (operands[3]) < 57
-         || REGNO (operands[4]) < 57
-         || REGNO (operands[5]) < 57))
+      && (REGNO_REG_CLASS (REGNO (operands[0])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[1])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[2])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[3])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[4])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[5])) != FPUPPER_REGS))
     return 0;
 
   /* Passed.  Operands are suitable for fmpyadd.  */
@@ -5729,12 +6564,12 @@ fmpysuboperands (operands)
 
   /* SFmode limits the registers to the upper 32 of the 32bit FP regs.  */
   if (mode == SFmode
-      && (REGNO (operands[0]) < 57
-         || REGNO (operands[1]) < 57
-         || REGNO (operands[2]) < 57
-         || REGNO (operands[3]) < 57
-         || REGNO (operands[4]) < 57
-         || REGNO (operands[5]) < 57))
+      && (REGNO_REG_CLASS (REGNO (operands[0])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[1])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[2])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[3])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[4])) != FPUPPER_REGS
+         || REGNO_REG_CLASS (REGNO (operands[5])) != FPUPPER_REGS))
     return 0;
 
   /* Passed.  Operands are suitable for fmpysub.  */
@@ -5785,35 +6620,21 @@ basereg_operand (op, mode)
   if (!cse_not_expected)
     return 0;
 
-  /* Once reload has started everything is considered valid.  Reload should
-     only create indexed addresses using the stack/frame pointer, and any
-     others were checked for validity when created by the combine pass. 
-
-     Also allow any register when TARGET_NO_SPACE_REGS is in effect since
-     we don't have to worry about the braindamaged implicit space register
-     selection using the basereg only (rather than effective address)
-     screwing us over.  */
-  if (TARGET_NO_SPACE_REGS || reload_in_progress || reload_completed)
+  /* Allow any register when TARGET_NO_SPACE_REGS is in effect since
+     we don't have to worry about the braindamaged implicit space
+     register selection from the basereg.  */
+  if (TARGET_NO_SPACE_REGS)
     return (GET_CODE (op) == REG);
 
-  /* Stack is always OK for indexing.  */
-  if (op == stack_pointer_rtx)
-    return 1;
-
   /* While it's always safe to index off the frame pointer, it's not
      always profitable, particularly when the frame pointer is being
      eliminated.  */
   if (! flag_omit_frame_pointer && op == frame_pointer_rtx)
     return 1;
 
-  /* The only other valid OPs are pseudo registers with
-     REGNO_POINTER_FLAG set.  */
-  if (GET_CODE (op) != REG
-      || REGNO (op) < FIRST_PSEUDO_REGISTER
-      || ! register_operand (op, mode))
-    return 0;
-    
-  return REGNO_POINTER_FLAG (REGNO (op));
+  return (GET_CODE (op) == REG
+          && REG_POINTER (op)
+          && register_operand (op, mode));
 }
 
 /* Return 1 if this operand is anything other than a hard register.  */
@@ -5827,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;
@@ -5889,7 +6710,7 @@ jump_in_call_delay (insn)
 
 /* Output an unconditional move and branch insn.  */
 
-char *
+const char *
 output_parallel_movb (operands, length)
      rtx *operands;
      int length;
@@ -5920,7 +6741,7 @@ output_parallel_movb (operands, length)
 
 /* Output an unconditional add and branch insn.  */
 
-char *
+const char *
 output_parallel_addb (operands, length)
      rtx *operands;
      int length;
@@ -5948,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.  */
@@ -5985,97 +6804,6 @@ following_call (insn)
   return 0;
 }
 
-/* Restore any INSN_CODEs for insns with unscaled indexed addresses since
-   the INSN_CODE might be clobberd by rerecognition triggered by reorg.  */
-
-static void
-restore_unscaled_index_insn_codes (insns)
-     rtx insns;
-{
-  rtx insn;
-
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
-    {
-      if (INSN_UID (insn) < max_unscaled_index_insn_codes_uid
-         && unscaled_index_insn_codes[INSN_UID (insn)] != -1)
-       INSN_CODE (insn) = unscaled_index_insn_codes[INSN_UID (insn)];
-    }
-}
-
-/* Severe braindamage:
-
-   On the PA, address computations within MEM expressions are not
-   commutative because of the implicit space register selection
-   from the base register (instead of the entire effective address).
-
-   Because of this mis-feature we have to know which register in a reg+reg
-   address is the base and which is the index.
-
-   Before reload, the base can be identified by REGNO_POINTER_FLAG.  We use
-   this to force base + index addresses to match a different insn than
-   index + base addresses.
-
-   We assume that no pass during or after reload creates new unscaled indexed
-   addresses, so any unscaled indexed address we find after reload must have
-   at one time been recognized a base + index or index + base and we accept
-   any register as a base register.
-
-   This scheme assumes that no pass during/after reload will rerecognize an
-   insn with an unscaled indexed address.  This failed due to a reorg call
-   to rerecognize certain insns.
-
-   So, we record if an insn uses an unscaled indexed address and which
-   register is the base (via recording of the INSN_CODE for such insns).
-
-   Just before we output code for the function, we make sure all the insns
-   using unscaled indexed addresses have the same INSN_CODE as they did
-   immediately before delay slot scheduling.
-
-   This is extremely gross.  Long term, I'd like to be able to look at
-   REG_POINTER_FLAG to handle these kinds of problems.  */
-static void
-record_unscaled_index_insn_codes (insns)
-     rtx insns;
-{
-  rtx insn;
-
-  max_unscaled_index_insn_codes_uid = get_max_uid ();
-  unscaled_index_insn_codes
-    = (int *)xmalloc (max_unscaled_index_insn_codes_uid * sizeof (int));
-  memset (unscaled_index_insn_codes, -1,
-         max_unscaled_index_insn_codes_uid * sizeof (int));
-
-  for (insn = insns; insn; insn = NEXT_INSN (insn))
-    {
-      rtx set = single_set (insn);
-      rtx mem = NULL_RTX;
-
-      /* Ignore anything that isn't a normal SET.  */
-      if (set == NULL_RTX)
-       continue;
-
-      /* No insns can have more than one MEM.  */
-      if (GET_CODE (SET_SRC (set)) == MEM)
-       mem = SET_SRC (set);
-
-      if (GET_CODE (SET_DEST (set)) == MEM)
-       mem = SET_DEST (set);
-       
-      /* If neither operand is a mem, then there's nothing to do.  */
-      if (mem == NULL_RTX)
-       continue;
-
-      if (GET_CODE (XEXP (mem, 0)) != PLUS)
-       continue;
-
-      /* If both are REGs (or SUBREGs), then record the insn code for
-        this insn.  */
-      if (REG_P (XEXP (XEXP (mem, 0), 0)) && REG_P (XEXP (XEXP (mem, 0), 1)))
-        unscaled_index_insn_codes[INSN_UID (insn)] = INSN_CODE (insn);
-    }
-}
-
 /* We use this hook to perform a PA specific optimization which is difficult
    to do in earlier passes.
 
@@ -6097,10 +6825,10 @@ record_unscaled_index_insn_codes (insns)
    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
@@ -6115,10 +6843,6 @@ pa_reorg (insns)
 {
   rtx insn;
 
-  /* Keep track of which insns have unscaled indexed addresses, and which
-     register is the base address in such insns.  */
-  record_unscaled_index_insn_codes (insns);
-
   remove_useless_addtr_insns (insns, 1);
 
   if (pa_cpu < PROCESSOR_8000)
@@ -6400,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.  */
@@ -6424,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;
                    }
                }
@@ -6482,7 +7208,7 @@ pa_combine_instructions (insns)
     }
 }
 
-int
+static int
 pa_can_combine_p (new, anchor, floater, reversed, dest, src1, src2)
      rtx new, anchor, floater;
      int reversed;
@@ -6503,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 (insn_code_number, 1))
+      || (extract_insn (new), ! constrain_operands (1)))
     return 0;
 
   if (reversed)
@@ -6544,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.
+
+   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.
 
-   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.
+   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
@@ -6558,13 +7290,260 @@ 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
           && get_attr_type (insn) == TYPE_MILLI));
 }
 
+/* Return the location of a parameter that is passed in a register or NULL
+   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.
+
+   ??? We might want to restructure this so that it looks more like other
+   ports.  */
+rtx
+function_arg (cum, mode, type, named, incoming)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named ATTRIBUTE_UNUSED;
+     int incoming;
+{
+  int max_arg_words = (TARGET_64BIT ? 8 : 4);
+  int fpr_reg_base;
+  int gpr_reg_base;
+  rtx retval;
+
+  if (! TARGET_64BIT)
+    {
+      /* If this arg would be passed partially or totally on the stack, then
+         this routine should return zero.  FUNCTION_ARG_PARTIAL_NREGS will
+         handle arguments which are split between regs and stack slots if
+         the ABI mandates split arguments.  */
+      if (cum->words + FUNCTION_ARG_SIZE (mode, type) > max_arg_words
+          || mode == VOIDmode)
+       return NULL_RTX;
+    }
+  else
+    {
+      int offset = 0;
+      if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
+       offset = 1;
+      if (cum->words + offset >= max_arg_words
+         || mode == VOIDmode)
+       return NULL_RTX;
+    }
+
+  /* The 32bit ABIs and the 64bit ABIs are rather different,
+     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.
+
+     The 64bit code probably is very wrong for structure passing.  */
+  if (TARGET_64BIT)
+    {
+      /* Advance the base registers to their current locations.
+
+         Remember, gprs grow towards smaller register numbers while
+        fprs grow to higher register numbers.  Also remember FP regs
+        are always 4 bytes wide, while the size of an integer register
+        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)
+       {
+         if (mode != BLKmode)
+           {
+             /* First deal with alignment of the doubleword.  */
+             gpr_reg_base -= (cum->words & 1);
+
+             /* This seems backwards, but it is what HP specifies.  We need
+                gpr_reg_base to point to the smaller numbered register of
+                the integer register pair.  So if we have an even register
+                 number, then decrement the gpr base.  */
+             gpr_reg_base -= ((gpr_reg_base % 2) == 0);
+
+             /* FP values behave sanely, except that each FP reg is only
+                half of word.  */
+             fpr_reg_base += ((fpr_reg_base % 2) == 0);
+            }
+         else
+           {
+             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)));
+             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));
+                 gpr_reg_base -= 1;
+                 offset += 8;
+               }
+             if (ub == 0)
+               return NULL_RTX;
+             else if (ub == 1)
+               return XEXP (loc[0], 0);
+             else
+               return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
+           }
+       }
+    }
+  else
+    {
+      /* If the argument is larger than a word, then we know precisely
+        which registers we must use.  */
+      if (FUNCTION_ARG_SIZE (mode, type) > 1)
+       {
+         if (cum->words)
+           {
+             gpr_reg_base = 23;
+             fpr_reg_base = 38;
+           }
+         else
+           {
+             gpr_reg_base = 25;
+             fpr_reg_base = 34;
+           }
+       }
+      else
+        {
+          /* We have a single word (32 bits).  A simple computation
+             will get us the register #s we need.  */
+          gpr_reg_base = 26 - cum->words;
+          fpr_reg_base = 32 + 2 * cum->words;
+       }
+    }
+
+  if (TARGET_64BIT && mode == TFmode)
+    {
+      return
+       gen_rtx_PARALLEL
+         (mode,
+          gen_rtvec (2,
+                     gen_rtx_EXPR_LIST (VOIDmode,
+                                        gen_rtx_REG (DImode, gpr_reg_base + 1),
+                                        const0_rtx),
+                     gen_rtx_EXPR_LIST (VOIDmode,
+                                        gen_rtx_REG (DImode, gpr_reg_base),
+                                        GEN_INT (8))));
+    }
+  /* 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)
+      /* 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
+           (mode,
+            gen_rtvec (2,
+                       gen_rtx_EXPR_LIST (VOIDmode,
+                                          gen_rtx_REG (mode, fpr_reg_base),
+                                          const0_rtx),
+                       gen_rtx_EXPR_LIST (VOIDmode,
+                                          gen_rtx_REG (mode, gpr_reg_base),
+                                          const0_rtx)));
+    }
+  else
+    {
+      /* See if we should pass this parameter in a general register.  */
+      if (TARGET_SOFT_FLOAT
+         /* Indirect calls in the normal 32bit ABI require all arguments
+            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.  */
+         || !FLOAT_MODE_P (mode))
+       retval = gen_rtx_REG (mode, gpr_reg_base);
+      else
+       retval = gen_rtx_REG (mode, fpr_reg_base);
+    }
+  return retval;
+}
+
+
+/* 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.  */
+int
+function_arg_partial_nregs (cum, mode, type, named)
+     CUMULATIVE_ARGS *cum;
+     enum machine_mode mode;
+     tree type;
+     int named ATTRIBUTE_UNUSED;
+{
+  unsigned int max_arg_words = 8;
+  unsigned int offset = 0;
+
+  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.  */
+    return 0;
+  else if (cum->words + offset >= max_arg_words)
+    /* Arg fully on the stack.  */
+    return 0;
+  else
+    /* Arg is split.  */
+    return max_arg_words - cum->words - offset;
+}
+
+
+/* Return 1 if this is a comparison operator.  This allows the use of
+   MATCH_OPERATOR to recognize all the branch insns.  */
+
+int
+cmpib_comparison_operator (op, mode)
+    register rtx op;
+    enum machine_mode mode;
+{
+  return ((mode == VOIDmode || GET_MODE (op) == mode)
+          && (GET_CODE (op) == EQ
+             || GET_CODE (op) == NE
+             || GET_CODE (op) == GT
+             || GET_CODE (op) == GTU
+             || GET_CODE (op) == GE
+             || GET_CODE (op) == LT
+             || GET_CODE (op) == LE
+             || GET_CODE (op) == LEU));
+}
+
 /* Mark ARG (which is really a struct deferred_plabel **) for GC.  */
 
 static void
@@ -6581,12 +7560,38 @@ 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);
   ggc_add_rtx_root (&hppa_compare_op1, 1);
-  ggc_add_rtx_root (&hp_profile_label_rtx, 1);
   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 ();
+}