OSDN Git Service

PR target/33062
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index ebe7a52..47de208 100644 (file)
@@ -1,13 +1,13 @@
 /* Subroutines for insn-output.c for HPPA.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -47,9 +46,7 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
-
-#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 
-#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hook_int_void_1
+#include "df.h"
 
 /* Return nonzero if there is a bypass for the output of 
    OUT_INSN and the fp store IN_INSN.  */
@@ -61,7 +58,8 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
   rtx set;
 
   if (recog_memoized (in_insn) < 0
-      || get_attr_type (in_insn) != TYPE_FPSTORE
+      || (get_attr_type (in_insn) != TYPE_FPSTORE
+         && get_attr_type (in_insn) != TYPE_FPSTORE_LOAD)
       || recog_memoized (out_insn) < 0)
     return 0;
 
@@ -87,6 +85,7 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
 
 static void copy_reg_pointer (rtx, rtx);
 static void fix_range (const char *);
+static bool pa_handle_option (size_t, const char *, int);
 static int hppa_address_cost (rtx);
 static bool hppa_rtx_costs (rtx, int, int, int *);
 static inline rtx force_mode (enum machine_mode, rtx);
@@ -94,7 +93,6 @@ static void pa_reorg (void);
 static void pa_combine_instructions (void);
 static int pa_can_combine_p (rtx, rtx, rtx, int, rtx, rtx, rtx);
 static int forward_branch_p (rtx);
-static int shadd_constant_p (int);
 static void compute_zdepwi_operands (unsigned HOST_WIDE_INT, unsigned *);
 static int compute_movmem_length (rtx);
 static int compute_clrmem_length (rtx);
@@ -110,7 +108,8 @@ static void pa_output_function_epilogue (FILE *, HOST_WIDE_INT);
 static int pa_adjust_cost (rtx, rtx, rtx, int);
 static int pa_adjust_priority (rtx, int);
 static int pa_issue_rate (void);
-static void pa_select_section (tree, int, unsigned HOST_WIDE_INT)
+static void pa_som_asm_init_sections (void) ATTRIBUTE_UNUSED;
+static section *pa_select_section (tree, int, unsigned HOST_WIDE_INT)
      ATTRIBUTE_UNUSED;
 static void pa_encode_section_info (tree, rtx, int);
 static const char *pa_strip_name_encoding (const char *);
@@ -126,10 +125,10 @@ static void pa_asm_out_destructor (rtx, int);
 static void pa_init_builtins (void);
 static rtx hppa_builtin_saveregs (void);
 static tree hppa_gimplify_va_arg_expr (tree, tree, tree *, tree *);
+static bool pa_scalar_mode_supported_p (enum machine_mode);
+static bool pa_commutative_p (const_rtx x, int outer_code);
 static void copy_fp_args (rtx) ATTRIBUTE_UNUSED;
 static int length_fp_args (rtx) ATTRIBUTE_UNUSED;
-static struct deferred_plabel *get_plabel (const char *)
-     ATTRIBUTE_UNUSED;
 static inline void pa_file_start_level (void) ATTRIBUTE_UNUSED;
 static inline void pa_file_start_space (int) ATTRIBUTE_UNUSED;
 static inline void pa_file_start_file (int) ATTRIBUTE_UNUSED;
@@ -140,38 +139,48 @@ static void pa_linux_file_start (void) ATTRIBUTE_UNUSED;
 static void pa_hpux64_gas_file_start (void) ATTRIBUTE_UNUSED;
 static void pa_hpux64_hpas_file_start (void) ATTRIBUTE_UNUSED;
 static void output_deferred_plabels (void);
+static void output_deferred_profile_counters (void) ATTRIBUTE_UNUSED;
+#ifdef ASM_OUTPUT_EXTERNAL_REAL
+static void pa_hpux_file_end (void);
+#endif
 #ifdef HPUX_LONG_DOUBLE_LIBRARY
 static void pa_hpux_init_libfuncs (void);
 #endif
 static rtx pa_struct_value_rtx (tree, int);
-static bool pa_pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode,
-                                 tree, bool);
-
+static bool pa_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
+                                 const_tree, bool);
+static int pa_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                tree, bool);
+static struct machine_function * pa_init_machine_status (void);
+static enum reg_class pa_secondary_reload (bool, rtx, enum reg_class,
+                                          enum machine_mode,
+                                          secondary_reload_info *);
+static void pa_extra_live_on_entry (bitmap);
+
+/* The following extra sections are only used for SOM.  */
+static GTY(()) section *som_readonly_data_section;
+static GTY(()) section *som_one_only_readonly_data_section;
+static GTY(()) section *som_one_only_data_section;
 
 /* Save the operands last given to a compare for use when we
    generate a scc or bcc insn.  */
 rtx hppa_compare_op0, hppa_compare_op1;
 enum cmp_type hppa_branch_type;
 
-/* Which architecture we are generating code for.  */
-enum architecture_type pa_arch;
-
-/* String to hold which architecture we are generating code for.  */
-const char *pa_arch_string;
-
-/* String used with the -mfixed-range= option.  */
-const char *pa_fixed_range_string;
-
 /* Which cpu we are scheduling for.  */
-enum processor_type pa_cpu;
+enum processor_type pa_cpu = TARGET_SCHED_DEFAULT;
 
-/* String to hold which cpu we are scheduling for.  */
-const char *pa_cpu_string;
+/* The UNIX standard to use for predefines and linking.  */
+int flag_pa_unix = TARGET_HPUX_11_11 ? 1998 : TARGET_HPUX_10_10 ? 1995 : 1993;
 
 /* 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;
 
+/* Boolean indicating whether the return pointer was saved by the
+   current function's prologue.  */
+static bool rp_saved;
+
 static rtx find_addr_reg (rtx);
 
 /* Keep track of the number of bytes we have output in the CODE subspace
@@ -188,7 +197,7 @@ static int last_address;
 struct deferred_plabel GTY(())
 {
   rtx internal_label;
-  const char *name;
+  rtx symbol;
 };
 static GTY((length ("n_deferred_plabels"))) struct deferred_plabel *
   deferred_plabels;
@@ -232,13 +241,20 @@ static size_t n_deferred_plabels = 0;
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL pa_function_ok_for_sibcall
 
+#undef TARGET_COMMUTATIVE_P
+#define TARGET_COMMUTATIVE_P pa_commutative_p
+
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK pa_asm_output_mi_thunk
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
 
 #undef TARGET_ASM_FILE_END
+#ifdef ASM_OUTPUT_EXTERNAL_REAL
+#define TARGET_ASM_FILE_END pa_hpux_file_end
+#else
 #define TARGET_ASM_FILE_END output_deferred_plabels
+#endif
 
 #if !defined(USE_COLLECT2)
 #undef TARGET_ASM_CONSTRUCTOR
@@ -247,6 +263,11 @@ static size_t n_deferred_plabels = 0;
 #define TARGET_ASM_DESTRUCTOR pa_asm_out_destructor
 #endif
 
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | TARGET_CPU_DEFAULT)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION pa_handle_option
+
 #undef TARGET_INIT_BUILTINS
 #define TARGET_INIT_BUILTINS pa_init_builtins
 
@@ -264,9 +285,9 @@ static size_t n_deferred_plabels = 0;
 #endif
 
 #undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
 #undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
 
 #undef TARGET_STRUCT_VALUE_RTX
 #define TARGET_STRUCT_VALUE_RTX pa_struct_value_rtx
@@ -276,12 +297,28 @@ static size_t n_deferred_plabels = 0;
 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
 #undef TARGET_PASS_BY_REFERENCE
 #define TARGET_PASS_BY_REFERENCE pa_pass_by_reference
+#undef TARGET_CALLEE_COPIES
+#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES pa_arg_partial_bytes
 
 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
 #define TARGET_EXPAND_BUILTIN_SAVEREGS hppa_builtin_saveregs
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR hppa_gimplify_va_arg_expr
 
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P pa_scalar_mode_supported_p
+
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM pa_tls_referenced_p
+
+#undef TARGET_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD pa_secondary_reload
+
+#undef TARGET_EXTRA_LIVE_ON_ENTRY
+#define TARGET_EXTRA_LIVE_ON_ENTRY pa_extra_live_on_entry
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */
@@ -296,7 +333,7 @@ fix_range (const char *const_str)
      REG2 are either register names or register numbers.  The effect
      of this option is to mark the registers in the range from REG1 to
      REG2 as ``fixed'' so they won't be used by the compiler.  This is
-     used, e.g., to ensure that kernel mode code doesn't use f32-f127.  */
+     used, e.g., to ensure that kernel mode code doesn't use fr4-fr31.  */
 
   i = strlen (const_str);
   str = (char *) alloca (i + 1);
@@ -307,7 +344,7 @@ fix_range (const char *const_str)
       dash = strchr (str, '-');
       if (!dash)
        {
-         warning ("value of -mfixed-range must have form REG1-REG2");
+         warning (0, "value of -mfixed-range must have form REG1-REG2");
          return;
        }
       *dash = '\0';
@@ -319,14 +356,14 @@ fix_range (const char *const_str)
       first = decode_reg_name (str);
       if (first < 0)
        {
-         warning ("unknown register name: %s", str);
+         warning (0, "unknown register name: %s", str);
          return;
        }
 
       last = decode_reg_name (dash + 1);
       if (last < 0)
        {
-         warning ("unknown register name: %s", dash + 1);
+         warning (0, "unknown register name: %s", dash + 1);
          return;
        }
 
@@ -334,7 +371,7 @@ fix_range (const char *const_str)
 
       if (first > last)
        {
-         warning ("%s-%s is an empty range", str, dash + 1);
+         warning (0, "%s-%s is an empty range", str, dash + 1);
          return;
        }
 
@@ -357,75 +394,78 @@ fix_range (const char *const_str)
     target_flags |= MASK_DISABLE_FPREGS;
 }
 
-void
-override_options (void)
-{
-  if (pa_cpu_string == NULL)
-    pa_cpu_string = TARGET_SCHED_DEFAULT;
-
-  if (! strcmp (pa_cpu_string, "8000"))
-    {
-      pa_cpu_string = "8000";
-      pa_cpu = PROCESSOR_8000;
-    }
-  else if (! strcmp (pa_cpu_string, "7100"))
-    {
-      pa_cpu_string = "7100";
-      pa_cpu = PROCESSOR_7100;
-    }
-  else if (! strcmp (pa_cpu_string, "700"))
-    {
-      pa_cpu_string = "700";
-      pa_cpu = PROCESSOR_700;
-    }
-  else if (! strcmp (pa_cpu_string, "7100LC"))
-    {
-      pa_cpu_string = "7100LC";
-      pa_cpu = PROCESSOR_7100LC;
-    }
-  else if (! strcmp (pa_cpu_string, "7200"))
-    {
-      pa_cpu_string = "7200";
-      pa_cpu = PROCESSOR_7200;
-    }
-  else if (! strcmp (pa_cpu_string, "7300"))
-    {
-      pa_cpu_string = "7300";
-      pa_cpu = PROCESSOR_7300;
-    }
-  else
-    {
-      warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
-    }
+/* Implement TARGET_HANDLE_OPTION.  */
 
-  /* Set the instruction architecture.  */
-  if (pa_arch_string && ! strcmp (pa_arch_string, "1.0"))
+static bool
+pa_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
+{
+  switch (code)
     {
-      pa_arch_string = "1.0";
-      pa_arch = ARCHITECTURE_10;
+    case OPT_mnosnake:
+    case OPT_mpa_risc_1_0:
+    case OPT_march_1_0:
       target_flags &= ~(MASK_PA_11 | MASK_PA_20);
-    }
-  else if (pa_arch_string && ! strcmp (pa_arch_string, "1.1"))
-    {
-      pa_arch_string = "1.1";
-      pa_arch = ARCHITECTURE_11;
+      return true;
+
+    case OPT_msnake:
+    case OPT_mpa_risc_1_1:
+    case OPT_march_1_1:
       target_flags &= ~MASK_PA_20;
       target_flags |= MASK_PA_11;
-    }
-  else if (pa_arch_string && ! strcmp (pa_arch_string, "2.0"))
-    {
-      pa_arch_string = "2.0";
-      pa_arch = ARCHITECTURE_20;
+      return true;
+
+    case OPT_mpa_risc_2_0:
+    case OPT_march_2_0:
       target_flags |= MASK_PA_11 | MASK_PA_20;
-    }
-  else if (pa_arch_string)
-    {
-      warning ("unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
-    }
+      return true;
+
+    case OPT_mschedule_:
+      if (strcmp (arg, "8000") == 0)
+       pa_cpu = PROCESSOR_8000;
+      else if (strcmp (arg, "7100") == 0)
+       pa_cpu = PROCESSOR_7100;
+      else if (strcmp (arg, "700") == 0)
+       pa_cpu = PROCESSOR_700;
+      else if (strcmp (arg, "7100LC") == 0)
+       pa_cpu = PROCESSOR_7100LC;
+      else if (strcmp (arg, "7200") == 0)
+       pa_cpu = PROCESSOR_7200;
+      else if (strcmp (arg, "7300") == 0)
+       pa_cpu = PROCESSOR_7300;
+      else
+       return false;
+      return true;
+
+    case OPT_mfixed_range_:
+      fix_range (arg);
+      return true;
 
-  if (pa_fixed_range_string)
-    fix_range (pa_fixed_range_string);
+#if TARGET_HPUX
+    case OPT_munix_93:
+      flag_pa_unix = 1993;
+      return true;
+#endif
 
+#if TARGET_HPUX_10_10
+    case OPT_munix_95:
+      flag_pa_unix = 1995;
+      return true;
+#endif
+
+#if TARGET_HPUX_11_11
+    case OPT_munix_98:
+      flag_pa_unix = 1998;
+      return true;
+#endif
+
+    default:
+      return true;
+    }
+}
+
+void
+override_options (void)
+{
   /* 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.  */
@@ -436,18 +476,18 @@ override_options (void)
 
   if (flag_pic && TARGET_PORTABLE_RUNTIME)
     {
-      warning ("PIC code generation is not supported in the portable runtime model\n");
+      warning (0, "PIC code generation is not supported in the portable runtime model");
     }
 
   if (flag_pic && TARGET_FAST_INDIRECT_CALLS)
    {
-      warning ("PIC code generation is not compatible with fast indirect calls\n");
+      warning (0, "PIC code generation is not compatible with fast indirect calls");
    }
 
   if (! TARGET_GAS && write_symbols != NO_DEBUG)
     {
-      warning ("-g is only supported when using GAS on this processor,");
-      warning ("-g option disabled");
+      warning (0, "-g is only supported when using GAS on this processor,");
+      warning (0, "-g option disabled");
       write_symbols = NO_DEBUG;
     }
 
@@ -467,17 +507,37 @@ override_options (void)
       targetm.asm_out.unaligned_op.si = NULL;
       targetm.asm_out.unaligned_op.di = NULL;
     }
+
+  init_machine_status = pa_init_machine_status;
 }
 
 static void
 pa_init_builtins (void)
 {
 #ifdef DONT_HAVE_FPUTC_UNLOCKED
-  built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED] = NULL_TREE;
-  implicit_built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED] = NULL_TREE;
+  built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED] =
+    built_in_decls[(int) BUILT_IN_PUTC_UNLOCKED];
+  implicit_built_in_decls[(int) BUILT_IN_FPUTC_UNLOCKED]
+    = implicit_built_in_decls[(int) BUILT_IN_PUTC_UNLOCKED];
+#endif
+#if TARGET_HPUX_11
+  if (built_in_decls [BUILT_IN_FINITE])
+    set_user_assembler_name (built_in_decls [BUILT_IN_FINITE], "_Isfinite");
+  if (built_in_decls [BUILT_IN_FINITEF])
+    set_user_assembler_name (built_in_decls [BUILT_IN_FINITEF], "_Isfinitef");
 #endif
 }
 
+/* Function to init struct machine_function.
+   This will be called, via a pointer variable,
+   from push_function_context.  */
+
+static struct machine_function *
+pa_init_machine_status (void)
+{
+  return ggc_alloc_cleared (sizeof (machine_function));
+}
+
 /* If FROM is a probable pointer register, mark TO as a probable
    pointer register with the same pointer alignment as FROM.  */
 
@@ -488,26 +548,6 @@ copy_reg_pointer (rtx to, rtx from)
     mark_reg_pointer (to, REGNO_POINTER_ALIGN (REGNO (from)));
 }
 
-/* Return nonzero only if OP is a register of mode MODE,
-   or CONST0_RTX.  */
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  return (op == CONST0_RTX (mode) || register_operand (op, mode));
-}
-
-/* Return nonzero if OP is suitable for use in a call to a named
-   function.
-
-   For 2.5 try to eliminate either call_operand_address or
-   function_label_operand, they perform very similar functions.  */
-int
-call_operand_address (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_MODE (op) == word_mode
-         && CONSTANT_P (op) && ! TARGET_PORTABLE_RUNTIME);
-}
-
 /* Return 1 if X contains a symbolic expression.  We know these
    expressions will have one of a few well defined forms, so
    we need only check those forms.  */
@@ -522,262 +562,17 @@ symbolic_expression_p (rtx x)
   return (symbolic_operand (x, VOIDmode));
 }
 
