OSDN Git Service

* pa.c (legitimize_pic_address): Use gcc_assert instead of abort.
[pf3gnuchains/gcc-fork.git] / gcc / config / pa / pa.c
index 70484c2..60eb3ba 100644 (file)
@@ -17,8 +17,8 @@ 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.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -84,6 +84,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);
@@ -155,26 +156,11 @@ static struct machine_function * pa_init_machine_status (void);
 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;
-
-/* String used with the -munix= option.  */
-const char *pa_unix_string;
+enum processor_type pa_cpu = TARGET_SCHED_DEFAULT;
 
 /* The UNIX standard to use for predefines and linking.  */
-int flag_pa_unix;
+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.  */
@@ -259,6 +245,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
 
@@ -301,6 +292,9 @@ static size_t n_deferred_plabels = 0;
 #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
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
 /* Parse the -mfixed-range= option string.  */
@@ -315,7 +309,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);
@@ -326,7 +320,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';
@@ -338,14 +332,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;
        }
 
@@ -353,7 +347,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;
        }
 
@@ -376,105 +370,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;
-      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;
 
-  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");
+    case OPT_mpa_risc_2_0:
+    case OPT_march_2_0:
+      target_flags |= MASK_PA_11 | MASK_PA_20;
+      return true;
 
-      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);
+    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
-       warning ("unknown -munix= option (%s).\nValid option is 93.\n",
-                pa_unix_string);
-    }
+       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.  */
@@ -485,18 +452,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;
     }
 
@@ -631,6 +598,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))
     {
@@ -652,8 +621,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
@@ -688,17 +656,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)
        {
@@ -713,6 +676,80 @@ legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
   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);
