OSDN Git Service

PR c++/19797
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index 7f4ba45..fce8c8c 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines for insn-output.c for HPPA.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Tim Moore (moore@cs.utah.edu), based on sparc.c
 
 This file is part of GCC.
@@ -48,9 +48,6 @@ Boston, MA 02111-1307, USA.  */
 #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
-
 /* Return nonzero if there is a bypass for the output of 
    OUT_INSN and the fp store IN_INSN.  */
 int
@@ -86,6 +83,7 @@ hppa_fpstore_bypass_p (rtx out_insn, rtx in_insn)
 #endif
 
 static void copy_reg_pointer (rtx, rtx);
+static void fix_range (const char *);
 static int hppa_address_cost (rtx);
 static bool hppa_rtx_costs (rtx, int, int, int *);
 static inline rtx force_mode (enum machine_mode, rtx);
@@ -125,10 +123,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 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 struct deferred_plabel *get_plabel (rtx) 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;
@@ -139,12 +137,18 @@ 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);
+#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,
+static bool pa_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
                                  tree, bool);
+static int pa_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+                                tree, bool);
+static struct machine_function * pa_init_machine_status (void);
 
 
 /* Save the operands last given to a compare for use when we
@@ -152,17 +156,26 @@ static bool pa_pass_by_reference (CUMULATIVE_ARGS *ca, enum machine_mode,
 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;
 
 /* String to hold which cpu we are scheduling for.  */
 const char *pa_cpu_string;
 
-/* Which architecture we are generating code for.  */
-enum architecture_type pa_arch;
+/* String used with the -munix= option.  */
+const char *pa_unix_string;
 
-/* String to hold which architecture we are generating code for.  */
-const char *pa_arch_string;
+/* The UNIX standard to use for predefines and linking.  */
+int flag_pa_unix;
 
 /* Counts for the number of callee-saved general and floating point
    registers which were saved by the current function's prologue.  */
@@ -184,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;
@@ -234,7 +247,11 @@ static size_t n_deferred_plabels = 0;
 #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
@@ -272,14 +289,94 @@ 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
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
+/* Parse the -mfixed-range= option string.  */
+
+static void
+fix_range (const char *const_str)
+{
+  int i, first, last;
+  char *str, *dash, *comma;
+
+  /* str must be of the form REG1'-'REG2{,REG1'-'REG} where REG1 and
+     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.  */
+
+  i = strlen (const_str);
+  str = (char *) alloca (i + 1);
+  memcpy (str, const_str, i + 1);
+
+  while (1)
+    {
+      dash = strchr (str, '-');
+      if (!dash)
+       {
+         warning ("value of -mfixed-range must have form REG1-REG2");
+         return;
+       }
+      *dash = '\0';
+
+      comma = strchr (dash + 1, ',');
+      if (comma)
+       *comma = '\0';
+
+      first = decode_reg_name (str);
+      if (first < 0)
+       {
+         warning ("unknown register name: %s", str);
+         return;
+       }
+
+      last = decode_reg_name (dash + 1);
+      if (last < 0)
+       {
+         warning ("unknown register name: %s", dash + 1);
+         return;
+       }
+
+      *dash = '-';
+
+      if (first > last)
+       {
+         warning ("%s-%s is an empty range", str, dash + 1);
+         return;
+       }
+
+      for (i = first; i <= last; ++i)
+       fixed_regs[i] = call_used_regs[i] = 1;
+
+      if (!comma)
+       break;
+
+      *comma = ',';
+      str = comma + 1;
+    }
+
+  /* Check if all floating point registers have been fixed.  */
+  for (i = FP_REG_FIRST; i <= FP_REG_LAST; i++)
+    if (!fixed_regs[i])
+      break;
+
+  if (i > FP_REG_LAST)
+    target_flags |= MASK_DISABLE_FPREGS;
+}
+
 void
 override_options (void)
 {
@@ -321,7 +418,7 @@ override_options (void)
       warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
     }
 
-  /* Set the instruction set architecture.  */
+  /* Set the instruction architecture.  */
   if (pa_arch_string && ! strcmp (pa_arch_string, "1.0"))
     {
       pa_arch_string = "1.0";
@@ -346,6 +443,39 @@ override_options (void)
       warning ("unknown -march= option (%s).\nValid options are 1.0, 1.1, and 2.0\n", pa_arch_string);
     }
 