-int
-symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-    case CONST:
-      op = XEXP (op, 0);
-      return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
-              || GET_CODE (XEXP (op, 0)) == LABEL_REF)
-             && GET_CODE (XEXP (op, 1)) == CONST_INT);
-    default:
-      return 0;
-    }
-}
-
-/* Return truth value of statement that OP is a symbolic memory
-   operand of mode MODE.  */
-
-int
-symbolic_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) != MEM)
-    return 0;
-  op = XEXP (op, 0);
-  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST
-         || GET_CODE (op) == HIGH || GET_CODE (op) == LABEL_REF);
-}
-
-/* Return 1 if the operand is either a register, zero, or a memory operand
-   that is not symbolic.  */
-
-int
-reg_or_0_or_nonsymb_mem_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-
-  if (op == CONST0_RTX (mode))
-    return 1;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  if (GET_CODE (op) != MEM)
-    return 0;
-
-  /* Until problems with management of the REG_POINTER flag are resolved,
-     we need to delay creating move insns with unscaled indexed addresses
-     until CSE is not expected.  */
-  if (!TARGET_NO_SPACE_REGS
-      && !cse_not_expected
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && REG_P (XEXP (XEXP (op, 0), 0))
-      && REG_P (XEXP (XEXP (op, 0), 1)))
-    return 0;
-
-  return (!symbolic_memory_operand (op, mode)
-         && memory_address_p (mode, XEXP (op, 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 (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 instruction into a
    general register.  */
 int
-cint_ok_for_move (HOST_WIDE_INT intval)
+cint_ok_for_move (HOST_WIDE_INT ival)
 {
   /* OK if ldo, ldil, or zdepi, can be used.  */
-  return (CONST_OK_FOR_LETTER_P (intval, 'J')
-         || CONST_OK_FOR_LETTER_P (intval, 'N')
-         || CONST_OK_FOR_LETTER_P (intval, 'K'));
-}
-
-/* Return 1 iff OP is an indexed memory operand.  */
-int
-indexed_memory_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode)
-    return 0;
-
-  /* Before reload, a (SUBREG (MEM...)) forces reloading into a register.  */
-  if (reload_completed && GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
-    return 0;
-
-  op = XEXP (op, 0);
-
-  return (memory_address_p (mode, op) && IS_INDEX_ADDR_P (op));
-}
-
-/* Accept anything that can be used as a destination operand for a
-   move instruction.  We don't accept indexed memory operands since
-   they are supported only for floating point stores.  */
-int
-move_dest_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-
-  if (GET_MODE (op) != mode)
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  if (GET_CODE (op) != MEM || symbolic_memory_operand (op, mode))
-    return 0;
-
-  op = XEXP (op, 0);
-
-  return (memory_address_p (mode, op)
-         && !IS_INDEX_ADDR_P (op)
-         && !IS_LO_SUM_DLT_ADDR_P (op));
-}
-
-/* Accept anything that can be used as a source operand for a move
-   instruction.  */
-int
-move_src_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-
-  if (GET_CODE (op) == CONST_INT)
-    return cint_ok_for_move (INTVAL (op));
-
-  if (GET_MODE (op) != mode)
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  if (GET_CODE (op) != MEM)
-    return 0;
-
-  /* Until problems with management of the REG_POINTER flag are resolved,
-     we need to delay creating move insns with unscaled indexed addresses
-     until CSE is not expected.  */
-  if (!TARGET_NO_SPACE_REGS
-      && !cse_not_expected
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && REG_P (XEXP (XEXP (op, 0), 0))
-      && REG_P (XEXP (XEXP (op, 0), 1)))
-    return 0;
-
-  return memory_address_p (mode, XEXP (op, 0));
-}
-
-/* Accept anything that can be used as the source operand for a prefetch
-   instruction.  */
-int
-prefetch_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != MEM)
-    return 0;
-
-  /* Until problems with management of the REG_POINTER flag are resolved,
-     we need to delay creating prefetch insns with unscaled indexed addresses
-     until CSE is not expected.  */
-  if (!TARGET_NO_SPACE_REGS
-      && !cse_not_expected
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && REG_P (XEXP (XEXP (op, 0), 0))
-      && REG_P (XEXP (XEXP (op, 0), 1)))
-    return 0;
-
-  return memory_address_p (mode, XEXP (op, 0));
-}
-
-/* Accept REG and any CONST_INT that can be moved in one instruction into a
-   general register.  */
-int
-reg_or_cint_move_operand (rtx op, enum machine_mode mode)
-{
-  if (register_operand (op, mode))
-    return 1;
-
-  return (GET_CODE (op) == CONST_INT && cint_ok_for_move (INTVAL (op)));
+  return (VAL_14_BITS_P (ival)
+         || ldil_cint_p (ival)
+         || zdepi_cint_p (ival));
 }
-
-int
-pic_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (!flag_pic)
-    return 0;
-
-  switch (GET_CODE (op))
-    {
-    case LABEL_REF:
-      return 1;
-    case CONST:
-      op = XEXP (op, 0);
-      return (GET_CODE (XEXP (op, 0)) == LABEL_REF
-             && GET_CODE (XEXP (op, 1)) == CONST_INT);
-    default:
-      return 0;
-    }
-}
-
-int
-fp_reg_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return reg_renumber && FP_REG_P (op);
-}
-
 \f
-
-/* Return truth value of whether OP can be used as an operand in a
-   three operand arithmetic insn that accepts registers of mode MODE
-   or 14-bit signed integers.  */
-int
-arith_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && INT_14_BITS (op)));
-}
-
-/* Return truth value of whether OP can be used as an operand in a
-   three operand arithmetic insn that accepts registers of mode MODE
-   or 11-bit signed integers.  */
-int
-arith11_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && INT_11_BITS (op)));
-}
-
 /* Return truth value of whether OP can be used as an operand in a
    adddi3 insn.  */
 int
@@ -788,96 +583,38 @@ adddi3_operand (rtx op, enum machine_mode mode)
              && (TARGET_64BIT ? INT_14_BITS (op) : INT_11_BITS (op))));
 }
 
-/* A constant integer suitable for use in a PRE_MODIFY memory
-   reference.  */
+/* True iff the operand OP can be used as the destination operand of
+   an integer store.  This also implies the operand could be used as
+   the source operand of an integer load.  Symbolic, lo_sum and indexed
+   memory operands are not allowed.  We accept reloading pseudos and
+   other memory operands.  */
 int
-pre_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-         && INTVAL (op) >= -0x2000 && INTVAL (op) < 0x10);
-}
-
-/* A constant integer suitable for use in a POST_MODIFY memory
-   reference.  */
+integer_store_memory_operand (rtx op, enum machine_mode mode)
+{
+  return ((reload_in_progress
+          && REG_P (op)
+          && REGNO (op) >= FIRST_PSEUDO_REGISTER
+          && reg_renumber [REGNO (op)] < 0)
+         || (GET_CODE (op) == MEM
+             && (reload_in_progress || memory_address_p (mode, XEXP (op, 0)))
+             && !symbolic_memory_operand (op, VOIDmode)
+             && !IS_LO_SUM_DLT_ADDR_P (XEXP (op, 0))
+             && !IS_INDEX_ADDR_P (XEXP (op, 0))));
+}
+
+/* True iff ldil can be used to load this CONST_INT.  The least
+   significant 11 bits of the value must be zero and the value must
+   not change sign when extended from 32 to 64 bits.  */
 int
-post_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+ldil_cint_p (HOST_WIDE_INT ival)
 {
-  return (GET_CODE (op) == CONST_INT
-         && INTVAL (op) < 0x2000 && INTVAL (op) >= -0x10);
-}
+  HOST_WIDE_INT x = ival & (((HOST_WIDE_INT) -1 << 31) | 0x7ff);
 
-int
-arith_double_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_DOUBLE
-             && GET_MODE (op) == mode
-             && VAL_14_BITS_P (CONST_DOUBLE_LOW (op))
-             && ((CONST_DOUBLE_HIGH (op) >= 0)
-                 == ((CONST_DOUBLE_LOW (op) & 0x1000) == 0))));
-}
-
-/* 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.  */
-
-int
-ireg_or_int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return ((GET_CODE (op) == CONST_INT && INT_5_BITS (op))
-         || (GET_CODE (op) == REG && REGNO (op) > 0 && REGNO (op) < 32));
-}
-
-/* Return nonzero if OP is an integer register, else return zero.  */
-int
-ireg_operand (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
-int5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && INT_5_BITS (op));
-}
-
-int
-uint5_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && INT_U5_BITS (op));
-}
-
-int
-int11_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && INT_11_BITS (op));
-}
-
-int
-uint32_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-#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) < (HOST_WIDE_INT) 1 << 32));
-#else
-  return (GET_CODE (op) == CONST_INT
-         || (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_HIGH (op) == 0));
-#endif
-}
-
-int
-arith5_operand (rtx op, enum machine_mode mode)
-{
-  return register_operand (op, mode) || int5_operand (op, mode);
+  return x == 0 || x == ((HOST_WIDE_INT) -1 << 31);
 }
 
 /* True iff zdepi can be used to generate this CONST_INT.
-   zdepi first sign extends a 5 bit signed number to a given field
+   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 (unsigned HOST_WIDE_INT x)
@@ -905,14 +642,6 @@ and_mask_p (unsigned HOST_WIDE_INT mask)
   return (mask & (mask - 1)) == 0;
 }
 
-/* True iff depi or extru can be used to compute (reg & OP).  */
-int
-and_operand (rtx op, enum machine_mode mode)
-{
-  return (register_operand (op, mode)
-         || (GET_CODE (op) == CONST_INT && and_mask_p (INTVAL (op))));
-}
-
 /* True iff depi can be used to compute (reg | MASK).  */
 int
 ior_mask_p (unsigned HOST_WIDE_INT mask)
@@ -920,44 +649,6 @@ ior_mask_p (unsigned HOST_WIDE_INT mask)
   mask += mask & -mask;
   return (mask & (mask - 1)) == 0;
 }
-
-/* True iff depi can be used to compute (reg | OP).  */
-int
-ior_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && ior_mask_p (INTVAL (op)));
-}
-
-int
-lhs_lshift_operand (rtx op, enum machine_mode mode)
-{
-  return register_operand (op, mode) || lhs_lshift_cint_operand (op, mode);
-}
-
-/* True iff OP is a CONST_INT of the forms 0...0xxxx or 0...01...1xxxx.
-   Such values can be the left hand side x in (x << r), using the zvdepi
-   instruction.  */
-int
-lhs_lshift_cint_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  unsigned HOST_WIDE_INT x;
-  if (GET_CODE (op) != CONST_INT)
-    return 0;
-  x = INTVAL (op) >> 4;
-  return (x & (x + 1)) == 0;
-}
-
-int
-arith32_operand (rtx op, enum machine_mode mode)
-{
-  return register_operand (op, mode) || GET_CODE (op) == CONST_INT;
-}
-
-int
-pc_or_label_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == PC || GET_CODE (op) == LABEL_REF);
-}
 \f
 /* Legitimize PIC addresses.  If the address is already
    position-independent, we return ORIG.  Newly generated
@@ -969,6 +660,8 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 {
   rtx pic_ref = orig;
 
+  gcc_assert (!PA_SYMBOL_REF_TLS_P (orig));
+
   /* Labels need special handling.  */
   if (pic_label_operand (orig, mode))
     {
@@ -990,8 +683,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
     {
       rtx insn, tmp_reg;
 
-      if (reg == 0)
-       abort ();
+      gcc_assert (reg);
 
       /* Before reload, allocate a temporary register for the intermediate
         result.  This allows the sequence to be deleted when the final
@@ -1003,20 +695,18 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx 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, tmp_reg,
-                                      gen_rtx_UNSPEC (Pmode,
-                                                      gen_rtvec (1, orig),
-                                                      UNSPEC_DLTIND14R)));
+       = gen_const_mem (Pmode,
+                        gen_rtx_LO_SUM (Pmode, tmp_reg,
+                                        gen_rtx_UNSPEC (Pmode,
+                                                        gen_rtvec (1, orig),
+                                                        UNSPEC_DLTIND14R)));
 
       current_function_uses_pic_offset_table = 1;
-      MEM_NOTRAP_P (pic_ref) = 1;
-      RTX_UNCHANGING_P (pic_ref) = 1;
       mark_reg_pointer (reg, BITS_PER_UNIT);
       insn = emit_move_insn (reg, pic_ref);
 
       /* Put a REG_EQUAL note on this insn, so that it can be optimized.  */
-      REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig, REG_NOTES (insn));
+      set_unique_reg_note (insn, REG_EQUAL, orig);
 
       return reg;
     }
@@ -1028,17 +718,12 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
          && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
        return orig;
 
-      if (reg == 0)
-       abort ();
-
-      if (GET_CODE (XEXP (orig, 0)) == PLUS)
-       {
-         base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
-         orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
-                                        base == reg ? 0 : reg);
-       }
-      else
-       abort ();
+      gcc_assert (reg);
+      gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+      
+      base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+      orig = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+                                    base == reg ? 0 : reg);
 
       if (GET_CODE (orig) == CONST_INT)
        {
@@ -1050,7 +735,90 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
       /* Likewise, should we set special REG_NOTEs here?  */
     }
 
-  return pic_ref;
+  return pic_ref;
+}
+
+static GTY(()) rtx gen_tls_tga;
+
+static rtx
+gen_tls_get_addr (void)
+{
+  if (!gen_tls_tga)
+    gen_tls_tga = init_one_libfunc ("__tls_get_addr");
+  return gen_tls_tga;
+}
+
+static rtx
+hppa_tls_call (rtx arg)
+{
+  rtx ret;
+
+  ret = gen_reg_rtx (Pmode);
+  emit_library_call_value (gen_tls_get_addr (), ret,
+                          LCT_CONST, Pmode, 1, arg, Pmode);
+
+  return ret;
+}
+
+static rtx
+legitimize_tls_address (rtx addr)
+{
+  rtx ret, insn, tmp, t1, t2, tp;
+  enum tls_model model = SYMBOL_REF_TLS_MODEL (addr);
+
+  switch (model) 
+    {
+      case TLS_MODEL_GLOBAL_DYNAMIC:
+       tmp = gen_reg_rtx (Pmode);
+       if (flag_pic)
+         emit_insn (gen_tgd_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tgd_load (tmp, addr));
+       ret = hppa_tls_call (tmp);
+       break;
+
+      case TLS_MODEL_LOCAL_DYNAMIC:
+       ret = gen_reg_rtx (Pmode);
+       tmp = gen_reg_rtx (Pmode);
+       start_sequence ();
+       if (flag_pic)
+         emit_insn (gen_tld_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tld_load (tmp, addr));
+       t1 = hppa_tls_call (tmp);
+       insn = get_insns ();
+       end_sequence ();
+       t2 = gen_reg_rtx (Pmode);
+       emit_libcall_block (insn, t2, t1, 
+                           gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+                                           UNSPEC_TLSLDBASE));
+       emit_insn (gen_tld_offset_load (ret, addr, t2));
+       break;
+
+      case TLS_MODEL_INITIAL_EXEC:
+       tp = gen_reg_rtx (Pmode);
+       tmp = gen_reg_rtx (Pmode);
+       ret = gen_reg_rtx (Pmode);
+       emit_insn (gen_tp_load (tp));
+       if (flag_pic)
+         emit_insn (gen_tie_load_pic (tmp, addr));
+       else
+         emit_insn (gen_tie_load (tmp, addr));
+       emit_move_insn (ret, gen_rtx_PLUS (Pmode, tp, tmp));
+       break;
+
+      case TLS_MODEL_LOCAL_EXEC:
+       tp = gen_reg_rtx (Pmode);
+       ret = gen_reg_rtx (Pmode);
+       emit_insn (gen_tp_load (tp));
+       emit_insn (gen_tle_load (ret, addr, tp));
+       break;
+
+      default:
+       gcc_unreachable ();
+    }
+
+  return ret;
 }
 
 /* Try machine-dependent ways of modifying an illegitimate address
@@ -1081,7 +849,7 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
 
    This is for CSE to find several similar references, and only use one Z.
 
-   X can either be a SYMBOL_REF or REG, but because combine can not
+   X can either be a SYMBOL_REF or REG, but because combine cannot
    perform a 4->2 combination we do nothing for SYMBOL_REF + D where
    D will not fit in 14 bits.
 
@@ -1122,7 +890,9 @@ hppa_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
       && !REG_POINTER (XEXP (x, 1)))
     return gen_rtx_PLUS (Pmode, XEXP (x, 1), XEXP (x, 0));
 
-  if (flag_pic)
+  if (PA_SYMBOL_REF_TLS_P (x))
+    return legitimize_tls_address (x);
+  else if (flag_pic)
     return legitimize_pic_address (x, mode, gen_reg_rtx (Pmode));
 
   /* Strip off CONST.  */
@@ -1567,12 +1337,30 @@ force_mode (enum machine_mode mode, rtx orig)
   if (mode == GET_MODE (orig))
     return orig;
 
-  if (REGNO (orig) >= FIRST_PSEUDO_REGISTER)
-    abort ();
+  gcc_assert (REGNO (orig) < FIRST_PSEUDO_REGISTER);
 
   return gen_rtx_REG (mode, REGNO (orig));
 }
 
+/* Return 1 if *X is a thread-local symbol.  */
+
+static int
+pa_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+  return PA_SYMBOL_REF_TLS_P (*x);
+}
+
+/* Return 1 if X contains a thread-local symbol.  */
+
+bool
+pa_tls_referenced_p (rtx x)
+{
+  if (!TARGET_HAVE_TLS)
+    return false;
+
+  return for_each_rtx (&x, &pa_tls_symbol_ref_1, 0);
+}
+
 /* Emit insns to move operands[1] into operands[0].
 
    Return 1 if we have written out everything that needs to be done to
@@ -1595,9 +1383,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
      addresses from the destination operand.  */
   if (GET_CODE (operand0) == MEM && IS_INDEX_ADDR_P (XEXP (operand0, 0)))
     {
-      /* This is only safe up to the beginning of life analysis.  */
-      if (no_new_pseudos)
-       abort ();
+      gcc_assert (can_create_pseudo_p ());
 
       tem = copy_to_mode_reg (Pmode, XEXP (operand0, 0));
       operand0 = replace_equiv_address (operand0, tem);
@@ -1657,12 +1443,12 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
   if (scratch_reg && reload_in_progress && GET_CODE (operand0) == MEM
       && ((tem = find_replacement (&XEXP (operand0, 0)))
          != XEXP (operand0, 0)))
-    operand0 = gen_rtx_MEM (GET_MODE (operand0), tem);
+    operand0 = replace_equiv_address (operand0, tem);
 
   if (scratch_reg && reload_in_progress && GET_CODE (operand1) == MEM
       && ((tem = find_replacement (&XEXP (operand1, 0)))
          != XEXP (operand1, 0)))
-    operand1 = gen_rtx_MEM (GET_MODE (operand1), tem);
+    operand1 = replace_equiv_address (operand1, tem);
 
   /* Handle secondary reloads for loads/stores of FP registers from
      REG+D addresses where D does not fit in 5 or 14 bits, including
@@ -1700,7 +1486,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
       else
        emit_move_insn (scratch_reg, XEXP (operand1, 0));
       emit_insn (gen_rtx_SET (VOIDmode, operand0,
-                             gen_rtx_MEM (mode, scratch_reg)));
+                             replace_equiv_address (operand1, scratch_reg)));
       return 1;
     }
   else if (scratch_reg
@@ -1737,7 +1523,8 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
        }
       else
        emit_move_insn (scratch_reg, XEXP (operand0, 0));
-      emit_insn (gen_rtx_SET (VOIDmode, gen_rtx_MEM (mode, scratch_reg),
+      emit_insn (gen_rtx_SET (VOIDmode,
+                             replace_equiv_address (operand0, scratch_reg),
                              operand1));
       return 1;
     }
@@ -1754,7 +1541,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
           && CONSTANT_P (operand1)
           && fp_reg_operand (operand0, mode))
     {
-      rtx xoperands[2];
+      rtx const_mem, xoperands[2];
 
       /* 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
@@ -1763,13 +1550,14 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
 
       /* Force the constant into memory and put the address of the
         memory location into scratch_reg.  */
+      const_mem = force_const_mem (mode, operand1);
       xoperands[0] = scratch_reg;
-      xoperands[1] = XEXP (force_const_mem (mode, operand1), 0);
+      xoperands[1] = XEXP (const_mem, 0);
       emit_move_sequence (xoperands, Pmode, 0);
 
       /* Now load the destination register.  */
       emit_insn (gen_rtx_SET (mode, operand0,
-                             gen_rtx_MEM (mode, scratch_reg)));
+                             replace_equiv_address (const_mem, scratch_reg)));
       return 1;
     }
   /* Handle secondary reloads for SAR.  These occur when trying to load
@@ -1806,8 +1594,8 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
             OPERAND0.  */
          scratch_reg = force_mode (GET_MODE (operand0), scratch_reg);
 
-         emit_move_insn (scratch_reg, gen_rtx_MEM (GET_MODE (operand0),
-                                                   scratch_reg));
+         emit_move_insn (scratch_reg,
+                         replace_equiv_address (operand1, scratch_reg));
        }
       else
        {
@@ -1971,8 +1759,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                {
                  /* Save away the constant part of the expression.  */
                  const_part = XEXP (XEXP (operand1, 0), 1);
-                 if (GET_CODE (const_part) != CONST_INT)
-                   abort ();
+                 gcc_assert (GET_CODE (const_part) == CONST_INT);
 
                  /* Force the function label into memory.  */
                  temp = force_const_mem (mode, XEXP (XEXP (operand1, 0), 0));
@@ -2035,10 +1822,10 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                       && (reload_completed || reload_in_progress)
                       && flag_pic)
                {
-                 operands[1] = force_const_mem (mode, operand1);
-                 operands[1] = legitimize_pic_address (XEXP (operands[1], 0),
+                 rtx const_mem = force_const_mem (mode, operand1);
+                 operands[1] = legitimize_pic_address (XEXP (const_mem, 0),
                                                        mode, temp);
-                 operands[1] = gen_rtx_MEM (mode, operands[1]);
+                 operands[1] = replace_equiv_address (const_mem, operands[1]);
                  emit_move_sequence (operands, mode, temp);
                }
              else
@@ -2092,6 +1879,26 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
            }
          return 1;
        }