+       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 ();
+       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));
+       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
    to be legitimate.  If we find one, return the new, valid address.
    This macro is used in only one place: `memory_address' in explow.c.
@@ -782,7 +819,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.  */
@@ -1227,12 +1266,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
@@ -1256,8 +1313,7 @@ emit_move_sequence (rtx *operands, enum machine_mode mode, rtx scratch_reg)
   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 (!no_new_pseudos);
 
       tem = copy_to_mode_reg (Pmode, XEXP (operand0, 0));
       operand0 = replace_equiv_address (operand0, tem);
@@ -1631,8 +1687,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));
@@ -1752,6 +1807,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)))
        {
@@ -1974,8 +2049,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.  */
@@ -2110,11 +2184,8 @@ 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.  */
-
-  if (optype0 != REGOP && optype1 != REGOP)
-    abort ();
+     supposed to allow to happen.  */
+  gcc_assert (optype0 == REGOP || optype1 == REGOP);
 
    /* Handle auto decrementing and incrementing loads and stores
      specifically, since the structure of the function doesn't work
@@ -2133,40 +2204,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)
@@ -2180,8 +2244,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))
            {
@@ -2207,8 +2271,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))
            {
@@ -2370,23 +2434,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
@@ -2407,11 +2470,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.
@@ -2542,7 +2604,7 @@ output_block_move (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
        return "";
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
 }
 
@@ -2684,7 +2746,7 @@ output_block_clear (rtx *operands, int size_is_constant ATTRIBUTE_UNUSED)
        return "";
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
 }
 
@@ -2744,15 +2806,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";
@@ -2796,15 +2856,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";
@@ -2843,8 +2901,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;
@@ -2873,9 +2930,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;
@@ -3250,8 +3306,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);
@@ -4305,8 +4360,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.  */
 
@@ -4386,9 +4442,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)
@@ -4471,9 +4526,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
@@ -4523,7 +4579,7 @@ pa_issue_rate (void)
     case PROCESSOR_8000:       return 4;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -4686,7 +4742,7 @@ print_operand (FILE *file, rtx x, int code)
        case LTU:
          fputs ("<<", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'N':                  /* Condition, (N)egated */
@@ -4713,7 +4769,7 @@ 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
@@ -4753,7 +4809,7 @@ print_operand (FILE *file, rtx x, int code)
        case ORDERED:
          fputs ("?", file);  break;
        default:
-         abort ();
+         gcc_unreachable ();
        }
       return;
     case 'S':                  /* Condition, operands are (S)wapped.  */
@@ -4780,7 +4836,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.  */
@@ -4807,51 +4863,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);
@@ -4926,7 +4964,7 @@ print_operand (FILE *file, rtx x, int code)
         addresses.  */
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   if (GET_CODE (x) == REG)
     {
@@ -5013,23 +5051,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.
@@ -5043,8 +5089,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;
@@ -5052,12 +5099,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)
@@ -5441,9 +5493,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);
 
@@ -6021,7 +6073,7 @@ output_cbranch (rtx *operands, int nullify, int length, int negated, rtx insn)
        return output_lbranch (operands[0], insn);
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
   return buf;
 }
@@ -6040,11 +6092,10 @@ output_lbranch (rtx dest, rtx insn)
   if (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);
@@ -6281,7 +6332,7 @@ output_bb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
   return buf;
 }
@@ -6426,7 +6477,7 @@ output_bvb (rtx *operands ATTRIBUTE_UNUSED, int nullify, int length,
        break;
 
       default:
-       abort ();
+       gcc_unreachable ();
     }
   return buf;
 }
@@ -6475,13 +6526,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
@@ -6503,9 +6556,11 @@ 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:
+         gcc_unreachable ();
        }
-      else
-       abort ();
+      
     }
   /* Deal with gross reload from FP register case.  */
   else if (which_alternative == 1)
@@ -6580,13 +6635,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
@@ -6608,9 +6665,10 @@ 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:
+         gcc_unreachable ();
        }
-      else
-       abort ();
     }
   /* Deal with gross reload from FP register case.  */
   else if (which_alternative == 1)
@@ -7048,7 +7106,7 @@ 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);
@@ -7096,7 +7154,7 @@ 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.  */
@@ -7261,8 +7319,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);
@@ -7434,6 +7491,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;
@@ -7900,7 +7959,7 @@ pa_asm_output_aligned_common (FILE *stream,
   max_common_align = TARGET_64BIT ? 128 : (size >= 4096 ? 256 : 64);
   if (align > max_common_align)
     {
-      warning ("alignment (%u) for %s exceeds maximum alignment "
+      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;
@@ -8643,24 +8702,40 @@ function_value (tree valtype, 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))
     {
-      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++)
+         for (i = 0; i < ub; i++)
+           {
+             loc[i] = gen_rtx_EXPR_LIST (VOIDmode,
+                                         gen_rtx_REG (DImode, 28 + i),
+                                         GEN_INT (offset));
+             offset += 8;
+           }
+
+         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)
@@ -8671,6 +8746,7 @@ function_value (tree valtype, tree func ATTRIBUTE_UNUSED)
     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);
@@ -8796,12 +8872,12 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
             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)
+         if (mode == BLKmode || (type && AGGREGATE_TYPE_P (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
@@ -8862,7 +8938,9 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
              && cum->indirect)
          /* If the parameter is not a floating point parameter, then
             it belongs in GPRs.  */
-         || !FLOAT_MODE_P (mode))
+         || !FLOAT_MODE_P (mode)
+         /* 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);
@@ -9022,18 +9100,18 @@ pa_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
    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(())
+typedef struct extern_symbol GTY(())
 {
   tree decl;
   const char *name;
-};
-typedef struct extern_symbol *extern_symbol;
+} extern_symbol;
 
 /* Define gc'd vector type for extern_symbol.  */
-DEF_VEC_GC_P(extern_symbol);
+DEF_VEC_O(extern_symbol);
+DEF_VEC_ALLOC_O(extern_symbol,gc);
 
 /* Vector of extern_symbol pointers.  */
-static GTY(()) VEC(extern_symbol) *extern_symbols;
+static GTY(()) VEC(extern_symbol,gc) *extern_symbols;
 
 #ifdef ASM_OUTPUT_EXTERNAL_REAL
 /* Mark DECL (name NAME) as an external reference (assembler output
@@ -9043,12 +9121,11 @@ static GTY(()) VEC(extern_symbol) *extern_symbols;
 void
 pa_hpux_asm_output_external (FILE *file, tree decl, const char *name)
 {
-  extern_symbol p = ggc_alloc (sizeof (struct extern_symbol));
+  extern_symbol * p = VEC_safe_push (extern_symbol, gc, extern_symbols, NULL);
 
   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.
@@ -9059,7 +9136,7 @@ static void
 pa_hpux_file_end (void)
 {
   unsigned int i;
-  extern_symbol p;
+  extern_symbol *p;
 
   output_deferred_plabels ();
 
@@ -9072,7 +9149,7 @@ pa_hpux_file_end (void)
        ASM_OUTPUT_EXTERNAL_REAL (asm_out_file, decl, p->name);
     }
 
-  extern_symbols = NULL;
+  VEC_free (extern_symbol, gc, extern_symbols);
 }
 #endif