+  if (TARGET_HPUX)
+    {
+      /* Set the default UNIX standard for HP-UX.  This affects the
+        predefines and startfiles used for the target.  */
+      if (pa_unix_string == NULL)
+       pa_unix_string
+         = TARGET_HPUX_11_11 ? "98" : (TARGET_HPUX_10_10 ? "95" : "93");
+
+      if (!strcmp (pa_unix_string, "93"))
+       flag_pa_unix = 1993;
+      else if (!strcmp (pa_unix_string, "95"))
+       flag_pa_unix = 1995;
+      else if (TARGET_HPUX_11_11)
+       {
+         if (!strcmp (pa_unix_string, "98"))
+           flag_pa_unix = 1998;
+         else
+           warning ("unknown -munix= option (%s).\n"
+                    "Valid options are 93, 95 and 98.\n",
+                    pa_unix_string);
+       }
+      else if (TARGET_HPUX_10_10)
+       warning ("unknown -munix= option (%s)."
+                "\nValid options are 93 and 95.\n",
+                pa_unix_string);
+      else
+       warning ("unknown -munix= option (%s).\nValid option is 93.\n",
+                pa_unix_string);
+    }
+
+  if (pa_fixed_range_string)
+    fix_range (pa_fixed_range_string);
+
   /* Unconditional branches in the delay slot are not compatible with dwarf2
      call frame information.  There is no benefit in using this optimization
      on PA8000 and later processors.  */
@@ -387,6 +517,8 @@ 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
@@ -398,6 +530,16 @@ pa_init_builtins (void)
 #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.  */
 
@@ -620,24 +762,59 @@ move_src_operand (rtx op, enum machine_mode mode)
 }
 
 /* Accept anything that can be used as the source operand for a prefetch
-   instruction.  */
+   instruction with a cache-control completer.  */
 int
-prefetch_operand (rtx op, enum machine_mode mode)
+prefetch_cc_operand (rtx op, enum machine_mode mode)
 {
   if (GET_CODE (op) != MEM)
     return 0;
 
+  op = XEXP (op, 0);
+
+  /* We must reject virtual registers as we don't allow REG+D.  */
+  if (op == virtual_incoming_args_rtx
+      || op == virtual_stack_vars_rtx
+      || op == virtual_stack_dynamic_rtx
+      || op == virtual_outgoing_args_rtx
+      || op == virtual_cfa_rtx)
+    return 0;
+
+  if (!REG_P (op) && !IS_INDEX_ADDR_P (op))
+    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)))
+      && GET_CODE (op) == PLUS
+      && REG_P (XEXP (op, 0)))
     return 0;
 
-  return memory_address_p (mode, XEXP (op, 0));
+  return memory_address_p (mode, op);
+}
+
+/* Accept anything that can be used as the source operand for a prefetch
+   instruction with no cache-control completer.  */
+int
+prefetch_nocc_operand (rtx op, enum machine_mode mode)
+{
+  if (GET_CODE (op) != MEM)
+    return 0;
+
+  op = XEXP (op, 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 (op) == PLUS
+      && REG_P (XEXP (op, 0))
+      && REG_P (XEXP (op, 1)))
+    return 0;
+
+  return memory_address_p (mode, op);
 }
 
 /* Accept REG and any CONST_INT that can be moved in one instruction into a
@@ -923,15 +1100,13 @@ 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);
 
@@ -1001,7 +1176,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.
 
@@ -3146,13 +3321,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);
@@ -3333,7 +3509,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
@@ -4133,6 +4309,14 @@ 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.  */
+      forget_section ();
+    }
+
   if (INSN_ADDRESSES_SET_P ())
     {
       insn = get_last_nonnote_insn ();
@@ -4968,7 +5152,10 @@ print_operand (FILE *file, rtx x, int code)
        }
       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))
        {
@@ -4987,19 +5174,19 @@ 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 ();
        }
@@ -5249,10 +5436,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)
@@ -5413,22 +5600,23 @@ pa_hpux64_hpas_file_start (void)
 #undef aputs
 
 static struct deferred_plabel *
-get_plabel (const char *fname)
+get_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 *)
@@ -5441,12 +5629,13 @@ 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];
@@ -5470,7 +5659,7 @@ output_deferred_plabels (void)
     {
       (*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);
     }
 }