+      else if (pa_tls_referenced_p (operand1))
+       {
+         rtx tmp = operand1;
+         rtx addend = NULL;
+
+         if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+           {
+             addend = XEXP (XEXP (tmp, 0), 1);
+             tmp = XEXP (XEXP (tmp, 0), 0);
+           }
+
+         gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+         tmp = legitimize_tls_address (tmp);
+         if (addend)
+           {
+             tmp = gen_rtx_PLUS (mode, tmp, addend);
+             tmp = force_operand (tmp, operands[0]);
+           }
+         operands[1] = tmp;
+       }
       else if (GET_CODE (operand1) != CONST_INT
               || !cint_ok_for_move (INTVAL (operand1)))
        {
@@ -2138,6 +1945,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
             because PLUS uses an 11-bit immediate and the insn sequence
             generated is not as efficient as the one using HIGH/LO_SUM.  */
          if (GET_CODE (operand1) == CONST_INT
+             && GET_MODE_BITSIZE (mode) <= BITS_PER_WORD
              && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT
              && !insert)
            {
@@ -2222,8 +2030,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
                }
            }
 
-         REG_NOTES (insn)
-           = gen_rtx_EXPR_LIST (REG_EQUAL, op1, REG_NOTES (insn));
+         set_unique_reg_note (insn, REG_EQUAL, op1);
 
          return 1;
        }
@@ -2245,6 +2052,7 @@ reloc_needed (tree exp)
     case ADDR_EXPR:
       return 1;
 
+    case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
     case MINUS_EXPR:
       reloc = reloc_needed (TREE_OPERAND (exp, 0));
@@ -2259,10 +2067,12 @@ reloc_needed (tree exp)
 
     case CONSTRUCTOR:
       {
-       register tree link;
-       for (link = CONSTRUCTOR_ELTS (exp); link; link = TREE_CHAIN (link))
-         if (TREE_VALUE (link) != 0)
-           reloc |= reloc_needed (TREE_VALUE (link));
+       tree value;
+       unsigned HOST_WIDE_INT ix;
+
+       FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), ix, value)
+         if (value)
+           reloc |= reloc_needed (value);
       }
       break;
 
@@ -2314,8 +2124,7 @@ singlemove_string (rtx *operands)
       long i;
       REAL_VALUE_TYPE d;
 
-      if (GET_MODE (operands[1]) != SFmode)
-       abort ();
+      gcc_assert (GET_MODE (operands[1]) == SFmode);
 
       /* Translate the CONST_DOUBLE to a CONST_INT with the same target
         bit pattern.  */
@@ -2450,11 +2259,27 @@ output_move_double (rtx *operands)
     optype1 = RNDOP;
 
   /* Check for the cases that the operand constraints are not
-     supposed to allow to happen.  Abort if we get one,
-     because generating code for these cases is painful.  */
+     supposed to allow to happen.  */
+  gcc_assert (optype0 == REGOP || optype1 == REGOP);
+
+  /* Handle copies between general and floating registers.  */
 
-  if (optype0 != REGOP && optype1 != REGOP)
-    abort ();
+  if (optype0 == REGOP && optype1 == REGOP
+      && FP_REG_P (operands[0]) ^ FP_REG_P (operands[1]))
+    {
+      if (FP_REG_P (operands[0]))
+       {
+         output_asm_insn ("{stws|stw} %1,-16(%%sp)", operands);
+         output_asm_insn ("{stws|stw} %R1,-12(%%sp)", operands);
+         return "{fldds|fldd} -16(%%sp),%0";
+       }
+      else
+       {
+         output_asm_insn ("{fstds|fstd} %1,-16(%%sp)", operands);
+         output_asm_insn ("{ldws|ldw} -16(%%sp),%0", operands);
+         return "{ldws|ldw} -12(%%sp),%R0";
+       }
+    }
 
    /* Handle auto decrementing and incrementing loads and stores
      specifically, since the structure of the function doesn't work
@@ -2473,40 +2298,33 @@ output_move_double (rtx *operands)
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[1], 0);
 
          operands[0] = XEXP (addr, 0);
-         if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
-           abort ();
+         gcc_assert (GET_CODE (operands[1]) == REG
+                     && GET_CODE (operands[0]) == REG);
 
-         if (!reg_overlap_mentioned_p (high_reg, addr))
-           {
-             /* No overlap between high target register and address
-                register.  (We do this in a non-obvious way to
-                save a register file writeback)  */
-             if (GET_CODE (addr) == POST_INC)
-               return "{stws|stw},ma %1,8(%0)\n\tstw %R1,-4(%0)";
-             return "{stws|stw},ma %1,-8(%0)\n\tstw %R1,12(%0)";
-           }
-         else
-           abort ();
+         gcc_assert (!reg_overlap_mentioned_p (high_reg, addr));
+         
+         /* No overlap between high target register and address
+            register.  (We do this in a non-obvious way to
+            save a register file writeback)  */
+         if (GET_CODE (addr) == POST_INC)
+           return "{stws|stw},ma %1,8(%0)\n\tstw %R1,-4(%0)";
+         return "{stws|stw},ma %1,-8(%0)\n\tstw %R1,12(%0)";
        }
       else if (GET_CODE (addr) == PRE_INC || GET_CODE (addr) == PRE_DEC)
        {
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[1], 0);
 
          operands[0] = XEXP (addr, 0);
-         if (GET_CODE (operands[1]) != REG || GET_CODE (operands[0]) != REG)
-           abort ();
-
-         if (!reg_overlap_mentioned_p (high_reg, addr))
-           {
-             /* No overlap between high target register and address
-                register.  (We do this in a non-obvious way to
-                save a register file writeback)  */
-             if (GET_CODE (addr) == PRE_INC)
-               return "{stws|stw},mb %1,8(%0)\n\tstw %R1,4(%0)";
-             return "{stws|stw},mb %1,-8(%0)\n\tstw %R1,4(%0)";
-           }
-         else
-           abort ();
+         gcc_assert (GET_CODE (operands[1]) == REG
+                     && GET_CODE (operands[0]) == REG);
+         
+         gcc_assert (!reg_overlap_mentioned_p (high_reg, addr));
+         /* No overlap between high target register and address
+            register.  (We do this in a non-obvious way to save a
+            register file writeback)  */
+         if (GET_CODE (addr) == PRE_INC)
+           return "{stws|stw},mb %1,8(%0)\n\tstw %R1,4(%0)";
+         return "{stws|stw},mb %1,-8(%0)\n\tstw %R1,4(%0)";
        }
     }
   if (optype1 == MEMOP)
@@ -2520,8 +2338,8 @@ output_move_double (rtx *operands)
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
 
          operands[1] = XEXP (addr, 0);
-         if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
-           abort ();
+         gcc_assert (GET_CODE (operands[0]) == REG
+                     && GET_CODE (operands[1]) == REG);
 
          if (!reg_overlap_mentioned_p (high_reg, addr))
            {
@@ -2547,8 +2365,8 @@ output_move_double (rtx *operands)
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
 
          operands[1] = XEXP (addr, 0);
-         if (GET_CODE (operands[0]) != REG || GET_CODE (operands[1]) != REG)
-           abort ();
+         gcc_assert (GET_CODE (operands[0]) == REG
+                     && GET_CODE (operands[1]) == REG);
 
          if (!reg_overlap_mentioned_p (high_reg, addr))
            {
@@ -2572,12 +2390,11 @@ output_move_double (rtx *operands)
       else if (GET_CODE (addr) == PLUS
               && GET_CODE (XEXP (addr, 0)) == MULT)
        {
+         rtx xoperands[4];
          rtx high_reg = gen_rtx_SUBREG (SImode, operands[0], 0);
 
          if (!reg_overlap_mentioned_p (high_reg, addr))
            {
-             rtx xoperands[3];
-
              xoperands[0] = high_reg;
              xoperands[1] = XEXP (addr, 1);
              xoperands[2] = XEXP (XEXP (addr, 0), 0);
@@ -2588,8 +2405,6 @@ output_move_double (rtx *operands)
            }
          else
            {
-             rtx xoperands[3];
-
              xoperands[0] = high_reg;
              xoperands[1] = XEXP (addr, 1);
              xoperands[2] = XEXP (XEXP (addr, 0), 0);
@@ -2710,23 +2525,22 @@ output_fp_move_double (rtx *operands)
     {
       output_asm_insn ("fstd%F0 %1,%0", operands);
     }
-  else if (operands[1] == CONST0_RTX (GET_MODE (operands[0])))
+  else
     {
-      if (GET_CODE (operands[0]) == REG)
-       {
-         rtx xoperands[2];
-         xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
-         xoperands[0] = operands[0];
-         output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands);
-       }
+      rtx xoperands[2];
+      
+      gcc_assert (operands[1] == CONST0_RTX (GET_MODE (operands[0])));
+      
       /* This is a pain.  You have to be prepared to deal with an
         arbitrary address here including pre/post increment/decrement.
 
         so avoid this in the MD.  */
-      else
-       abort ();
+      gcc_assert (GET_CODE (operands[0]) == REG);
+      
+      xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+      xoperands[0] = operands[0];
+      output_asm_insn ("copy %%r0,%0\n\tcopy %%r0,%1", xoperands);
     }
-  else abort ();
   return "";
 }
 \f
@@ -2747,11 +2561,10 @@ find_addr_reg (rtx addr)
       else if (CONSTANT_P (XEXP (addr, 1)))
        addr = XEXP (addr, 0);
       else
-       abort ();
+       gcc_unreachable ();
     }
-  if (GET_CODE (addr) == REG)
-    return addr;
-  abort ();
+  gcc_assert (GET_CODE (addr) == REG);
+  return addr;
 }
 
 /* Emit code to perform a block move.
@@ -2882,7 +2695,7 @@ output_block_move (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
        return "";
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
 }
 
@@ -3024,7 +2837,7 @@ output_block_clear (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
        return "";
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
 }
 
@@ -3084,15 +2897,13 @@ output_and (rtx *operands)
        if ((mask & (1 << ms0)) == 0)
          break;
 
-      if (ms0 != 32)
-       abort ();
+      gcc_assert (ms0 == 32);
 
       if (ls1 == 32)
        {
          len = ls0;
 
-         if (len == 0)
-           abort ();
+         gcc_assert (len);
 
          operands[2] = GEN_INT (len);
          return "{extru|extrw,u} %1,31,%2,%0";
@@ -3136,15 +2947,13 @@ output_64bit_and (rtx *operands)
        if ((mask & ((unsigned HOST_WIDE_INT) 1 << ms0)) == 0)
          break;
 
-      if (ms0 != HOST_BITS_PER_WIDE_INT)
-       abort ();
+      gcc_assert (ms0 == HOST_BITS_PER_WIDE_INT);
 
       if (ls1 == HOST_BITS_PER_WIDE_INT)
        {
          len = ls0;
 
-         if (len == 0)
-           abort ();
+         gcc_assert (len);
 
          operands[2] = GEN_INT (len);
          return "extrd,u %1,63,%2,%0";
@@ -3183,8 +2992,7 @@ output_ior (rtx *operands)
     if ((mask & (1 << bs1)) == 0)
       break;
 
-  if (bs1 != 32 && ((unsigned HOST_WIDE_INT) 1 << bs1) <= mask)
-    abort ();
+  gcc_assert (bs1 == 32 || ((unsigned HOST_WIDE_INT) 1 << bs1) > mask);
 
   p = 31 - bs0;
   len = bs1 - bs0;
@@ -3213,9 +3021,8 @@ output_64bit_ior (rtx *operands)
     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 ();
+  gcc_assert (bs1 == HOST_BITS_PER_WIDE_INT
+             || ((unsigned HOST_WIDE_INT) 1 << bs1) > mask);
 
   p = 63 - bs0;
   len = bs1 - bs0;
@@ -3226,13 +3033,14 @@ output_64bit_ior (rtx *operands)
 }
 \f
 /* Target hook for assembling integer objects.  This code handles
-   aligned SI and DI integers specially, since function references must
-   be preceded by P%.  */
+   aligned SI and DI integers specially since function references
+   must be preceded by P%.  */
 
 static bool
 pa_assemble_integer (rtx x, unsigned int size, int aligned_p)
 {
-  if (size == UNITS_PER_WORD && 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);
@@ -3413,7 +3221,7 @@ remove_useless_addtr_insns (int check_notes)
            {
              rtx pattern = PATTERN (next);
 
-             /* If it a reversed fp conditional branch (eg uses add,tr)
+             /* If it a reversed fp conditional branch (e.g. uses add,tr)
                 and CCFP dies, then reverse our conditional and the branch
                 to avoid the add,tr.  */
              if (GET_CODE (pattern) == SET
@@ -3540,20 +3348,18 @@ store_reg (int reg, HOST_WIDE_INT disp, int base)
       rtx tmpreg = gen_rtx_REG (Pmode, 1);
 
       emit_move_insn (tmpreg, delta);
-      emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
-      dest = gen_rtx_MEM (word_mode, tmpreg);
-      insn = emit_move_insn (dest, src);
+      insn = emit_move_insn (tmpreg, gen_rtx_PLUS (Pmode, tmpreg, basereg));
       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),
+               gen_rtx_SET (VOIDmode, tmpreg,
+                            gen_rtx_PLUS (Pmode, basereg, delta)),
                 REG_NOTES (insn));
+         RTX_FRAME_RELATED_P (insn) = 1;
        }
+      dest = gen_rtx_MEM (word_mode, tmpreg);
+      insn = emit_move_insn (dest, src);
     }
   else
     {
@@ -3589,8 +3395,7 @@ store_reg_modify (int base, int reg, HOST_WIDE_INT mod)
 {
   rtx insn, basereg, srcreg, delta;
 
-  if (!VAL_14_BITS_P (mod))
-    abort ();
+  gcc_assert (VAL_14_BITS_P (mod));
 
   basereg = gen_rtx_REG (Pmode, base);
   srcreg = gen_rtx_REG (word_mode, reg);
@@ -3602,25 +3407,9 @@ store_reg_modify (int base, int reg, HOST_WIDE_INT mod)
       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));
-       }
+        in a parallel with more than one element.  */
+      RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 0)) = 1;
+      RTX_FRAME_RELATED_P (XVECEXP (PATTERN (insn), 0, 1)) = 1;
     }
 }
 
@@ -3650,6 +3439,12 @@ set_reg_plus_d (int reg, int base, HOST_WIDE_INT disp, int note)
       emit_move_insn (tmpreg, delta);
       insn = emit_move_insn (gen_rtx_REG (Pmode, reg),
                             gen_rtx_PLUS (Pmode, tmpreg, basereg));
+      if (DO_FRAME_NOTES)
+       REG_NOTES (insn)
+         = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+             gen_rtx_SET (VOIDmode, tmpreg,
+                          gen_rtx_PLUS (Pmode, basereg, delta)),
+             REG_NOTES (insn));
     }
   else
     {
@@ -3703,13 +3498,13 @@ compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
 
   /* Account for space used by the callee general register saves.  */
   for (i = 18, j = frame_pointer_needed ? 4 : 3; i >= j; i--)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       size += UNITS_PER_WORD;
 
   /* Account for space used by the callee floating point register saves.  */
   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 (df_regs_ever_live_p (i)
+       || (!TARGET_64BIT && df_regs_ever_live_p (i + 1)))
       {
        freg_saved = 1;
 
@@ -3774,15 +3569,17 @@ pa_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
      to output the assembler directives which denote the start
      of a function.  */
   fprintf (file, "\t.CALLINFO FRAME=" HOST_WIDE_INT_PRINT_DEC, actual_fsize);
-  if (regs_ever_live[2])
-    fputs (",CALLS,SAVE_RP", file);
-  else
+  if (current_function_is_leaf)
     fputs (",NO_CALLS", file);
+  else
+    fputs (",CALLS", file);
+  if (rp_saved)
+    fputs (",SAVE_RP", file);
 
   /* The SAVE_SP flag is used to indicate that register %r3 is stored
      at the beginning of the frame and that it is used as the frame
      pointer for the frame.  We do this because our current frame
-     layout doesn't conform to that specified in the the HP runtime
+     layout doesn't conform to that specified in the HP runtime
      documentation and we need a way to indicate to programs such as
      GDB where %r3 is saved.  The SAVE_SP flag was chosen because it
      isn't used by HP compilers but is supported by the assembler.
@@ -3838,8 +3635,13 @@ hppa_expand_prologue (void)
   /* Save RP first.  The calling conventions manual states RP will
      always be stored into the caller's frame at sp - 20 or sp - 16
      depending on which ABI is in use.  */
-  if (regs_ever_live[2] || current_function_calls_eh_return)
-    store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
+  if (df_regs_ever_live_p (2) || current_function_calls_eh_return)
+    {
+      store_reg (2, TARGET_64BIT ? -16 : -20, STACK_POINTER_REGNUM);
+      rp_saved = true;
+    }
+  else
+    rp_saved = false;
 
   /* Allocate the local frame and set up the frame pointer if needed.  */
   if (actual_fsize != 0)
@@ -3854,17 +3656,7 @@ hppa_expand_prologue (void)
             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));
-           }
+           RTX_FRAME_RELATED_P (insn) = 1;
 
          insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
          if (DO_FRAME_NOTES)
@@ -3959,7 +3751,7 @@ hppa_expand_prologue (void)
        }
 
       for (i = 18; i >= 4; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            store_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
@@ -3999,7 +3791,7 @@ hppa_expand_prologue (void)
        }
 
       for (i = 18; i >= 3; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            /* If merge_sp_adjust_with_store is nonzero, then we can
               optimize the first GR save.  */
@@ -4062,8 +3854,8 @@ hppa_expand_prologue (void)
       /* Now actually save the FP registers.  */
       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 (df_regs_ever_live_p (i)
+             || (! TARGET_64BIT && df_regs_ever_live_p (i + 1)))
            {
              rtx addr, insn, reg;
              addr = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
@@ -4213,6 +4005,15 @@ pa_output_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 
   fputs ("\t.EXIT\n\t.PROCEND\n", file);
 
+  if (TARGET_SOM && TARGET_GAS)
+    {
+      /* We done with this subspace except possibly for some additional
+        debug information.  Forget that we are in this subspace to ensure
+        that the next function is output in its own subspace.  */
+      in_section = NULL;
+      cfun->machine->in_nsubspa = 2;
+    }
+
   if (INSN_ADDRESSES_SET_P ())
     {
       insn = get_last_nonnote_insn ();
@@ -4242,7 +4043,7 @@ hppa_expand_epilogue (void)
   /* Try to restore RP early to avoid load/use interlocks when
      RP gets used in the return (bv) instruction.  This appears to still
      be necessary even when we schedule the prologue and epilogue.  */
-  if (regs_ever_live [2] || current_function_calls_eh_return)
+  if (rp_saved)
     {
       ret_off = TARGET_64BIT ? -16 : -20;
       if (frame_pointer_needed)
@@ -4284,7 +4085,7 @@ hppa_expand_epilogue (void)
        }
 
       for (i = 18; i >= 4; i--)
-       if (regs_ever_live[i] && ! call_used_regs[i])
+       if (df_regs_ever_live_p (i) && ! call_used_regs[i])
          {
            load_reg (i, offset, FRAME_POINTER_REGNUM);
            offset += UNITS_PER_WORD;
@@ -4321,7 +4122,7 @@ hppa_expand_epilogue (void)
 
       for (i = 18; i >= 3; i--)
        {
-         if (regs_ever_live[i] && ! call_used_regs[i])
+         if (df_regs_ever_live_p (i) && ! call_used_regs[i])
            {
              /* Only for the first load.
                 merge_sp_adjust_with_load holds the register load
@@ -4351,8 +4152,8 @@ hppa_expand_epilogue (void)
 
       /* Actually do the restores now.  */
       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 (df_regs_ever_live_p (i)
+           || (! TARGET_64BIT && df_regs_ever_live_p (i + 1)))
          {
            rtx src = gen_rtx_MEM (DFmode, gen_rtx_POST_INC (DFmode, tmpreg));
            rtx dest = gen_rtx_REG (DFmode, i);
@@ -4410,6 +4211,37 @@ hppa_pic_save_rtx (void)
   return get_hard_reg_initial_val (word_mode, PIC_OFFSET_TABLE_REGNUM);
 }
 
+#ifndef NO_DEFERRED_PROFILE_COUNTERS
+#define NO_DEFERRED_PROFILE_COUNTERS 0
+#endif
+
+
+/* Vector of funcdef numbers.  */
+static VEC(int,heap) *funcdef_nos;
+
+/* Output deferred profile counters.  */
+static void
+output_deferred_profile_counters (void)
+{
+  unsigned int i;
+  int align, n;
+
+  if (VEC_empty (int, funcdef_nos))
+   return;
+
+  switch_to_section (data_section);
+  align = MIN (BIGGEST_ALIGNMENT, LONG_TYPE_SIZE);
+  ASM_OUTPUT_ALIGN (asm_out_file, floor_log2 (align / BITS_PER_UNIT));
+
+  for (i = 0; VEC_iterate (int, funcdef_nos, i, n); i++)
+    {
+      targetm.asm_out.internal_label (asm_out_file, "LP", n);
+      assemble_integer (const0_rtx, LONG_TYPE_SIZE / BITS_PER_UNIT, align, 1);
+    }
+
+  VEC_free (int, heap, funcdef_nos);
+}
+
 void
 hppa_profile_hook (int label_no)
 {
@@ -4432,7 +4264,7 @@ hppa_profile_hook (int label_no)
 
   emit_move_insn (gen_rtx_REG (word_mode, 26), gen_rtx_REG (word_mode, 2));
 
-  /* The address of the function is loaded into %r25 with a instruction-
+  /* The address of the function is loaded into %r25 with an instruction-
      relative sequence that avoids the use of relocations.  The sequence
      is split so that the load_offset_label_address instruction can
      occupy the delay slot of the call to _mcount.  */
@@ -4444,11 +4276,12 @@ hppa_profile_hook (int label_no)
   emit_insn (gen_load_offset_label_address (gen_rtx_REG (SImode, 25), 
                                            reg, begin_label_rtx, label_rtx));
 
-#ifndef NO_PROFILE_COUNTERS
+#if !NO_DEFERRED_PROFILE_COUNTERS
   {
     rtx count_label_rtx, addr, r24;
     char count_label_name[16];
 
+    VEC_safe_push (int, heap, funcdef_nos, label_no);
     ASM_GENERATE_INTERNAL_LABEL (count_label_name, "LP", label_no);
     count_label_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (count_label_name));
 
@@ -4558,8 +4391,10 @@ return_addr_rtx (int count, rtx frameaddr)
                 GEN_INT (0x00011820), NE, NULL_RTX, SImode, 1);
   emit_jump_insn (gen_bne (label));
 
+  /* 0xe0400002 must be specified as -532676606 so that it won't be
+     rejected as an invalid immediate operand on 64-bit hosts.  */
   emit_cmp_insn (gen_rtx_MEM (SImode, plus_constant (ins, 12)),
-                GEN_INT (0xe0400002), NE, NULL_RTX, SImode, 1);
+                GEN_INT (-532676606), NE, NULL_RTX, SImode, 1);
 
   /* If there is no export stub then just use the value saved from
      the return pointer register.  */
@@ -4581,22 +4416,6 @@ return_addr_rtx (int count, rtx frameaddr)
   return saved_rp;
 }
 
-/* This is only valid once reload has completed because it depends on
-   knowing exactly how much (if any) frame there is and...
-
-   It's only valid if there is no frame marker to de-allocate and...
-
-   It's only valid if %r2 hasn't been saved into the caller's frame
-   (we're not profiling and %r2 isn't live anywhere).  */
-int
-hppa_can_use_return_insn_p (void)
-{
-  return (reload_completed
-         && (compute_frame_size (get_frame_size (), 0) ? 0 : 1)
-         && ! regs_ever_live[2]
-         && ! frame_pointer_needed);
-}
-
 void
 emit_bcond_fp (enum rtx_code code, rtx operand0)
 {
@@ -4636,8 +4455,9 @@ pa_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
   attr_type = get_attr_type (insn);
 
-  if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
+  switch (REG_NOTE_KIND (link))
     {
+    case REG_DEP_ANTI:
       /* Anti dependency; DEP_INSN reads a register that INSN writes some
         cycles later.  */
 
@@ -4717,9 +4537,8 @@ pa_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
       /* For other anti dependencies, the cost is 0.  */
       return 0;
-    }
-  else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
-    {
+
+    case REG_DEP_OUTPUT:
       /* Output dependency; DEP_INSN writes a register that INSN writes some
         cycles later.  */
       if (attr_type == TYPE_FPLOAD)
@@ -4802,9 +4621,10 @@ pa_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 
       /* For other output dependencies, the cost is 0.  */
       return 0;
+
+    default:
+      gcc_unreachable ();
     }
-  else
-    abort ();
 }
 
 /* Adjust scheduling priorities.  We use this to try and keep addil
@@ -4854,7 +4674,7 @@ pa_issue_rate (void)
     case PROCESSOR_8000:       return 4;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -5017,7 +4837,7 @@ print_operand (FILE *file, rtx x, int code)
        case LTU:
          fputs ("<<", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'N':                  /* Condition, (N)egated */
@@ -5044,11 +4864,14 @@ print_operand (FILE *file, rtx x, int code)
        case LTU:
          fputs (">>=", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     /* For floating point comparisons.  Note that the output
-       predicates are the complement of the desired mode.  */
+       predicates are the complement of the desired mode.  The
+       conditions for GT, GE, LT, LE and LTGT cause an invalid
+       operation exception if the result is unordered and this
+       exception is enabled in the floating-point status register.  */
     case 'Y':
       switch (GET_CODE (x))
        {
@@ -5067,21 +4890,21 @@ print_operand (FILE *file, rtx x, int code)
        case LTGT:
          fputs ("!<>", file);  break;
        case UNLE:
-         fputs (">", file);  break;
+         fputs ("!?<=", file);  break;
        case UNLT:
-         fputs (">=", file);  break;
+         fputs ("!?<", file);  break;
        case UNGE:
-         fputs ("<", file);  break;
+         fputs ("!?>=", file);  break;
        case UNGT:
-         fputs ("<=", file);  break;
+         fputs ("!?>", file);  break;
        case UNEQ:
-         fputs ("<>", file);  break;
+         fputs ("!?=", file);  break;
        case UNORDERED:
-         fputs ("<=>", file);  break;
+         fputs ("!?", file);  break;
        case ORDERED:
-         fputs ("!<=>", file);  break;
+         fputs ("?", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'S':                  /* Condition, operands are (S)wapped.  */
@@ -5108,7 +4931,7 @@ print_operand (FILE *file, rtx x, int code)
        case LTU:
          fputs (">>", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'B':                  /* Condition, (B)oth swapped and negate.  */
@@ -5135,51 +4958,33 @@ print_operand (FILE *file, rtx x, int code)
        case LTU:
          fputs ("<<=", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'k':
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~INTVAL (x));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~INTVAL (x));
+      return;
     case 'Q':
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - (INTVAL (x) & 63));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, 64 - (INTVAL (x) & 63));
+      return;
     case 'L':
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - (INTVAL (x) & 31));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, 32 - (INTVAL (x) & 31));
+      return;
     case 'O':
-      if (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0)
-       {
-         fprintf (file, "%d", exact_log2 (INTVAL (x)));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT && exact_log2 (INTVAL (x)) >= 0);
+      fprintf (file, "%d", exact_log2 (INTVAL (x)));
+      return;
     case 'p':
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 63 - (INTVAL (x) & 63));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, 63 - (INTVAL (x) & 63));
+      return;
     case 'P':
-      if (GET_CODE (x) == CONST_INT)
-       {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, 31 - (INTVAL (x) & 31));
-         return;
-       }
-      abort ();
+      gcc_assert (GET_CODE (x) == CONST_INT);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, 31 - (INTVAL (x) & 31));
+      return;
     case 'I':
       if (GET_CODE (x) == CONST_INT)
        fputs ("i", file);