@@ -6021,8 +6210,7 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
 
       /* 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);
+      u = build_int_cst (valist_type, (size > 4 ? -8 : -4));
       t = build (BIT_AND_EXPR, valist_type, t, u);
 
       t = build (MODIFY_EXPR, valist_type, valist, t);
@@ -6044,6 +6232,50 @@ hppa_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p, tree *post_p)
     }
 }
 
+/* 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;
+
+    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,
@@ -6058,7 +6290,7 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
   int useskip = 0;
   rtx xoperands[5];
 
-  /* 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.
 
@@ -6367,7 +6599,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
   static char buf[100];
   int useskip = 0;
 
-  /* 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 +6744,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
   static char buf[100];
   int useskip = 0;
 
-  /* 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.  */
@@ -6652,7 +6884,7 @@ const char *
 output_dbra (rtx *operands, rtx insn, int which_alternative)
 {
 
-  /* 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 +6988,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
             int reverse_comparison)
 {
 
-  /* 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))
@@ -6853,7 +7085,7 @@ output_movb (rtx *operands, rtx insn, int which_alternative,
       if (get_attr_length (insn) == 8)
        return "{comb|cmpb},%S2 %%r0,%1,%3\n\tmtsar %r1";
       else
-       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tbl %3\n\tmtsar %r1";
+       return "{comclr|cmpclr},%B2 %%r0,%1,%%r0\n\tb %3\n\tmtsar %r1";
     }
 }
 
@@ -7248,7 +7480,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));
+         struct deferred_plabel *p = get_plabel (call_dest);
 
          xoperands[0] = p->internal_label;
          xoperands[1] = gen_label_rtx ();
@@ -7377,7 +7609,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));
+                 struct deferred_plabel *p = get_plabel (call_dest);
 
                  xoperands[0] = p->internal_label;
                  xoperands[1] = gen_label_rtx ();
@@ -7693,18 +7925,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
@@ -7736,18 +7968,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;
        }
     }
@@ -7756,53 +7989,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;
        }
     }
@@ -7813,99 +8047,92 @@ 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;
        }
     }
@@ -7915,11 +8142,12 @@ pa_asm_output_mi_thunk (FILE *file, tree thunk_fndecl, HOST_WIDE_INT delta,
   if (TARGET_SOM && flag_pic && TREE_PUBLIC (function))
     {
       data_section ();
-      fprintf (file, "\t.align 4\n");
+      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);
     }
+  else if (TARGET_SOM && TARGET_GAS)
+    forget_section ();
 
   current_thunk_number++;
   nbytes = ((nbytes + FUNCTION_BOUNDARY / BITS_PER_UNIT - 1)
@@ -7954,6 +8182,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.
@@ -7971,9 +8202,8 @@ 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));
 }
 
 /* Returns 1 if the 6 operands specified in OPERANDS are suitable for
@@ -8009,13 +8239,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;
@@ -8070,6 +8300,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)
+{
+  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 ("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;
+    }
+
+  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)
+{
+  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
@@ -8102,11 +8416,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]))
@@ -8346,7 +8660,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
@@ -8766,7 +9080,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.
 
@@ -8857,7 +9171,7 @@ 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)
@@ -9026,15 +9340,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;
 
@@ -9046,7 +9363,7 @@ 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;
 }
 
 
@@ -9067,6 +9384,50 @@ cmpib_comparison_operator (rtx op, enum machine_mode mode)
              || GET_CODE (op) == LEU));
 }
 
+/* Return a string to output before text in the current function.
+
+   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.  */
+const char *
+som_text_section_asm_op (void)
+{
+  if (!TARGET_SOM)
+    return "";
+
+  if (TARGET_GAS)
+    {
+      if (cfun && !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))
+           return
+ "\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,SORT=24,COMDAT";
+
+         return "\t.SPACE $TEXT$\n\t.NSUBSPA $CODE$";
+       }
+      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.  Do this in
+            the default text section.  We need to forget that we are
+            in the text section so that the function text_section in
+            varasm.c will call us the next time around.  */
+         forget_section ();
+       }
+    }
+
+  return "\t.SPACE $TEXT$\n\t.SUBSPA $CODE$";
+}
+
 /* On hpux10, the linker will give an error if we have a reference
    in the read-only data section to a symbol defined in a shared
    library.  Therefore, expressions that might require a reloc can
@@ -9083,10 +9444,21 @@ pa_select_section (tree exp, int reloc,
       && (DECL_INITIAL (exp) == error_mark_node
           || TREE_CONSTANT (DECL_INITIAL (exp)))
       && !reloc)
+    {
+      if (TARGET_SOM
+         && DECL_ONE_ONLY (exp)
+         && !DECL_WEAK (exp))
+       som_one_only_readonly_data_section ();
+      else
+       readonly_data_section ();
+    }
+  else if (CONSTANT_CLASS_P (exp) && !reloc)
     readonly_data_section ();
-  else if (TREE_CODE_CLASS (TREE_CODE (exp)) == 'c'
-          && !reloc)
-    readonly_data_section ();
+  else if (TARGET_SOM
+          && TREE_CODE (exp) == VAR_DECL
+          && DECL_ONE_ONLY (exp)
+          && !DECL_WEAK (exp))
+    som_one_only_data_section ();
   else
     data_section ();
 }
@@ -9130,4 +9502,63 @@ 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.  */
+
+struct extern_symbol GTY(())
+{
+  tree decl;
+  const char *name;
+};
+typedef struct extern_symbol *extern_symbol;
+
+/* Define gc'd vector type for extern_symbol.  */
+DEF_VEC_GC_P(extern_symbol);
+
+/* Vector of extern_symbol pointers.  */
+static GTY(()) VEC(extern_symbol) *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 = ggc_alloc (sizeof (struct extern_symbol));
+
+  gcc_assert (file == asm_out_file);
+  p->decl = decl;
+  p->name = name;
+  VEC_safe_push (extern_symbol, extern_symbols, p);
+}
+
+/* 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;
+
+  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);
+    }
+
+  extern_symbols = NULL;
+}
+#endif
+
 #include "gt-pa.h"