@@ -5254,7 +5059,7 @@ print_operand (FILE *file, rtx x, int code)
         addresses.  */
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   if (GET_CODE (x) == REG)
     {
@@ -5329,10 +5134,10 @@ output_global_address (FILE *file, rtx x, int round_constant)
     x = XEXP (x, 0);
 
   if (GET_CODE (x) == SYMBOL_REF && read_only_operand (x, VOIDmode))
-    assemble_name (file, XSTR (x, 0));
+    output_addr_const (file, x);
   else if (GET_CODE (x) == SYMBOL_REF && !flag_pic)
     {
-      assemble_name (file, XSTR (x, 0));
+      output_addr_const (file, x);
       fputs ("-$global$", file);
     }
   else if (GET_CODE (x) == CONST)
@@ -5341,23 +5146,31 @@ output_global_address (FILE *file, rtx x, int round_constant)
       int offset = 0;          /* assembler wants -$global$ at end */
       rtx base = NULL_RTX;
 
-      if (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
+      switch (GET_CODE (XEXP (XEXP (x, 0), 0)))
        {
+       case SYMBOL_REF:
          base = XEXP (XEXP (x, 0), 0);
          output_addr_const (file, base);
+         break;
+       case CONST_INT:
+         offset = INTVAL (XEXP (XEXP (x, 0), 0));
+         break;
+       default:
+         gcc_unreachable ();
        }
-      else if (GET_CODE (XEXP (XEXP (x, 0), 0)) == CONST_INT)
-       offset = INTVAL (XEXP (XEXP (x, 0), 0));
-      else abort ();
 
-      if (GET_CODE (XEXP (XEXP (x, 0), 1)) == SYMBOL_REF)
+      switch (GET_CODE (XEXP (XEXP (x, 0), 1)))
        {
+       case SYMBOL_REF:
          base = XEXP (XEXP (x, 0), 1);
          output_addr_const (file, base);
+         break;
+       case CONST_INT:
+         offset = INTVAL (XEXP (XEXP (x, 0), 1));
+         break;
+       default:
+         gcc_unreachable ();
        }
-      else if (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
-       offset = INTVAL (XEXP (XEXP (x, 0), 1));
-      else abort ();
 
       /* How bogus.  The compiler is apparently responsible for
         rounding the constant if it uses an LR field selector.
@@ -5371,8 +5184,9 @@ output_global_address (FILE *file, rtx x, int round_constant)
       if (round_constant)
        offset = ((offset + 0x1000) & ~0x1fff);
 
-      if (GET_CODE (XEXP (x, 0)) == PLUS)
+      switch (GET_CODE (XEXP (x, 0)))
        {
+       case PLUS:
          if (offset < 0)
            {
              offset = -offset;
@@ -5380,12 +5194,17 @@ output_global_address (FILE *file, rtx x, int round_constant)
            }
          else
            sep = "+";
-       }
-      else if (GET_CODE (XEXP (x, 0)) == MINUS
-              && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
-       sep = "-";
-      else abort ();
+         break;
+
+       case MINUS:
+         gcc_assert (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF);
+         sep = "-";
+         break;
 
+       default:
+         gcc_unreachable ();
+       }
+      
       if (!read_only_operand (base, VOIDmode) && !flag_pic)
        fputs ("-$global$", file);
       if (offset)
@@ -5492,23 +5311,27 @@ pa_hpux64_hpas_file_start (void)
 }
 #undef aputs
 
-static struct deferred_plabel *
-get_plabel (const char *fname)
+/* Search the deferred plabel list for SYMBOL and return its internal
+   label.  If an entry for SYMBOL is not found, a new entry is created.  */
+
+rtx
+get_deferred_plabel (rtx symbol)
 {
+  const char *fname = XSTR (symbol, 0);
   size_t i;
 
   /* See if we have already put this function on the list of deferred
      plabels.  This list is generally small, so a liner search is not
      too ugly.  If it proves too slow replace it with something faster.  */
   for (i = 0; i < n_deferred_plabels; i++)
-    if (strcmp (fname, deferred_plabels[i].name) == 0)
+    if (strcmp (fname, XSTR (deferred_plabels[i].symbol, 0)) == 0)
       break;
 
   /* If the deferred plabel list is empty, or this entry was not found
      on the list, create a new entry on the list.  */
   if (deferred_plabels == NULL || i == n_deferred_plabels)
     {
-      const char *real_name;
+      tree id;
 
       if (deferred_plabels == 0)
        deferred_plabels = (struct deferred_plabel *)
@@ -5521,36 +5344,38 @@ get_plabel (const char *fname)
 
       i = n_deferred_plabels++;
       deferred_plabels[i].internal_label = gen_label_rtx ();
-      deferred_plabels[i].name = ggc_strdup (fname);
+      deferred_plabels[i].symbol = symbol;
 
-      /* Gross.  We have just implicitly taken the address of this function,
-        mark it as such.  */
-      real_name = (*targetm.strip_name_encoding) (fname);
-      TREE_SYMBOL_REFERENCED (get_identifier (real_name)) = 1;
+      /* Gross.  We have just implicitly taken the address of this
+        function.  Mark it in the same manner as assemble_name.  */
+      id = maybe_get_identifier (targetm.strip_name_encoding (fname));
+      if (id)
+       mark_referenced (id);
     }
 
-  return &deferred_plabels[i];
+  return deferred_plabels[i].internal_label;
 }
 
 static void
 output_deferred_plabels (void)
 {
   size_t i;
-  /* If we have deferred plabels, then we need to switch into the data
-     section and align it to a 4 byte boundary before we output the
-     deferred plabels.  */
+
+  /* If we have some deferred plabels, then we need to switch into the
+     data or readonly data section, and align it to a 4 byte boundary
+     before outputting the deferred plabels.  */
   if (n_deferred_plabels)
     {
-      data_section ();
+      switch_to_section (flag_pic ? data_section : readonly_data_section);
       ASM_OUTPUT_ALIGN (asm_out_file, TARGET_64BIT ? 3 : 2);
     }
 
   /* Now output the deferred plabels.  */
   for (i = 0; i < n_deferred_plabels; i++)
     {
-      (*targetm.asm_out.internal_label) (asm_out_file, "L",
+      targetm.asm_out.internal_label (asm_out_file, "L",
                 CODE_LABEL_NUMBER (deferred_plabels[i].internal_label));
-      assemble_integer (gen_rtx_SYMBOL_REF (Pmode, deferred_plabels[i].name),
+      assemble_integer (deferred_plabels[i].symbol,
                        TARGET_64BIT ? 8 : 4, TARGET_64BIT ? 64 : 32, 1);
     }
 }
@@ -5592,6 +5417,8 @@ pa_hpux_init_libfuncs (void)
 
   set_conv_libfunc (sfloat_optab, TFmode, SImode, "_U_Qfcnvxf_sgl_to_quad");
   set_conv_libfunc (sfloat_optab, TFmode, DImode, "_U_Qfcnvxf_dbl_to_quad");
+  set_conv_libfunc (ufloat_optab, TFmode, SImode, "_U_Qfcnvxf_usgl_to_quad");
+  set_conv_libfunc (ufloat_optab, TFmode, DImode, "_U_Qfcnvxf_udbl_to_quad");
 }
 #endif
 
@@ -5632,8 +5459,7 @@ output_mul_insn (int unsignedp ATTRIBUTE_UNUSED, rtx insn)
 /* Emit the rtl for doing a division by a constant.  */
 
 /* Do magic division millicodes exist for this value? */
-static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
-                                1, 1};
+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
@@ -5642,15 +5468,6 @@ static const int magic_milli[]= {0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0,
 static int div_milli[16][2];
 
 int
-div_operand (rtx op, enum machine_mode mode)
-{
-  return (mode == SImode
-         && ((GET_CODE (op) == REG && REGNO (op) == 25)
-             || (GET_CODE (op) == CONST_INT && INTVAL (op) > 0
-                 && INTVAL (op) < 16 && magic_milli[INTVAL (op)])));
-}
-
-int
 emit_hpdiv_const (rtx *operands, int unsignedp)
 {
   if (GET_CODE (operands[2]) == CONST_INT
@@ -5777,9 +5594,9 @@ output_arg_descriptor (rtx call_insn)
       return;
     }
 
-  if (GET_CODE (call_insn) != CALL_INSN)
-    abort ();
-  for (link = CALL_INSN_FUNCTION_USAGE (call_insn); link; link = XEXP (link, 1))
+  gcc_assert (GET_CODE (call_insn) == CALL_INSN);
+  for (link = CALL_INSN_FUNCTION_USAGE (call_insn);
+       link; link = XEXP (link, 1))
     {
       rtx use = XEXP (link, 0);
 
@@ -5825,104 +5642,138 @@ output_arg_descriptor (rtx call_insn)
   fputc ('\n', asm_out_file);
 }
 \f
-/* Return the class of any secondary reload register that is needed to
-   move IN into a register in class CLASS using mode MODE.
-
-   Profiling has showed this routine and its descendants account for
-   a significant amount of compile time (~7%).  So it has been
-   optimized to reduce redundant computations and eliminate useless
-   function calls.
-
-   It might be worthwhile to try and make this a leaf function too.  */
-
-enum reg_class
-secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
+static enum reg_class
+pa_secondary_reload (bool in_p, rtx x, enum reg_class class,
+                    enum machine_mode mode, secondary_reload_info *sri)
 {
-  int regno, is_symbolic;
+  int is_symbolic, regno;
 
-  /* Trying to load a constant into a FP register during PIC code
-     generation will require %r1 as a scratch register.  */
-  if (flag_pic
-      && GET_MODE_CLASS (mode) == MODE_INT
-      && FP_REG_CLASS_P (class)
-      && (GET_CODE (in) == CONST_INT || GET_CODE (in) == CONST_DOUBLE))
-    return R1_REGS;
-
-  /* Profiling showed the PA port spends about 1.3% of its compilation
-     time in true_regnum from calls inside secondary_reload_class.  */
+  /* Handle the easy stuff first.  */
+  if (class == R1_REGS)
+    return NO_REGS;
 
-  if (GET_CODE (in) == REG)
+  if (REG_P (x))
     {
-      regno = REGNO (in);
-      if (regno >= FIRST_PSEUDO_REGISTER)
-       regno = true_regnum (in);
+      regno = REGNO (x);
+      if (class == BASE_REG_CLASS && regno < FIRST_PSEUDO_REGISTER)
+       return NO_REGS;
     }
-  else if (GET_CODE (in) == SUBREG)
-    regno = true_regnum (in);
   else
     regno = -1;
 
   /* If we have something like (mem (mem (...)), we can safely assume the
      inner MEM will end up in a general register after reloading, so there's
      no need for a secondary reload.  */
-  if (GET_CODE (in) == MEM
-      && GET_CODE (XEXP (in, 0)) == MEM)
+  if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == MEM)
     return NO_REGS;
 
+  /* Trying to load a constant into a FP register during PIC code
+     generation requires %r1 as a scratch register.  */
+  if (flag_pic
+      && (mode == SImode || mode == DImode)
+      && FP_REG_CLASS_P (class)
+      && (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE))
+    {
+      sri->icode = (mode == SImode ? CODE_FOR_reload_insi_r1
+                   : CODE_FOR_reload_indi_r1);
+      return NO_REGS;
+    }
+
+  /* Profiling showed the PA port spends about 1.3% of its compilation
+     time in true_regnum from calls inside pa_secondary_reload_class.  */
+  if (regno >= FIRST_PSEUDO_REGISTER || GET_CODE (x) == SUBREG)
+    regno = true_regnum (x);
+
   /* Handle out of range displacement for integer mode loads/stores of
      FP registers.  */
   if (((regno >= FIRST_PSEUDO_REGISTER || regno == -1)
        && GET_MODE_CLASS (mode) == MODE_INT
        && FP_REG_CLASS_P (class))
       || (class == SHIFT_REGS && (regno <= 0 || regno >= 32)))
-    return GENERAL_REGS;
+    {
+      sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+      return NO_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;
+         || (class == SHIFT_REGS
+             && FP_REG_CLASS_P (REGNO_REG_CLASS (regno)))))
+    {
+      sri->icode = in_p ? reload_in_optab[mode] : reload_out_optab[mode];
+      return NO_REGS;
+    }
 
-  if (GET_CODE (in) == HIGH)
-    in = XEXP (in, 0);
+  /* Secondary reloads of symbolic operands require %r1 as a scratch
+     register when we're generating PIC code and the operand isn't
+     readonly.  */
+  if (GET_CODE (x) == HIGH)
+    x = XEXP (x, 0);
 
   /* Profiling has showed GCC spends about 2.6% of its compilation
-     time in symbolic_operand from calls inside secondary_reload_class.
-
-     We use an inline copy and only compute its return value once to avoid
-     useless work.  */
-  switch (GET_CODE (in))
+     time in symbolic_operand from calls inside pa_secondary_reload_class.
+     So, we use an inline copy to avoid useless work.  */
+  switch (GET_CODE (x))
     {
-      rtx tmp;
+      rtx op;
 
       case SYMBOL_REF:
+        is_symbolic = !SYMBOL_REF_TLS_MODEL (x);
+        break;
       case LABEL_REF:
         is_symbolic = 1;
         break;
       case CONST:
-       tmp = XEXP (in, 0);
-       is_symbolic = ((GET_CODE (XEXP (tmp, 0)) == SYMBOL_REF
-                       || GET_CODE (XEXP (tmp, 0)) == LABEL_REF)
-                      && GET_CODE (XEXP (tmp, 1)) == CONST_INT);
+       op = XEXP (x, 0);
+       is_symbolic = (((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+                        && !SYMBOL_REF_TLS_MODEL (XEXP (op, 0)))
+                       || GET_CODE (XEXP (op, 0)) == LABEL_REF)
+                      && GET_CODE (XEXP (op, 1)) == CONST_INT);
         break;
-
       default:
         is_symbolic = 0;
         break;
     }
 
-  if (!flag_pic
-      && is_symbolic
-      && read_only_operand (in, VOIDmode))
-    return NO_REGS;
-
-  if (class != R1_REGS && is_symbolic)
-    return R1_REGS;
+  if (is_symbolic && (flag_pic || !read_only_operand (x, VOIDmode)))
+    {
+      gcc_assert (mode == SImode || mode == DImode);
+      sri->icode = (mode == SImode ? CODE_FOR_reload_insi_r1
+                   : CODE_FOR_reload_indi_r1);
+    }
 
   return NO_REGS;
 }
 
+/* Implement TARGET_EXTRA_LIVE_ON_ENTRY.  The argument pointer
+   is only marked as live on entry by df-scan when it is a fixed
+   register.  It isn't a fixed register in the 64-bit runtime,
+   so we need to mark it here.  */
+
+static void
+pa_extra_live_on_entry (bitmap regs)
+{
+  if (TARGET_64BIT)
+    bitmap_set_bit (regs, ARG_POINTER_REGNUM);
+}
+
+/* Implement EH_RETURN_HANDLER_RTX.  The MEM needs to be volatile
+   to prevent it from being deleted.  */
+
+rtx
+pa_eh_return_handler_rtx (void)
+{
+  rtx tmp;
+
+  tmp = gen_rtx_PLUS (word_mode, frame_pointer_rtx,
+                     TARGET_64BIT ? GEN_INT (-16) : GEN_INT (-20));
+  tmp = gen_rtx_MEM (word_mode, tmp);
+  tmp->volatil = 1;
+  return tmp;
+}
+
 /* In the 32-bit runtime, arguments larger than eight bytes are passed
    by invisible reference.  As a GCC extension, we also pass anything
    with a zero or variable size by reference.
@@ -5938,7 +5789,7 @@ secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx in)
 
 static bool
 pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
-                     enum machine_mode mode, tree type,
+                     enum machine_mode mode, const_tree type,
                      bool named ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT size;
@@ -5955,7 +5806,7 @@ pa_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
 }
 
 enum direction
-function_arg_padding (enum machine_mode mode, tree type)
+function_arg_padding (enum machine_mode mode, const_tree type)
 {
   if (mode == BLKmode
       || (TARGET_64BIT && type && AGGREGATE_TYPE_P (type)))
@@ -6096,34 +5947,83 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
       /* Args grow down.  Not handled by generic routines.  */
 
-      u = fold_convert (valist_type, size_in_bytes (type));
-      t = build (MINUS_EXPR, valist_type, valist, u);
+      u = fold_convert (sizetype, size_in_bytes (type));
+      u = fold_build1 (NEGATE_EXPR, sizetype, u);
+      t = build2 (POINTER_PLUS_EXPR, valist_type, valist, u);
 
       /* Copied from va-pa.h, but we probably don't need to align to
         word size, since we generate and preserve that invariant.  */
-      u = build_int_2 ((size > 4 ? -8 : -4), -1);
-      u = fold_convert (valist_type, u);
-      t = build (BIT_AND_EXPR, valist_type, t, u);
+      u = size_int (size > 4 ? -8 : -4);
+      t = fold_convert (sizetype, t);
+      t = build2 (BIT_AND_EXPR, sizetype, t, u);
+      t = fold_convert (valist_type, t);
 
-      t = build (MODIFY_EXPR, valist_type, valist, t);
+      t = build2 (MODIFY_EXPR, valist_type, valist, t);
 
       ofs = (8 - size) % 4;
       if (ofs != 0)
        {
-         u = fold_convert (valist_type, size_int (ofs));
-         t = build (PLUS_EXPR, valist_type, t, u);
+         u = size_int (ofs);
+         t = build2 (POINTER_PLUS_EXPR, valist_type, t, u);
        }
 
       t = fold_convert (ptr, t);
-      t = build_fold_indirect_ref (t);
+      t = build_va_arg_indirect_ref (t);
 
       if (indirect)
-       t = build_fold_indirect_ref (t);
+       t = build_va_arg_indirect_ref (t);
 
       return t;
     }
 }
 
+/* True if MODE is valid for the target.  By "valid", we mean able to
+   be manipulated in non-trivial ways.  In particular, this means all
+   the arithmetic is supported.
+
+   Currently, TImode is not valid as the HP 64-bit runtime documentation
+   doesn't document the alignment and calling conventions for this type. 
+   Thus, we return false when PRECISION is 2 * BITS_PER_WORD and
+   2 * BITS_PER_WORD isn't equal LONG_LONG_TYPE_SIZE.  */
+
+static bool
+pa_scalar_mode_supported_p (enum machine_mode mode)
+{
+  int precision = GET_MODE_PRECISION (mode);
+
+  switch (GET_MODE_CLASS (mode))
+    {
+    case MODE_PARTIAL_INT:
+    case MODE_INT:
+      if (precision == CHAR_TYPE_SIZE)
+       return true;
+      if (precision == SHORT_TYPE_SIZE)
+       return true;
+      if (precision == INT_TYPE_SIZE)
+       return true;
+      if (precision == LONG_TYPE_SIZE)
+       return true;
+      if (precision == LONG_LONG_TYPE_SIZE)
+       return true;
+      return false;
+
+    case MODE_FLOAT:
+      if (precision == FLOAT_TYPE_SIZE)
+       return true;
+      if (precision == DOUBLE_TYPE_SIZE)
+       return true;
+      if (precision == LONG_DOUBLE_TYPE_SIZE)
+       return true;
+      return false;
+
+    case MODE_DECIMAL_FLOAT:
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* This routine handles all the normal conditional branch sequences we
    might need to generate.  It handles compare immediate vs compare
    register, nullification of delay slots, varying length branches,
@@ -6132,13 +6032,15 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
    parameters.  */
 
 const char *
-output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
+output_cbranch (rtx *operands, int negated, rtx insn)
 {
   static char buf[100];
   int useskip = 0;
-  rtx xoperands[5];
+  int nullify = INSN_ANNULLED_BRANCH_P (insn);
+  int length = get_attr_length (insn);
+  int xdelay;
 
-  /* A conditional branch to the following instruction (eg the delay slot)
+  /* A conditional branch to the following instruction (e.g. the delay slot)
      is asking for a disaster.  This can happen when not optimizing and
      when jump optimization fails.
 
@@ -6155,6 +6057,8 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
      zero for cmpb, we must ensure that we use cmpb for the comparison.  */
   if (GET_MODE (operands[1]) == DImode && operands[2] == const0_rtx)
     operands[2] = gen_rtx_REG (DImode, 0);
+  if (GET_MODE (operands[2]) == DImode && operands[1] == const0_rtx)
+    operands[1] = gen_rtx_REG (DImode, 0);
 
   /* If this is a long branch with its delay slot unfilled, set `nullify'
      as it can nullify the delay slot and save a nop.  */
@@ -6204,7 +6108,7 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
        with an unfilled delay slot.  */
       case 8:
        /* Handle weird backwards branch with a filled delay slot
-          with is nullified.  */
+          which is nullified.  */
        if (dbr_sequence_length () != 0
            && ! forward_branch_p (insn)
            && nullify)
@@ -6251,19 +6155,24 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
          }
        break;
 
-      case 20:
-      case 28:
-       xoperands[0] = operands[0];
-       xoperands[1] = operands[1];
-       xoperands[2] = operands[2];
-       xoperands[3] = operands[3];
-
+      default:
        /* The reversed conditional branch must branch over one additional
-          instruction if the delay slot is filled.  If the delay slot
-          is empty, the instruction after the reversed condition branch
-          must be nullified.  */
-       nullify = dbr_sequence_length () == 0;
-       xoperands[4] = nullify ? GEN_INT (length) : GEN_INT (length + 4);
+          instruction if the delay slot is filled and needs to be extracted
+          by output_lbranch.  If the delay slot is empty or this is a
+          nullified forward branch, the instruction after the reversed
+          condition branch must be nullified.  */
+       if (dbr_sequence_length () == 0
+           || (nullify && forward_branch_p (insn)))
+         {
+           nullify = 1;
+           xdelay = 0;
+           operands[4] = GEN_INT (length);
+         }
+       else
+         {
+           xdelay = 1;
+           operands[4] = GEN_INT (length + 4);
+         }
 
        /* Create a reversed conditional branch which branches around
           the following insns.  */
@@ -6310,39 +6219,47 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
              }
          }
 
-       output_asm_insn (buf, xoperands);
-       return output_lbranch (operands[0], insn);
-
-      default:
-       abort ();
+       output_asm_insn (buf, operands);
+       return output_lbranch (operands[0], insn, xdelay);
     }
   return buf;
 }
 
-/* This routine handles long unconditional branches that exceed the
-   maximum range of a simple branch instruction.  */
+/* This routine handles output of long unconditional branches that
+   exceed the maximum range of a simple branch instruction.  Since
+   we don't have a register available for the branch, we save register
+   %r1 in the frame marker, load the branch destination DEST into %r1,
+   execute the branch, and restore %r1 in the delay slot of the branch.
+
+   Since long branches may have an insn in the delay slot and the
+   delay slot is used to restore %r1, we in general need to extract
+   this insn and execute it before the branch.  However, to facilitate
+   use of this function by conditional branches, we also provide an
+   option to not extract the delay insn so that it will be emitted
+   after the long branch.  So, if there is an insn in the delay slot,
+   it is extracted if XDELAY is nonzero.
+
+   The lengths of the various long-branch sequences are 20, 16 and 24
+   bytes for the portable runtime, non-PIC and PIC cases, respectively.  */
 
 const char *
-output_lbranch (rtx dest, rtx insn)
+output_lbranch (rtx dest, rtx insn, int xdelay)
 {
   rtx xoperands[2];
  
   xoperands[0] = dest;
 
   /* First, free up the delay slot.  */
-  if (dbr_sequence_length () != 0)
+  if (xdelay && dbr_sequence_length () != 0)
     {
       /* We can't handle a jump in the delay slot.  */
-      if (GET_CODE (NEXT_INSN (insn)) == JUMP_INSN)
-       abort ();
+      gcc_assert (GET_CODE (NEXT_INSN (insn)) != JUMP_INSN);
 
       final_scan_insn (NEXT_INSN (insn), asm_out_file,
-                      optimize, 0, 0, NULL);
+                      optimize, 0, NULL);
 
       /* Now delete the delay insn.  */
-      PUT_CODE (NEXT_INSN (insn), NOTE);
-      NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-      NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+      SET_INSN_DELETED (NEXT_INSN (insn));
     }
 
   /* Output an insn to save %r1.  The runtime documentation doesn't
@@ -6367,7 +6284,7 @@ output_lbranch (rtx dest, rtx insn)
      for other purposes.  */
   if (TARGET_64BIT)
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        /* Use the return pointer slot in the frame marker.  */
        output_asm_insn ("std %%r1,-16(%%r30)", xoperands);
       else
@@ -6377,7 +6294,7 @@ output_lbranch (rtx dest, rtx insn)
     }
   else
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        /* Use the return pointer slot in the frame marker.  */
        output_asm_insn ("stw %%r1,-20(%%r30)", xoperands);
       else
@@ -6403,8 +6320,8 @@ output_lbranch (rtx dest, rtx insn)
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("addil L'%l0-%l1,%%r1", xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
          output_asm_insn ("ldo R'%l0-%l1(%%r1),%%r1", xoperands);
        }
       else
@@ -6421,14 +6338,14 @@ output_lbranch (rtx dest, rtx insn)
   /* Now restore the value of %r1 in the delay slot.  */
   if (TARGET_64BIT)
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        return "ldd -16(%%r30),%%r1";
       else
        return "ldd -40(%%r30),%%r1";
     }
   else
     {
-      if (actual_fsize == 0 && !regs_ever_live[2])
+      if (actual_fsize == 0 && !df_regs_ever_live_p (2))
        return "ldw -20(%%r30),%%r1";
       else
        return "ldw -12(%%r30),%%r1";
@@ -6441,13 +6358,15 @@ output_lbranch (rtx dest, rtx insn)
    above.  it returns the appropriate output template to emit the branch.  */
 
 const char *
-output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
-          int negated, rtx insn, int which)
+output_bb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
 {
   static char buf[100];
   int useskip = 0;
+  int nullify = INSN_ANNULLED_BRANCH_P (insn);
+  int length = get_attr_length (insn);
+  int xdelay;
 
-  /* A conditional branch to the following instruction (eg the delay slot) is
+  /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  I do not think this can happen as this pattern
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
@@ -6512,7 +6431,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
        with an unfilled delay slot.  */
       case 8:
        /* Handle weird backwards branch with a filled delay slot
-          with is nullified.  */
+          which is nullified.  */
        if (dbr_sequence_length () != 0
            && ! forward_branch_p (insn)
            && nullify)
@@ -6554,9 +6473,10 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
          }
        else
          {
-           strcpy (buf, "{extrs,|extrw,s,}");
            if (GET_MODE (operands[0]) == DImode)
              strcpy (buf, "extrd,s,*");
+           else
+             strcpy (buf, "{extrs,|extrw,s,}");
            if ((which == 0 && negated)
                || (which == 1 && ! negated))
              strcat (buf, "<");
@@ -6571,10 +6491,43 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
            else
              strcat (buf, " %0,%1,1,%%r0\n\tb %2");
          }
-       break;
+       break;
+
+      default:
+       /* The reversed conditional branch must branch over one additional
+          instruction if the delay slot is filled and needs to be extracted
+          by output_lbranch.  If the delay slot is empty or this is a
+          nullified forward branch, the instruction after the reversed
+          condition branch must be nullified.  */
+       if (dbr_sequence_length () == 0
+           || (nullify && forward_branch_p (insn)))
+         {
+           nullify = 1;
+           xdelay = 0;
+           operands[4] = GEN_INT (length);
+         }
+       else
+         {
+           xdelay = 1;
+           operands[4] = GEN_INT (length + 4);
+         }
 
-      default:
-       abort ();
+       if (GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "bb,*");
+       else
+         strcpy (buf, "bb,");
+       if ((which == 0 && negated)
+           || (which == 1 && !negated))
+         strcat (buf, "<");
+       else
+         strcat (buf, ">=");
+       if (nullify)
+         strcat (buf, ",n %0,%1,.+%4");
+       else
+         strcat (buf, " %0,%1,.+%4");
+       output_asm_insn (buf, operands);
+       return output_lbranch (negated ? operands[3] : operands[2],
+                              insn, xdelay);
     }
   return buf;
 }
@@ -6586,13 +6539,15 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
    branch.  */
 
 const char *
-output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
-           int negated, rtx insn, int which)
+output_bvb (rtx *operands ATTRIBUTE_UNUSED, int negated, rtx insn, int which)
 {
   static char buf[100];
   int useskip = 0;
+  int nullify = INSN_ANNULLED_BRANCH_P (insn);
+  int length = get_attr_length (insn);
+  int xdelay;
 
-  /* A conditional branch to the following instruction (eg the delay slot) is
+  /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  I do not think this can happen as this pattern
      is only used when optimizing; jump optimization should eliminate the
      jump.  But be prepared just in case.  */
@@ -6657,7 +6612,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
        with an unfilled delay slot.  */
       case 8:
        /* Handle weird backwards branch with a filled delay slot
-          with is nullified.  */
+          which is nullified.  */
        if (dbr_sequence_length () != 0
            && ! forward_branch_p (insn)
            && nullify)
@@ -6719,7 +6674,40 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
        break;
 
       default:
-       abort ();
+       /* The reversed conditional branch must branch over one additional
+          instruction if the delay slot is filled and needs to be extracted
+          by output_lbranch.  If the delay slot is empty or this is a
+          nullified forward branch, the instruction after the reversed
+          condition branch must be nullified.  */
+       if (dbr_sequence_length () == 0
+           || (nullify && forward_branch_p (insn)))
+         {
+           nullify = 1;
+           xdelay = 0;
+           operands[4] = GEN_INT (length);
+         }
+       else
+         {
+           xdelay = 1;
+           operands[4] = GEN_INT (length + 4);
+         }
+
+       if (GET_MODE (operands[0]) == DImode)
+         strcpy (buf, "bb,*");
+       else
+         strcpy (buf, "{bvb,|bb,}");
+       if ((which == 0 && negated)
+           || (which == 1 && !negated))
+         strcat (buf, "<");
+       else
+         strcat (buf, ">=");
+       if (nullify)
+         strcat (buf, ",n {%0,.+%4|%0,%%sar,.+%4}");
+       else
+         strcat (buf, " {%0,.+%4|%0,%%sar,.+%4}");
+       output_asm_insn (buf, operands);
+       return output_lbranch (negated ? operands[3] : operands[2],
+                              insn, xdelay);
     }
   return buf;
 }
@@ -6731,8 +6719,9 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
 const char *
 output_dbra (rtx *operands, rtx insn, int which_alternative)
 {
+  int length = get_attr_length (insn);
 
-  /* A conditional branch to the following instruction (eg the delay slot) is
+  /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
   if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
@@ -6756,7 +6745,7 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
   if (which_alternative == 0)
     {
       int nullify = INSN_ANNULLED_BRANCH_P (insn);
-      int length = get_attr_length (insn);
+      int xdelay;
 
       /* If this is a long branch with its delay slot unfilled, set `nullify'
         as it can nullify the delay slot and save a nop.  */
@@ -6768,13 +6757,15 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
       if (! nullify && length == 4 && dbr_sequence_length () == 0)
        nullify = forward_branch_p (insn);
 
-      /* Handle short versions first.  */
-      if (length == 4 && nullify)
-       return "addib,%C2,n %1,%0,%3";
-      else if (length == 4 && ! nullify)
-       return "addib,%C2 %1,%0,%3";
-      else if (length == 8)
+      switch (length)
        {
+       case 4:
+         if (nullify)
+           return "addib,%C2,n %1,%0,%3";
+         else
+           return "addib,%C2 %1,%0,%3";
+      
+       case 8:
          /* Handle weird backwards branch with a fulled delay slot
             which is nullified.  */
          if (dbr_sequence_length () != 0
@@ -6796,9 +6787,34 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
            return "addi,%N2 %1,%0,%0\n\tb,n %3";
          else
            return "addi,%N2 %1,%0,%0\n\tb %3";
+
+       default:
+         /* The reversed conditional branch must branch over one additional
+            instruction if the delay slot is filled and needs to be extracted
+            by output_lbranch.  If the delay slot is empty or this is a
+            nullified forward branch, the instruction after the reversed
+            condition branch must be nullified.  */
+         if (dbr_sequence_length () == 0
+             || (nullify && forward_branch_p (insn)))
+           {
+             nullify = 1;
+             xdelay = 0;
+             operands[4] = GEN_INT (length);
+           }
+         else
+           {
+             xdelay = 1;
+             operands[4] = GEN_INT (length + 4);
+           }
+
+         if (nullify)
+           output_asm_insn ("addib,%N2,n %1,%0,.+%4", operands);
+         else
+           output_asm_insn ("addib,%N2 %1,%0,.+%4", operands);
+
+         return output_lbranch (operands[3], insn, xdelay);
        }
-      else
-       abort ();
+      
     }
   /* Deal with gross reload from FP register case.  */
   else if (which_alternative == 1)
@@ -6809,10 +6825,17 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
       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)
+      if (length == 24)
        return "{comb|cmpb},%S2 %%r0,%4,%3\n\t{fldws|fldw} -16(%%r30),%0";
-      else
+      else if (length == 28)
        return "{comclr|cmpclr},%B2 %%r0,%4,%%r0\n\tb %3\n\t{fldws|fldw} -16(%%r30),%0";
+      else
+       {
+         operands[5] = GEN_INT (length - 16);
+         output_asm_insn ("{comb|cmpb},%B2 %%r0,%4,.+%5", operands);
+         output_asm_insn ("{fldws|fldw} -16(%%r30),%0", operands);
+         return output_lbranch (operands[3], insn, 0);
+       }
     }
   /* Deal with gross reload from memory case.  */
   else
@@ -6820,14 +6843,20 @@ output_dbra (rtx *operands, rtx insn, int which_alternative)
       /* Reload loop counter from memory, the store back to memory
         happens in the branch's delay slot.  */
       output_asm_insn ("ldw %0,%4", operands);
-      if (get_attr_length (insn) == 12)
+      if (length == 12)
        return "addib,%C2 %1,%4,%3\n\tstw %4,%0";
-      else
+      else if (length == 16)
        return "addi,%N2 %1,%4,%4\n\tb %3\n\tstw %4,%0";
+      else
+       {
+         operands[5] = GEN_INT (length - 4);
+         output_asm_insn ("addib,%N2 %1,%4,.+%5\n\tstw %4,%0", operands);
+         return output_lbranch (operands[3], insn, 0);
+       }
     }
 }
 
-/* Return the output template for emitting a dbra type insn.
+/* Return the output template for emitting a movb type insn.
 
    Note it may perform some output operations on its own before
    returning the final output string.  */
@@ -6835,8 +6864,9 @@ const char *
 output_movb (rtx *operands, rtx insn, int which_alternative,
             int reverse_comparison)
 {
+  int length = get_attr_length (insn);
 
-  /* A conditional branch to the following instruction (eg the delay slot) is
+  /* A conditional branch to the following instruction (e.g. the delay slot) is
      asking for a disaster.  Be prepared!  */
 
   if (next_real_insn (JUMP_LABEL (insn)) == next_real_insn (insn))
@@ -6861,7 +6891,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
   if (which_alternative == 0)
     {
       int nullify = INSN_ANNULLED_BRANCH_P (insn);
-      int length = get_attr_length (insn);
+      int xdelay;
 
       /* If this is a long branch with its delay slot unfilled, set `nullify'
         as it can nullify the delay slot and save a nop.  */
@@ -6873,13 +6903,15 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
       if (! nullify && length == 4 && dbr_sequence_length () == 0)
        nullify = forward_branch_p (insn);
 
-      /* Handle short versions first.  */
-      if (length == 4 && nullify)
-       return "movb,%C2,n %1,%0,%3";
-      else if (length == 4 && ! nullify)
-       return "movb,%C2 %1,%0,%3";
-      else if (length == 8)
+      switch (length)
        {
+       case 4:
+         if (nullify)
+           return "movb,%C2,n %1,%0,%3";
+         else
+           return "movb,%C2 %1,%0,%3";
+
+       case 8:
          /* Handle weird backwards branch with a filled delay slot
             which is nullified.  */
          if (dbr_sequence_length () != 0
@@ -6901,39 +6933,84 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
            return "or,%N2 %1,%%r0,%0\n\tb,n %3";
          else
            return "or,%N2 %1,%%r0,%0\n\tb %3";
+
+       default:
+         /* The reversed conditional branch must branch over one additional
+            instruction if the delay slot is filled and needs to be extracted
+            by output_lbranch.  If the delay slot is empty or this is a
+            nullified forward branch, the instruction after the reversed
+            condition branch must be nullified.  */
+         if (dbr_sequence_length () == 0
+             || (nullify && forward_branch_p (insn)))
+           {
+             nullify = 1;
+             xdelay = 0;
+             operands[4] = GEN_INT (length);
+           }
+         else
+           {
+             xdelay = 1;
+             operands[4] = GEN_INT (length + 4);
+           }
+
+         if (nullify)
+           output_asm_insn ("movb,%N2,n %1,%0,.+%4", operands);
+         else
+           output_asm_insn ("movb,%N2 %1,%0,.+%4", operands);
+
+         return output_lbranch (operands[3], insn, xdelay);
        }
-      else
-       abort ();
     }
-  /* Deal with gross reload from FP register case.  */
+  /* Deal with gross reload for FP destination register case.  */
   else if (which_alternative == 1)
     {
-      /* 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.  */
+      /* Move source register to MEM, perform the branch test, then
+        finally load the FP register from MEM from within the branch's
+        delay slot.  */
       output_asm_insn ("stw %1,-16(%%r30)", operands);
-      if (get_attr_length (insn) == 12)
+      if (length == 12)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\t{fldws|fldw} -16(%%r30),%0";
-      else
+      else if (length == 16)
        return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\t{fldws|fldw} -16(%%r30),%0";
+      else
+       {
+         operands[4] = GEN_INT (length - 4);
+         output_asm_insn ("{comb|cmpb},%B2 %%r0,%1,.+%4", operands);
+         output_asm_insn ("{fldws|fldw} -16(%%r30),%0", operands);
+         return output_lbranch (operands[3], insn, 0);
+       }
     }
   /* Deal with gross reload from memory case.  */
   else if (which_alternative == 2)
     {
       /* Reload loop counter from memory, the store back to memory
         happens in the branch's delay slot.  */
-      if (get_attr_length (insn) == 8)
+      if (length == 8)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\tstw %1,%0";
-      else
+      else if (length == 12)
        return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tstw %1,%0";
+      else
+       {
+         operands[4] = GEN_INT (length);
+         output_asm_insn ("{comb|cmpb},%B2 %%r0,%1,.+%4\n\tstw %1,%0",
+                          operands);
+         return output_lbranch (operands[3], insn, 0);
+       }
     }
   /* Handle SAR as a destination.  */
   else
     {
-      if (get_attr_length (insn) == 8)
+      if (length == 8)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\tmtsar %r1";
+      else if (length == 12)
+       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tmtsar %r1";
       else
-       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tbl %3\n\tmtsar %r1";
+       {
+         operands[4] = GEN_INT (length);
+         output_asm_insn ("{comb|cmpb},%B2 %%r0,%1,.+%4\n\tmtsar %r1",
+                          operands);
+         return output_lbranch (operands[3], insn, 0);
+       }
     }
 }
 
@@ -7103,7 +7180,7 @@ output_millicode_call (rtx insn, rtx call_dest)
            {
              xoperands[1] = gen_label_rtx ();
              output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
-             (*targetm.asm_out.internal_label) (asm_out_file, "L",
+             targetm.asm_out.internal_label (asm_out_file, "L",
                                         CODE_LABEL_NUMBER (xoperands[1]));
              output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
            }
@@ -7147,7 +7224,7 @@ output_millicode_call (rtx insn, rtx call_dest)
                 millicode symbol but not an arbitrary external
                 symbol when generating SOM output.  */
              xoperands[1] = gen_label_rtx ();
-             (*targetm.asm_out.internal_label) (asm_out_file, "L",
+             targetm.asm_out.internal_label (asm_out_file, "L",
                                         CODE_LABEL_NUMBER (xoperands[1]));
              output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
              output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
@@ -7186,8 +7263,8 @@ output_millicode_call (rtx insn, rtx call_dest)
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("ldo %0-%1(%2),%2", xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
        }
       else
        /* ??? This branch may not reach its target.  */
@@ -7198,9 +7275,7 @@ output_millicode_call (rtx insn, rtx call_dest)
     output_asm_insn ("nop\n\tb,n %0", xoperands);
 
   /* Delete the jump.  */
-  PUT_CODE (NEXT_INSN (insn), NOTE);
-  NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+  SET_INSN_DELETED (NEXT_INSN (insn));
 
   return "";
 }
@@ -7245,7 +7320,7 @@ attr_length_call (rtx insn, int sibcall)
     call_dest = XEXP (XEXP (XEXP (XVECEXP (pat, 0, 0), 1), 0), 0);
 
   call_decl = SYMBOL_REF_DECL (call_dest);
-  local_call = call_decl && (*targetm.binds_local_p) (call_decl);
+  local_call = call_decl && targetm.binds_local_p (call_decl);
 
   /* pc-relative branch.  */
   if (!TARGET_LONG_CALLS
@@ -7264,7 +7339,8 @@ attr_length_call (rtx insn, int sibcall)
   /* long pc-relative branch sequence.  */
   else if ((TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
           || (TARGET_64BIT && !TARGET_GAS)
-          || (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call)))
+          || (TARGET_GAS && !TARGET_SOM
+              && (TARGET_LONG_PIC_PCREL_CALL || local_call)))
     {
       length += 20;
 
@@ -7308,7 +7384,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
   int delay_slot_filled = 0;
   int seq_length = dbr_sequence_length ();
   tree call_decl = SYMBOL_REF_DECL (call_dest);
-  int local_call = call_decl && (*targetm.binds_local_p) (call_decl);
+  int local_call = call_decl && targetm.binds_local_p (call_decl);
   rtx xoperands[2];
 
   xoperands[0] = call_dest;
@@ -7328,9 +7404,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
          /* ??? As far as I can tell, the HP linker doesn't support the
             long pc-relative sequence described in the 64-bit runtime
             architecture.  So, we use a slightly longer indirect call.  */
-         struct deferred_plabel *p = get_plabel (XSTR (call_dest, 0));
-
-         xoperands[0] = p->internal_label;
+         xoperands[0] = get_deferred_plabel (call_dest);
          xoperands[1] = gen_label_rtx ();
 
          /* If this isn't a sibcall, we put the load of %r27 into the
@@ -7341,12 +7415,10 @@ output_call (rtx insn, rtx call_dest, int sibcall)
              && !sibcall)
            {
              final_scan_insn (NEXT_INSN (insn), asm_out_file,
-                              optimize, 0, 0, NULL);
+                              optimize, 0, NULL);
 
              /* Now delete the delay insn.  */
-             PUT_CODE (NEXT_INSN (insn), NOTE);
-             NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+             SET_INSN_DELETED (NEXT_INSN (insn));
              delay_insn_deleted = 1;
            }
 
@@ -7377,7 +7449,8 @@ output_call (rtx insn, rtx call_dest, int sibcall)
              they don't allow an instruction in the delay slot.  */
          if (!((TARGET_LONG_ABS_CALL || local_call) && !flag_pic)
              && !(TARGET_SOM && TARGET_LONG_PIC_SDIFF_CALL)
-             && !(TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
+             && !(TARGET_GAS && !TARGET_SOM
+                  && (TARGET_LONG_PIC_PCREL_CALL || local_call))
              && !TARGET_64BIT)
            indirect_call = 1;
 
@@ -7389,13 +7462,11 @@ output_call (rtx insn, rtx call_dest, int sibcall)
              /* A non-jump insn in the delay slot.  By definition we can
                 emit this insn before the call (and in fact before argument
                 relocating.  */
-             final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0, 0,
+             final_scan_insn (NEXT_INSN (insn), asm_out_file, optimize, 0,
                               NULL);
 
              /* Now delete the delay insn.  */
-             PUT_CODE (NEXT_INSN (insn), NOTE);
-             NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+             SET_INSN_DELETED (NEXT_INSN (insn));
              delay_insn_deleted = 1;
            }
 
@@ -7433,11 +7504,12 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                  xoperands[1] = gen_label_rtx ();
                  output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
                  output_asm_insn ("addil L'%0-%l1,%%r1", xoperands);
-                 (*targetm.asm_out.internal_label) (asm_out_file, "L",
+                 targetm.asm_out.internal_label (asm_out_file, "L",
                                             CODE_LABEL_NUMBER (xoperands[1]));
                  output_asm_insn ("ldo R'%0-%l1(%%r1),%%r1", xoperands);
                }
-             else if (TARGET_GAS && (TARGET_LONG_PIC_PCREL_CALL || local_call))
+             else if (TARGET_GAS && !TARGET_SOM
+                      && (TARGET_LONG_PIC_PCREL_CALL || local_call))
                {
                  /*  GAS currently can't generate the relocations that
                      are needed for the SOM linker under HP-UX using this
@@ -7457,9 +7529,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
                     essentially an inline implementation of $$dyncall.
                     We don't actually try to call $$dyncall as this is
                     as difficult as calling the function itself.  */
-                 struct deferred_plabel *p = get_plabel (XSTR (call_dest, 0));
-
-                 xoperands[0] = p->internal_label;
+                 xoperands[0] = get_deferred_plabel (call_dest);
                  xoperands[1] = gen_label_rtx ();
 
                  /* Since the call is indirect, FP arguments in registers
@@ -7554,8 +7624,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
     return "";
 
   /* A sibcall should never have a branch in the delay slot.  */
-  if (sibcall)
-    abort ();
+  gcc_assert (!sibcall);
 
   /* This call has an unconditional jump in its delay slot.  */
   xoperands[0] = XEXP (PATTERN (NEXT_INSN (insn)), 1);
@@ -7572,8 +7641,8 @@ output_call (rtx insn, rtx call_dest, int sibcall)
        {
          xoperands[1] = gen_label_rtx ();
          output_asm_insn ("ldo %0-%1(%%r2),%%r2", xoperands);
-         (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                            CODE_LABEL_NUMBER (xoperands[1]));
+         targetm.asm_out.internal_label (asm_out_file, "L",
+                                         CODE_LABEL_NUMBER (xoperands[1]));
        }
       else
        output_asm_insn ("nop\n\tb,n %0", xoperands);
@@ -7582,9 +7651,7 @@ output_call (rtx insn, rtx call_dest, int sibcall)
     output_asm_insn ("b,n %0", xoperands);
 
   /* Delete the jump.  */
-  PUT_CODE (NEXT_INSN (insn), NOTE);
-  NOTE_LINE_NUMBER (NEXT_INSN (insn)) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (NEXT_INSN (insn)) = 0;
+  SET_INSN_DELETED (NEXT_INSN (insn));
 
   return "";
 }
@@ -7613,7 +7680,8 @@ attr_length_indirect_call (rtx insn)
 
   if (TARGET_FAST_INDIRECT_CALLS
       || (!TARGET_PORTABLE_RUNTIME
-         && ((TARGET_PA_20 && distance < 7600000) || distance < 240000)))
+         && ((TARGET_PA_20 && !TARGET_SOM && distance < 7600000)
+             || distance < 240000)))
     return 8;
 
   if (flag_pic)
@@ -7650,10 +7718,10 @@ output_indirect_call (rtx insn, rtx call_dest)
      the remaining cases.  */
   if (attr_length_indirect_call (insn) == 8)
     {
-      /* The HP linker substitutes a BLE for millicode calls using
-        the short PIC PCREL form.  Thus, we must use %r31 as the
-        link register when generating PA 1.x code.  */
-      if (TARGET_PA_20)
+      /* The HP linker sometimes substitutes a BLE for BL/B,L calls to
+        $$dyncall.  Since BLE uses %r31 as the link register, the 22-bit
+        variant of the B,L instruction can't be used on the SOM target.  */
+      if (TARGET_PA_20 && !TARGET_SOM)
        return ".CALL\tARGW0=GR\n\tb,l $$dyncall,%%r2\n\tcopy %%r2,%%r31";
       else
        return ".CALL\tARGW0=GR\n\tbl $$dyncall,%%r31\n\tcopy %%r31,%%r2";
@@ -7675,8 +7743,8 @@ output_indirect_call (rtx insn, rtx call_dest)
     {
       xoperands[0] = gen_label_rtx ();
       output_asm_insn ("addil L'$$dyncall-%0,%%r1", xoperands);
-      (*targetm.asm_out.internal_label) (asm_out_file, "L",
-                                        CODE_LABEL_NUMBER (xoperands[0]));
+      targetm.asm_out.internal_label (asm_out_file, "L",
+                                     CODE_LABEL_NUMBER (xoperands[0]));
       output_asm_insn ("ldo R'$$dyncall-%0(%%r1),%%r1", xoperands);
     }
   else
@@ -7727,6 +7795,8 @@ hppa_encode_label (rtx sym)
 static void
 pa_encode_section_info (tree decl, rtx rtl, int first)
 {
+  default_encode_section_info (decl, rtl, first);
+
   if (first && TEXT_SPACE_P (decl))
     {
       SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
@@ -7773,18 +7843,18 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
                        HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
                        tree function)
 {
-  const char *fname = XSTR (XEXP (DECL_RTL (function), 0), 0);
-  const char *tname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
+  static unsigned int current_thunk_number;
   int val_14 = VAL_14_BITS_P (delta);
   int nbytes = 0;
-  static unsigned int current_thunk_number;
   char label[16];
+  rtx xoperands[4];
 
-  ASM_OUTPUT_LABEL (file, tname);
-  fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=0,NO_CALLS\n\t.ENTRY\n");
+  xoperands[0] = XEXP (DECL_RTL (function), 0);
+  xoperands[1] = XEXP (DECL_RTL (thunk_fndecl), 0);
+  xoperands[2] = GEN_INT (delta);
 
-  fname = (*targetm.strip_name_encoding) (fname);
-  tname = (*targetm.strip_name_encoding) (tname);
+  ASM_OUTPUT_LABEL (file, XSTR (xoperands[1], 0));
+  fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=0,NO_CALLS\n\t.ENTRY\n");
 
   /* Output the thunk.  We know that the function is in the same
      translation unit (i.e., the same space) as the thunk, and that
@@ -7816,18 +7886,19 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
                       && last_address < 262132)))
              || (!targetm.have_named_sections && last_address < 262132))))
     {
+      if (!val_14)
+       output_asm_insn ("addil L'%2,%%r26", xoperands);
+
+      output_asm_insn ("b %0", xoperands);
+
       if (val_14)
        {
-         fprintf (file, "\tb %s\n\tldo " HOST_WIDE_INT_PRINT_DEC
-                        "(%%r26),%%r26\n", fname, delta);
+         output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
          nbytes += 8;
        }
       else
        {
-         fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
-                        ",%%r26\n", delta);
-         fprintf (file, "\tb %s\n\tldo R'" HOST_WIDE_INT_PRINT_DEC
-                        "(%%r1),%%r26\n", fname, delta);
+         output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
          nbytes += 12;
        }
     }
@@ -7836,53 +7907,54 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
       /* We only have one call-clobbered scratch register, so we can't
          make use of the delay slot if delta doesn't fit in 14 bits.  */
       if (!val_14)
-       fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
-                      ",%%r26\n\tldo R'" HOST_WIDE_INT_PRINT_DEC
-                      "(%%r1),%%r26\n", delta, delta);
+       {
+         output_asm_insn ("addil L'%2,%%r26", xoperands);
+         output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
+       }
 
-      fprintf (file, "\tb,l .+8,%%r1\n");
+      output_asm_insn ("b,l .+8,%%r1", xoperands);
 
       if (TARGET_GAS)
        {
-         fprintf (file, "\taddil L'%s-$PIC_pcrel$0+4,%%r1\n", fname);
-         fprintf (file, "\tldo R'%s-$PIC_pcrel$0+8(%%r1),%%r1\n", fname);
+         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);
        }
       else
        {
-         int off = val_14 ? 8 : 16;
-         fprintf (file, "\taddil L'%s-%s-%d,%%r1\n", fname, tname, off);
-         fprintf (file, "\tldo R'%s-%s-%d(%%r1),%%r1\n", fname, tname, off);
+         xoperands[3] = GEN_INT (val_14 ? 8 : 16);
+         output_asm_insn ("addil L'%0-%1-%3,%%r1", xoperands);
        }
 
       if (val_14)
        {
-         fprintf (file, "\tbv %%r0(%%r1)\n\tldo ");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
+         output_asm_insn ("bv %%r0(%%r1)", xoperands);
+         output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
          nbytes += 20;
        }
       else
        {
-         fprintf (file, "\tbv,n %%r0(%%r1)\n");
+         output_asm_insn ("bv,n %%r0(%%r1)", xoperands);
          nbytes += 24;
        }
     }
   else if (TARGET_PORTABLE_RUNTIME)
     {
-      fprintf (file, "\tldil L'%s,%%r1\n", fname);
-      fprintf (file, "\tldo R'%s(%%r1),%%r22\n", fname);
+      output_asm_insn ("ldil L'%0,%%r1", xoperands);
+      output_asm_insn ("ldo R'%0(%%r1),%%r22", xoperands);
+
+      if (!val_14)
+       output_asm_insn ("addil L'%2,%%r26", xoperands);
+
+      output_asm_insn ("bv %%r0(%%r22)", xoperands);
 
       if (val_14)
        {
-         fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
+         output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
          nbytes += 16;
        }
       else
        {
-         fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
-                        ",%%r26\n", delta);
-         fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
-         fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
+         output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
          nbytes += 20;
        }
     }
@@ -7893,112 +7965,113 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
         call the function directly with an indirect sequence similar to
         that used by $$dyncall.  This is possible because $$dyncall acts
         as the import stub in an indirect call.  */
-      const char *lab;
-
       ASM_GENERATE_INTERNAL_LABEL (label, "LTHN", current_thunk_number);
-      lab = (*targetm.strip_name_encoding) (label);
-
-      fprintf (file, "\taddil LT'%s,%%r19\n", lab);
-      fprintf (file, "\tldw RT'%s(%%r1),%%r22\n", lab);
-      fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
-      fprintf (file, "\tbb,>=,n %%r22,30,.+16\n");
-      fprintf (file, "\tdepi 0,31,2,%%r22\n");
-      fprintf (file, "\tldw 4(%%sr0,%%r22),%%r19\n");
-      fprintf (file, "\tldw 0(%%sr0,%%r22),%%r22\n");
+      xoperands[3] = gen_rtx_SYMBOL_REF (Pmode, label);
+      output_asm_insn ("addil LT'%3,%%r19", xoperands);
+      output_asm_insn ("ldw RT'%3(%%r1),%%r22", xoperands);
+      output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands);
+      output_asm_insn ("bb,>=,n %%r22,30,.+16", xoperands);
+      output_asm_insn ("depi 0,31,2,%%r22", xoperands);
+      output_asm_insn ("ldw 4(%%sr0,%%r22),%%r19", xoperands);
+      output_asm_insn ("ldw 0(%%sr0,%%r22),%%r22", xoperands);
+
       if (!val_14)
        {
-         fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
-                        ",%%r26\n", delta);
+         output_asm_insn ("addil L'%2,%%r26", xoperands);
          nbytes += 4;
        }
+
       if (TARGET_PA_20)
        {
-          fprintf (file, "\tbve (%%r22)\n\tldo ");
+         output_asm_insn ("bve (%%r22)", xoperands);
+         nbytes += 36;
+       }
+      else if (TARGET_NO_SPACE_REGS)
+       {
+         output_asm_insn ("be 0(%%sr4,%%r22)", xoperands);
          nbytes += 36;
        }
       else
        {
-         if (TARGET_NO_SPACE_REGS)
-           {
-             fprintf (file, "\tbe 0(%%sr4,%%r22)\n\tldo ");
-             nbytes += 36;
-           }
-         else
-           {
-             fprintf (file, "\tldsid (%%sr0,%%r22),%%r21\n");
-             fprintf (file, "\tmtsp %%r21,%%sr0\n");
-             fprintf (file, "\tbe 0(%%sr0,%%r22)\n\tldo ");
-             nbytes += 44;
-           }
+         output_asm_insn ("ldsid (%%sr0,%%r22),%%r21", xoperands);
+         output_asm_insn ("mtsp %%r21,%%sr0", xoperands);
+         output_asm_insn ("be 0(%%sr0,%%r22)", xoperands);
+         nbytes += 44;
        }
 
       if (val_14)
-       fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
+       output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
       else
-       fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
+       output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
     }
   else if (flag_pic)
     {
-      if (TARGET_PA_20)
-       fprintf (file, "\tb,l .+8,%%r1\n");
-      else
-       fprintf (file, "\tbl .+8,%%r1\n");
+      output_asm_insn ("{bl|b,l} .+8,%%r1", xoperands);
 
       if (TARGET_SOM || !TARGET_GAS)
        {
-         fprintf (file, "\taddil L'%s-%s-8,%%r1\n", fname, tname);
-         fprintf (file, "\tldo R'%s-%s-8(%%r1),%%r22\n", fname, tname);
+         output_asm_insn ("addil L'%0-%1-8,%%r1", xoperands);
+         output_asm_insn ("ldo R'%0-%1-8(%%r1),%%r22", xoperands);
        }
       else
        {
-         fprintf (file, "\taddil L'%s-$PIC_pcrel$0+4,%%r1\n", fname);
-         fprintf (file, "\tldo R'%s-$PIC_pcrel$0+8(%%r1),%%r22\n", fname);
+         output_asm_insn ("addil L'%0-$PIC_pcrel$0+4,%%r1", xoperands);
+         output_asm_insn ("ldo R'%0-$PIC_pcrel$0+8(%%r1),%%r22", xoperands);
        }
 
+      if (!val_14)
+       output_asm_insn ("addil L'%2,%%r26", xoperands);
+
+      output_asm_insn ("bv %%r0(%%r22)", xoperands);
+
       if (val_14)
        {
-         fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
+         output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
          nbytes += 20;
        }
       else
        {
-         fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC
-                        ",%%r26\n", delta);
-         fprintf (file, "\tbv %%r0(%%r22)\n\tldo ");
-         fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
+         output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
          nbytes += 24;
        }
     }
   else
     {
       if (!val_14)
-       fprintf (file, "\taddil L'" HOST_WIDE_INT_PRINT_DEC ",%%r26\n", delta);
+       output_asm_insn ("addil L'%2,%%r26", xoperands);
 
-      fprintf (file, "\tldil L'%s,%%r22\n", fname);
-      fprintf (file, "\tbe R'%s(%%sr4,%%r22)\n\tldo ", fname);
+      output_asm_insn ("ldil L'%0,%%r22", xoperands);
+      output_asm_insn ("be R'%0(%%sr4,%%r22)", xoperands);
 
       if (val_14)
        {
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC "(%%r26),%%r26\n", delta);
+         output_asm_insn ("ldo %2(%%r26),%%r26", xoperands);
          nbytes += 12;
        }
       else
        {
-         fprintf (file, "R'" HOST_WIDE_INT_PRINT_DEC "(%%r1),%%r26\n", delta);
+         output_asm_insn ("ldo R'%2(%%r1),%%r26", xoperands);
          nbytes += 16;
        }
     }
 
   fprintf (file, "\t.EXIT\n\t.PROCEND\n");
 
+  if (TARGET_SOM && TARGET_GAS)
+    {
+      /* We done with this subspace except possibly for some additional
+        debug information.  Forget that we are in this subspace to ensure
+        that the next function is output in its own subspace.  */
+      in_section = NULL;
+      cfun->machine->in_nsubspa = 2;
+    }
+
   if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
     {
-      data_section ();
-      fprintf (file, "\t.align 4\n");
+      switch_to_section (data_section);
+      output_asm_insn (".align 4", xoperands);
       ASM_OUTPUT_LABEL (file, label);
-      fprintf (file, "\t.word P'%s\n", fname);
-      function_section (thunk_fndecl);
+      output_asm_insn (".word P'%0", xoperands);
     }
 
   current_thunk_number++;
@@ -8034,6 +8107,9 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
 static bool
 pa_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
+  if (TARGET_PORTABLE_RUNTIME)
+    return false;
+
   /* Sibcalls are ok for TARGET_ELF32 as along as the linker is used in
      single subspace mode and the call is not indirect.  As far as I know,
      there is no operating system support for the multiple subspace mode.
@@ -8051,9 +8127,20 @@ pa_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   if (TARGET_64BIT)
     return false;
 
-  return (decl
-         && !TARGET_PORTABLE_RUNTIME
-         && !TREE_PUBLIC (decl));
+  /* Sibcalls are only ok within a translation unit.  */
+  return (decl && !TREE_PUBLIC (decl));
+}
+
+/* ??? Addition is not commutative on the PA due to the weird implicit
+   space register selection rules for memory addresses.  Therefore, we
+   don't consider a + b == b + a, as this might be inside a MEM.  */
+static bool
+pa_commutative_p (const_rtx x, int outer_code)
+{
+  return (COMMUTATIVE_P (x)
+         && (TARGET_NO_SPACE_REGS
+             || (outer_code != UNKNOWN && outer_code != MEM)
+             || GET_CODE (x) != PLUS));
 }
 
 /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
@@ -8089,13 +8176,13 @@ fmpyaddoperands (rtx *operands)
       && ! rtx_equal_p (operands[3], operands[5]))
     return 0;
 
-  /* Inout operand of add can not conflict with any operands from multiply.  */
+  /* Inout operand of add cannot conflict with any operands from multiply.  */
   if (rtx_equal_p (operands[3], operands[0])
      || rtx_equal_p (operands[3], operands[1])
      || rtx_equal_p (operands[3], operands[2]))
     return 0;
 
-  /* multiply can not feed into addition operands.  */
+  /* multiply cannot feed into addition operands.  */
   if (rtx_equal_p (operands[4], operands[0])
       || rtx_equal_p (operands[5], operands[0]))
     return 0;
@@ -8150,6 +8237,90 @@ pa_asm_out_destructor (rtx symbol, int priority)
 }
 #endif
 
+/* This function places uninitialized global data in the bss section.
+   The ASM_OUTPUT_ALIGNED_BSS macro needs to be defined to call this
+   function on the SOM port to prevent uninitialized global data from
+   being placed in the data section.  */
+   
+void
+pa_asm_output_aligned_bss (FILE *stream,
+                          const char *name,
+                          unsigned HOST_WIDE_INT size,
+                          unsigned int align)
+{
+  switch_to_section (bss_section);
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+
+#ifdef ASM_OUTPUT_TYPE_DIRECTIVE
+  ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "object");
+#endif
+
+#ifdef ASM_OUTPUT_SIZE_DIRECTIVE
+  ASM_OUTPUT_SIZE_DIRECTIVE (stream, name, size);
+#endif
+
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+  ASM_OUTPUT_LABEL (stream, name);
+  fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+}
+
+/* Both the HP and GNU assemblers under HP-UX provide a .comm directive
+   that doesn't allow the alignment of global common storage to be directly
+   specified.  The SOM linker aligns common storage based on the rounded
+   value of the NUM_BYTES parameter in the .comm directive.  It's not
+   possible to use the .align directive as it doesn't affect the alignment
+   of the label associated with a .comm directive.  */
+
+void
+pa_asm_output_aligned_common (FILE *stream,
+                             const char *name,
+                             unsigned HOST_WIDE_INT size,
+                             unsigned int align)
+{
+  unsigned int max_common_align;
+
+  max_common_align = TARGET_64BIT ? 128 : (size >= 4096 ? 256 : 64);
+  if (align > max_common_align)
+    {
+      warning (0, "alignment (%u) for %s exceeds maximum alignment "
+              "for global common data.  Using %u",
+              align / BITS_PER_UNIT, name, max_common_align / BITS_PER_UNIT);
+      align = max_common_align;
+    }
+
+  switch_to_section (bss_section);
+
+  assemble_name (stream, name);
+  fprintf (stream, "\t.comm "HOST_WIDE_INT_PRINT_UNSIGNED"\n",
+           MAX (size, align / BITS_PER_UNIT));
+}
+
+/* We can't use .comm for local common storage as the SOM linker effectively
+   treats the symbol as universal and uses the same storage for local symbols
+   with the same name in different object files.  The .block directive
+   reserves an uninitialized block of storage.  However, it's not common
+   storage.  Fortunately, GCC never requests common storage with the same
+   name in any given translation unit.  */
+
+void
+pa_asm_output_aligned_local (FILE *stream,
+                            const char *name,
+                            unsigned HOST_WIDE_INT size,
+                            unsigned int align)
+{
+  switch_to_section (bss_section);
+  fprintf (stream, "\t.align %u\n", align / BITS_PER_UNIT);
+
+#ifdef LOCAL_ASM_OP
+  fprintf (stream, "%s", LOCAL_ASM_OP);
+  assemble_name (stream, name);
+  fprintf (stream, "\n");
+#endif
+
+  ASM_OUTPUT_LABEL (stream, name);
+  fprintf (stream, "\t.block "HOST_WIDE_INT_PRINT_UNSIGNED"\n", size);
+}
+
 /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
    use in fmpysub instructions.  */
 int
@@ -8182,11 +8353,11 @@ fmpysuboperands (rtx *operands)
   if (! rtx_equal_p (operands[3], operands[4]))
     return 0;
 
-  /* multiply can not feed into subtraction.  */
+  /* multiply cannot feed into subtraction.  */
   if (rtx_equal_p (operands[5], operands[0]))
     return 0;
 
-  /* Inout operand of sub can not conflict with any operands from multiply.  */
+  /* Inout operand of sub cannot conflict with any operands from multiply.  */
   if (rtx_equal_p (operands[3], operands[0])
      || rtx_equal_p (operands[3], operands[1])
      || rtx_equal_p (operands[3], operands[2]))
@@ -8206,16 +8377,9 @@ fmpysuboperands (rtx *operands)
   return 1;
 }
 
-int
-plus_xor_ior_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == PLUS || GET_CODE (op) == XOR
-         || GET_CODE (op) == IOR);
-}
-
 /* Return 1 if the given constant is 2, 4, or 8.  These are the valid
    constants for shadd instructions.  */
-static int
+int
 shadd_constant_p (int val)
 {
   if (val == 2 || val == 4 || val == 8)
@@ -8224,14 +8388,6 @@ shadd_constant_p (int val)
     return 0;
 }
 
-/* Return 1 if OP is a CONST_INT with the value 2, 4, or 8.  These are
-   the valid constant for shadd instructions.  */
-int
-shadd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && shadd_constant_p (INTVAL (op)));
-}
-
 /* Return 1 if OP is valid as a base or index register in a
    REG+REG address.  */
 
@@ -8294,14 +8450,6 @@ eq_neq_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   return (GET_CODE (op) == EQ || GET_CODE (op) == NE);
 }
 
-/* Return 1 if OP is an operator suitable for use in a movb instruction.  */
-int
-movb_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == EQ || GET_CODE (op) == NE
-         || GET_CODE (op) == LT || GET_CODE (op) == GE);
-}
-
 /* Return 1 if INSN is in the delay slot of a call instruction.  */
 int
 jump_in_call_delay (rtx insn)
@@ -8327,37 +8475,50 @@ jump_in_call_delay (rtx insn)
 /* Output an unconditional move and branch insn.  */
 
 const char *
-output_parallel_movb (rtx *operands, int length)
+output_parallel_movb (rtx *operands, rtx insn)
 {
+  int length = get_attr_length (insn);
+
   /* These are the cases in which we win.  */
   if (length == 4)
     return "mov%I1b,tr %1,%0,%2";
 
-  /* None of these cases wins, but they don't lose either.  */
-  if (dbr_sequence_length () == 0)
+  /* None of the following cases win, but they don't lose either.  */
+  if (length == 8)
     {
-      /* Nothing in the delay slot, fake it by putting the combined
-        insn (the copy or add) in the delay slot of a bl.  */
-      if (GET_CODE (operands[1]) == CONST_INT)
-       return "b %2\n\tldi %1,%0";
+      if (dbr_sequence_length () == 0)
+       {
+         /* Nothing in the delay slot, fake it by putting the combined
+            insn (the copy or add) in the delay slot of a bl.  */
+         if (GET_CODE (operands[1]) == CONST_INT)
+           return "b %2\n\tldi %1,%0";
+         else
+           return "b %2\n\tcopy %1,%0";
+       }
       else
-       return "b %2\n\tcopy %1,%0";
+       {
+         /* Something in the delay slot, but we've got a long branch.  */
+         if (GET_CODE (operands[1]) == CONST_INT)
+           return "ldi %1,%0\n\tb %2";
+         else
+           return "copy %1,%0\n\tb %2";
+       }
     }
+
+  if (GET_CODE (operands[1]) == CONST_INT)
+    output_asm_insn ("ldi %1,%0", operands);
   else
-    {
-      /* Something in the delay slot, but we've got a long branch.  */
-      if (GET_CODE (operands[1]) == CONST_INT)
-       return "ldi %1,%0\n\tb %2";
-      else
-       return "copy %1,%0\n\tb %2";
-    }
+    output_asm_insn ("copy %1,%0", operands);
+  return output_lbranch (operands[2], insn, 1);
 }
 
 /* Output an unconditional add and branch insn.  */
 
 const char *
-output_parallel_addb (rtx *operands, int length)
+output_parallel_addb (rtx *operands, rtx insn)
 {
+  int length = get_attr_length (insn);
+
   /* To make life easy we want operand0 to be the shared input/output
      operand and operand1 to be the readonly operand.  */
   if (operands[0] == operands[1])
@@ -8367,18 +8528,20 @@ output_parallel_addb (rtx *operands, int length)
   if (length == 4)
     return "add%I1b,tr %1,%0,%3";
 
-  /* None of these cases win, but they don't lose either.  */
-  if (dbr_sequence_length () == 0)
-    {
-      /* Nothing in the delay slot, fake it by putting the combined
-        insn (the copy or add) in the delay slot of a bl.  */
-      return "b %3\n\tadd%I1 %1,%0,%0";
-    }
-  else
+  /* None of the following cases win, but they don't lose either.  */
+  if (length == 8)
     {
-      /* Something in the delay slot, but we've got a long branch.  */
-      return "add%I1 %1,%0,%0\n\tb %3";
+      if (dbr_sequence_length () == 0)
+       /* Nothing in the delay slot, fake it by putting the combined
+          insn (the copy or add) in the delay slot of a bl.  */
+       return "b %3\n\tadd%I1 %1,%0,%0";
+      else
+       /* Something in the delay slot, but we've got a long branch.  */
+       return "add%I1 %1,%0,%0\n\tb %3";
     }
+
+  output_asm_insn ("add%I1 %1,%0,%0", operands);
+  return output_lbranch (operands[3], insn, 1);
 }
 
 /* Return nonzero if INSN (a jump insn) immediately follows a call
@@ -8426,7 +8589,7 @@ following_call (rtx insn)
    will adhere to those rules.
 
    So, late in the compilation process we find all the jump tables, and
-   expand them into real code -- eg each entry in the jump table vector
+   expand them into real code -- e.g. each entry in the jump table vector
    will get an appropriate label followed by a jump to the final target.
 
    Reorg and the final jump pass can then optimize these branches and
@@ -8739,9 +8902,7 @@ pa_combine_instructions (void)
                                            PATTERN (floater))),
                                anchor);
 
-             PUT_CODE (anchor, NOTE);
-             NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (anchor) = 0;
+             SET_INSN_DELETED (anchor);
 
              /* Emit a special USE insn for FLOATER, then delete
                 the floating insn.  */
@@ -8763,9 +8924,7 @@ pa_combine_instructions (void)
                                         anchor);
 
              JUMP_LABEL (temp) = JUMP_LABEL (anchor);
-             PUT_CODE (anchor, NOTE);
-             NOTE_LINE_NUMBER (anchor) = NOTE_INSN_DELETED;
-             NOTE_SOURCE_FILE (anchor) = 0;
+             SET_INSN_DELETED (anchor);
 
              /* Emit a special USE insn for FLOATER, then delete
                 the floating insn.  */
@@ -8846,7 +9005,7 @@ pa_can_combine_p (rtx new, rtx anchor, rtx floater, int reversed, rtx dest,
    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
+   Note we cannot 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.
 
@@ -8873,38 +9032,57 @@ insn_refs_are_delayed (rtx insn)
    to match the HP Compiler ABI.  */
 
 rtx
-function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
+function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED)
 {
   enum machine_mode valmode;
 
-  /* Aggregates with a size less than or equal to 128 bits are returned
-     in GR 28(-29).  They are left justified.  The pad bits are undefined.
-     Larger aggregates are returned in memory.  */
-  if (TARGET_64BIT && AGGREGATE_TYPE_P (valtype))
+  if (AGGREGATE_TYPE_P (valtype)
+      || TREE_CODE (valtype) == COMPLEX_TYPE
+      || TREE_CODE (valtype) == VECTOR_TYPE)
     {
-      rtx loc[2];
-      int i, offset = 0;
-      int ub = int_size_in_bytes (valtype) <= UNITS_PER_WORD ? 1 : 2;
+      if (TARGET_64BIT)
+       {
+          /* Aggregates with a size less than or equal to 128 bits are
+            returned in GR 28(-29).  They are left justified.  The pad
+            bits are undefined.  Larger aggregates are returned in
+            memory.  */
+         rtx loc[2];
+         int i, offset = 0;
+         int ub = int_size_in_bytes (valtype) <= UNITS_PER_WORD ? 1 : 2;
+
+         for (i = 0; i < ub; i++)
+           {
+             loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
+                                         gen_rtx_REG (DImode, 28 + i),
+                                         GEN_INT (offset));
+             offset += 8;
+           }
 
-      for (i = 0; i < ub; i++)
+         return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (ub, loc));
+       }
+      else if (int_size_in_bytes (valtype) > UNITS_PER_WORD)
        {
-         loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
-                                     gen_rtx_REG (DImode, 28 + i),
-                                     GEN_INT (offset));
-         offset += 8;
+         /* Aggregates 5 to 8 bytes in size are returned in general
+            registers r28-r29 in the same manner as other non
+            floating-point objects.  The data is right-justified and
+            zero-extended to 64 bits.  This is opposite to the normal
+            justification used on big endian targets and requires
+            special treatment.  */
+         rtx loc = gen_rtx_EXPR_LIST (VOIDmode,
+                                      gen_rtx_REG (DImode, 28), const0_rtx);
+         return gen_rtx_PARALLEL (BLKmode, gen_rtvec (1, loc));
        }
-
-      return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (ub, loc));
     }
 
   if ((INTEGRAL_TYPE_P (valtype)
-       && TYPE_PRECISION (valtype) < BITS_PER_WORD)
+       && GET_MODE_BITSIZE (TYPE_MODE (valtype)) < BITS_PER_WORD)
       || POINTER_TYPE_P (valtype))
     valmode = word_mode;
   else
     valmode = TYPE_MODE (valtype);
 
   if (TREE_CODE (valtype) == REAL_TYPE
+      && !AGGREGATE_TYPE_P (valtype)
       && TYPE_MODE (valtype) != TFmode
       && !TARGET_SOFT_FLOAT)
     return gen_rtx_REG (valmode, 32);
@@ -8937,10 +9115,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
   arg_size = FUNCTION_ARG_SIZE (mode, type);
 
   /* If this arg would be passed partially or totally on the stack, then
-     this routine should return zero.  FUNCTION_ARG_PARTIAL_NREGS will
+     this routine should return zero.  pa_arg_partial_bytes will
      handle arguments which are split between regs and stack slots if
      the ABI mandates split arguments.  */
-  if (! TARGET_64BIT)
+  if (!TARGET_64BIT)
     {
       /* The 32-bit ABI does not split arguments.  */
       if (cum->words + arg_size > max_arg_words)
@@ -8975,7 +9153,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
         treatment.  */
       if (arg_size > 1
          || mode == BLKmode
-         || (type && AGGREGATE_TYPE_P (type)))
+         || (type && (AGGREGATE_TYPE_P (type)
+                      || TREE_CODE (type) == COMPLEX_TYPE
+                      || TREE_CODE (type) == VECTOR_TYPE)))
        {
          /* Double-extended precision (80-bit), quad-precision (128-bit)
             and aggregates including complex numbers are aligned on
@@ -9029,13 +9209,18 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
             objects.  The data is right-justified and zero-extended
             to 64 bits.  This is opposite to the normal justification
             used on big endian targets and requires special treatment.
-            We now define BLOCK_REG_PADDING to pad these objects.  */
-         if (mode == BLKmode)
+            We now define BLOCK_REG_PADDING to pad these objects.
+            Aggregates, complex and vector types are passed in the same
+            manner as structures.  */
+         if (mode == BLKmode
+             || (type && (AGGREGATE_TYPE_P (type)
+                          || TREE_CODE (type) == COMPLEX_TYPE
+                          || TREE_CODE (type) == VECTOR_TYPE)))
            {
              rtx loc = gen_rtx_EXPR_LIST (VOIDmode,
                                           gen_rtx_REG (DImode, gpr_reg_base),
                                           const0_rtx);
-             return gen_rtx_PARALLEL (mode, gen_rtvec (1, loc));
+             return gen_rtx_PARALLEL (BLKmode, gen_rtvec (1, loc));
            }
        }
       else
@@ -9053,9 +9238,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
        /* 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
+       /* The parameter must be some kind of scalar float, else we just
          pass it in integer registers.  */
-       && FLOAT_MODE_P (mode)
+       && GET_MODE_CLASS (mode) == MODE_FLOAT
        /* The target function must not have a prototype.  */
        && cum->nargs_prototype <= 0
        /* libcalls do not need to pass items in both FP and general
@@ -9071,7 +9256,7 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
          && !TARGET_GAS
          && !cum->incoming
          && cum->indirect
-         && FLOAT_MODE_P (mode)))
+         && GET_MODE_CLASS (mode) == MODE_FLOAT))
     {
       retval
        = gen_rtx_PARALLEL
@@ -9094,9 +9279,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
              && !TARGET_64BIT
              && !TARGET_ELF32
              && cum->indirect)
-         /* If the parameter is not a floating point parameter, then
-            it belongs in GPRs.  */
-         || !FLOAT_MODE_P (mode))
+         /* If the parameter is not a scalar floating-point parameter,
+            then it belongs in GPRs.  */
+         || GET_MODE_CLASS (mode) != MODE_FLOAT
+         /* Structure with single SFmode field belongs in GPR.  */
+         || (type && AGGREGATE_TYPE_P (type)))
        retval = gen_rtx_REG (mode, gpr_reg_base);
       else
        retval = gen_rtx_REG (mode, fpr_reg_base);
@@ -9106,15 +9293,18 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
 
 
 /* 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 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
-                           tree type, int named ATTRIBUTE_UNUSED)
+   then this routine should return zero.  */
+
+static int
+pa_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                     tree type, bool named ATTRIBUTE_UNUSED)
 {
   unsigned int max_arg_words = 8;
   unsigned int offset = 0;
 
+  if (!TARGET_64BIT)
+    return 0;
+
   if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1))
     offset = 1;
 
@@ -9126,25 +9316,120 @@ function_arg_partial_nregs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
     return 0;
   else
     /* Arg is split.  */
-    return max_arg_words - cum->words - offset;
+    return (max_arg_words - cum->words - offset) * UNITS_PER_WORD;
 }
 
 
-/* Return 1 if this is a comparison operator.  This allows the use of
-   MATCH_OPERATOR to recognize all the branch insns.  */
+/* A get_unnamed_section callback for switching to the text section.
 
-int
-cmpib_comparison_operator (rtx op, enum machine_mode mode)
+   This function is only used with SOM.  Because we don't support
+   named subspaces, we can only create a new subspace or switch back
+   to the default text subspace.  */
+
+static void
+som_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+{
+  gcc_assert (TARGET_SOM);
+  if (TARGET_GAS)
+    {
+      if (cfun && cfun->machine && !cfun->machine->in_nsubspa)
+       {
+         /* We only want to emit a .nsubspa directive once at the
+            start of the function.  */
+         cfun->machine->in_nsubspa = 1;
+
+         /* Create a new subspace for the text.  This provides
+            better stub placement and one-only functions.  */
+         if (cfun->decl
+             && DECL_ONE_ONLY (cfun->decl)
+             && !DECL_WEAK (cfun->decl))
+           {
+             output_section_asm_op ("\t.SPACE $TEXT$\n"
+                                    "\t.NSUBSPA $CODE$,QUAD=0,ALIGN=8,"
+                                    "ACCESS=44,SORT=24,COMDAT");
+             return;
+           }
+       }
+      else
+       {
+         /* There isn't a current function or the body of the current
+            function has been completed.  So, we are changing to the
+            text section to output debugging information.  Thus, we
+            need to forget that we are in the text section so that
+            varasm.c will call us when text_section is selected again.  */
+         gcc_assert (!cfun || !cfun->machine
+                     || cfun->machine->in_nsubspa == 2);
+         in_section = NULL;
+       }
+      output_section_asm_op ("\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$");
+      return;
+    }
+  output_section_asm_op ("\t.SPACE $TEXT$\n\t.SUBSPA $CODE$");
+}
+
+/* A get_unnamed_section callback for switching to comdat data
+   sections.  This function is only used with SOM.  */
+
+static void
+som_output_comdat_data_section_asm_op (const void *data)
 {
-  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));
+  in_section = NULL;
+  output_section_asm_op (data);
+}
+
+/* Implement TARGET_ASM_INITIALIZE_SECTIONS  */
+
+static void
+pa_som_asm_init_sections (void)
+{
+  text_section
+    = get_unnamed_section (0, som_output_text_section_asm_op, NULL);
+
+  /* SOM puts readonly data in the default $LIT$ subspace when PIC code
+     is not being generated.  */
+  som_readonly_data_section
+    = get_unnamed_section (0, output_section_asm_op,
+                          "\t.SPACE $TEXT$\n\t.SUBSPA $LIT$");
+
+  /* When secondary definitions are not supported, SOM makes readonly
+     data one-only by creating a new $LIT$ subspace in $TEXT$ with
+     the comdat flag.  */
+  som_one_only_readonly_data_section
+    = get_unnamed_section (0, som_output_comdat_data_section_asm_op,
+                          "\t.SPACE $TEXT$\n"
+                          "\t.NSUBSPA $LIT$,QUAD=0,ALIGN=8,"
+                          "ACCESS=0x2c,SORT=16,COMDAT");
+
+
+  /* When secondary definitions are not supported, SOM makes data one-only
+     by creating a new $DATA$ subspace in $PRIVATE$ with the comdat flag.  */
+  som_one_only_data_section
+    = get_unnamed_section (SECTION_WRITE,
+                          som_output_comdat_data_section_asm_op,
+                          "\t.SPACE $PRIVATE$\n"
+                          "\t.NSUBSPA $DATA$,QUAD=1,ALIGN=8,"
+                          "ACCESS=31,SORT=24,COMDAT");
+
+  /* FIXME: HPUX ld generates incorrect GOT entries for "T" fixups
+     which reference data within the $TEXT$ space (for example constant
+     strings in the $LIT$ subspace).
+
+     The assemblers (GAS and HP as) both have problems with handling
+     the difference of two symbols which is the other correct way to
+     reference constant data during PIC code generation.
+
+     So, there's no way to reference constant data which is in the
+     $TEXT$ space during PIC generation.  Instead place all constant
+     data into the $PRIVATE$ subspace (this reduces sharing, but it
+     works correctly).  */
+  readonly_data_section = flag_pic ? data_section : som_readonly_data_section;
+
+  /* We must not have a reference to an external symbol defined in a
+     shared library in a readonly section, else the SOM linker will
+     complain.
+
+     So, we force exception information into the data section.  */
+  exception_section = data_section;
 }
 
 /* On hpux10, the linker will give an error if we have a reference
@@ -9152,7 +9437,7 @@ cmpib_comparison_operator (rtx op, enum machine_mode mode)
    library.  Therefore, expressions that might require a reloc can
    not be placed in the read-only data section.  */
 
-static void
+static section *
 pa_select_section (tree exp, int reloc,
                   unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
@@ -9163,12 +9448,23 @@ pa_select_section (tree exp, int reloc,
       && (DECL_INITIAL (exp) == error_mark_node
           || TREE_CONSTANT (DECL_INITIAL (exp)))
       && !reloc)
-    readonly_data_section ();
-  else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c'
-          && !reloc)
-    readonly_data_section ();
+    {
+      if (TARGET_SOM
+         && DECL_ONE_ONLY (exp)
+         && !DECL_WEAK (exp))
+       return som_one_only_readonly_data_section;
+      else
+       return readonly_data_section;
+    }
+  else if (CONSTANT_CLASS_P (exp) && !reloc)
+    return readonly_data_section;
+  else if (TARGET_SOM
+          && TREE_CODE (exp) == VAR_DECL
+          && DECL_ONE_ONLY (exp)
+          && !DECL_WEAK (exp))
+    return som_one_only_data_section;
   else
-    data_section ();
+    return data_section;
 }
 
 static void
@@ -9196,7 +9492,7 @@ pa_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
 /* Worker function for TARGET_RETURN_IN_MEMORY.  */
 
 bool
-pa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+pa_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
 {
   /* SOM ABI says that objects larger than 64 bits are returned in memory.
      PA64 ABI says that objects larger than 128 bits are returned in memory.
@@ -9210,4 +9506,65 @@ pa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
          || int_size_in_bytes (type) <= 0);
 }
 
+/* Structure to hold declaration and name of external symbols that are
+   emitted by GCC.  We generate a vector of these symbols and output them
+   at the end of the file if and only if SYMBOL_REF_REFERENCED_P is true.
+   This avoids putting out names that are never really used.  */
+
+typedef struct extern_symbol GTY(())
+{
+  tree decl;
+  const char *name;
+} extern_symbol;
+
+/* Define gc'd vector type for extern_symbol.  */
+DEF_VEC_O(extern_symbol);
+DEF_VEC_ALLOC_O(extern_symbol,gc);
+
+/* Vector of extern_symbol pointers.  */
+static GTY(()) VEC(extern_symbol,gc) *extern_symbols;
+
+#ifdef ASM_OUTPUT_EXTERNAL_REAL
+/* Mark DECL (name NAME) as an external reference (assembler output
+   file FILE).  This saves the names to output at the end of the file
+   if actually referenced.  */
+
+void
+pa_hpux_asm_output_external (FILE *file, tree decl, const char *name)
+{
+  extern_symbol * p = VEC_safe_push (extern_symbol, gc, extern_symbols, NULL);
+
+  gcc_assert (file == asm_out_file);
+  p->decl = decl;
+  p->name = name;
+}
+
+/* Output text required at the end of an assembler file.
+   This includes deferred plabels and .import directives for
+   all external symbols that were actually referenced.  */
+
+static void
+pa_hpux_file_end (void)
+{
+  unsigned int i;
+  extern_symbol *p;
+
+  if (!NO_DEFERRED_PROFILE_COUNTERS)
+    output_deferred_profile_counters ();
+
+  output_deferred_plabels ();
+
+  for (i = 0; VEC_iterate (extern_symbol, extern_symbols, i, p); i++)
+    {
+      tree decl = p->decl;
+
+      if (!TREE_ASM_WRITTEN (decl)
+         && SYMBOL_REF_REFERENCED_P (XEXP (DECL_RTL (decl), 0)))
+       ASM_OUTPUT_EXTERNAL_REAL (asm_out_file, decl, p->name);
+    }
+
+  VEC_free (extern_symbol, gc, extern_symbols);
+}
+#endif
+
 #include "gt-pa.h"