OSDN Git Service

* config/alpha/osf5.h (TARGET_LD_BUGGY_LDGP): New.
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 97e56e4..3e3de70 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on the DEC Alpha.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000 Free Software Foundation, Inc. 
+   2000, 2001 Free Software Foundation, Inc. 
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
@@ -29,7 +29,6 @@ Boston, MA 02111-1307, USA.  */
 #include "real.h"
 #include "insn-config.h"
 #include "conditions.h"
-#include "insn-flags.h"
 #include "output.h"
 #include "insn-attr.h"
 #include "flags.h"
@@ -70,6 +69,7 @@ enum alpha_fp_trap_mode alpha_fptm;
 /* Strings decoded into the above options.  */
 
 const char *alpha_cpu_string;  /* -mcpu= */
+const char *alpha_tune_string; /* -mtune= */
 const char *alpha_tp_string;   /* -mtrap-precision=[p|s|i] */
 const char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */
 const char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */
@@ -118,6 +118,8 @@ static void alpha_init_machine_status
   PARAMS ((struct function *p));
 static void alpha_mark_machine_status
   PARAMS ((struct function *p));
+static void alpha_free_machine_status
+  PARAMS ((struct function *p));
 static int alpha_ra_ever_killed
   PARAMS ((void));
 static rtx set_frame_related_p
@@ -146,6 +148,31 @@ static rtx alpha_emit_xfloating_compare
 void
 override_options ()
 {
+  int i;
+  static struct cpu_table {
+    const char *name;
+    enum processor_type processor;
+    int flags;
+  } cpu_table[] = {
+#define EV5_MASK (MASK_CPU_EV5)
+#define EV6_MASK (MASK_CPU_EV6|MASK_BWX|MASK_MAX|MASK_FIX)
+    { "ev4",   PROCESSOR_EV4, 0 },
+    { "ev45",  PROCESSOR_EV4, 0 },
+    { "21064", PROCESSOR_EV4, 0 },
+    { "ev5",   PROCESSOR_EV5, EV5_MASK },
+    { "21164", PROCESSOR_EV5, EV5_MASK },
+    { "ev56",  PROCESSOR_EV5, EV5_MASK|MASK_BWX },
+    { "21164a",        PROCESSOR_EV5, EV5_MASK|MASK_BWX },
+    { "pca56", PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+    { "21164PC",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+    { "21164pc",PROCESSOR_EV5, EV5_MASK|MASK_BWX|MASK_MAX },
+    { "ev6",   PROCESSOR_EV6, EV6_MASK },
+    { "21264", PROCESSOR_EV6, EV6_MASK },
+    { "ev67",  PROCESSOR_EV6, EV6_MASK|MASK_CIX },
+    { "21264a",        PROCESSOR_EV6, EV6_MASK|MASK_CIX },
+    { 0, 0, 0 }
+  };
+                  
   alpha_tp = ALPHA_TP_PROG;
   alpha_fprm = ALPHA_FPRM_NORM;
   alpha_fptm = ALPHA_FPTM_N;
@@ -209,61 +236,41 @@ override_options ()
 
   if (alpha_cpu_string)
     {
-      if (! strcmp (alpha_cpu_string, "ev4")
-         || ! strcmp (alpha_cpu_string, "ev45")
-         || ! strcmp (alpha_cpu_string, "21064"))
-       {
-         alpha_cpu = PROCESSOR_EV4;
-         target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX);
-       }
-      else if (! strcmp (alpha_cpu_string, "ev5")
-              || ! strcmp (alpha_cpu_string, "21164"))
-       {
-         alpha_cpu = PROCESSOR_EV5;
-         target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX);
-       }
-      else if (! strcmp (alpha_cpu_string, "ev56")
-              || ! strcmp (alpha_cpu_string, "21164a"))
-       {
-         alpha_cpu = PROCESSOR_EV5;
-         target_flags |= MASK_BWX;
-         target_flags &= ~ (MASK_MAX | MASK_FIX | MASK_CIX);
-       }
-      else if (! strcmp (alpha_cpu_string, "pca56")
-              || ! strcmp (alpha_cpu_string, "21164PC")
-              || ! strcmp (alpha_cpu_string, "21164pc"))
-       {
-         alpha_cpu = PROCESSOR_EV5;
-         target_flags |= MASK_BWX | MASK_MAX;
-         target_flags &= ~ (MASK_FIX | MASK_CIX);
-       }
-      else if (! strcmp (alpha_cpu_string, "ev6")
-              || ! strcmp (alpha_cpu_string, "21264"))
-       {
-         alpha_cpu = PROCESSOR_EV6;
-         target_flags |= MASK_BWX | MASK_MAX | MASK_FIX;
-         target_flags &= ~ (MASK_CIX);
-       }
-      else if (! strcmp (alpha_cpu_string, "ev67")
-              || ! strcmp (alpha_cpu_string, "21264a"))
-       {
-         alpha_cpu = PROCESSOR_EV6;
-         target_flags |= MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX;
-       }
-      else
+      for (i = 0; cpu_table [i].name; i++)
+       if (! strcmp (alpha_cpu_string, cpu_table [i].name))
+         {
+           alpha_cpu = cpu_table [i].processor;
+           target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX
+                              | MASK_CPU_EV5 | MASK_CPU_EV6);
+           target_flags |= cpu_table [i].flags;
+           break;
+         }
+      if (! cpu_table [i].name)
        error ("bad value `%s' for -mcpu switch", alpha_cpu_string);
     }
 
+  if (alpha_tune_string)
+    {
+      for (i = 0; cpu_table [i].name; i++)
+       if (! strcmp (alpha_tune_string, cpu_table [i].name))
+         {
+           alpha_cpu = cpu_table [i].processor;
+           break;
+         }
+      if (! cpu_table [i].name)
+       error ("bad value `%s' for -mcpu switch", alpha_tune_string);
+    }
+
   /* Do some sanity checks on the above options. */
 
   if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
-      && alpha_tp != ALPHA_TP_INSN && alpha_cpu != PROCESSOR_EV6)
+      && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6)
     {
       warning ("fp software completion requires -mtrap-precision=i");
       alpha_tp = ALPHA_TP_INSN;
     }
 
-  if (alpha_cpu == PROCESSOR_EV6)
+  if (TARGET_CPU_EV6)
     {
       /* Except for EV6 pass 1 (not released), we always have precise
         arithmetic traps.  Which means we can do software completion
@@ -303,11 +310,11 @@ override_options ()
        {
          { 3, 30, -1 },        /* ev4 -- Bcache is a guess */
          { 2, 12, 38 },        /* ev5 -- Bcache from PC164 LMbench numbers */
-         { 3, 13, -1 },        /* ev6 -- Ho hum, doesn't exist yet */
+         { 3, 12, 30 },        /* ev6 -- Bcache from DS20 LMbench. */
        };
 
        lat = alpha_mlat_string[1] - '0';
-       if (lat < 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1)
+       if (lat <= 0 || lat > 3 || cache_latency[alpha_cpu][lat-1] == -1)
          {
            warning ("L%d cache latency unknown for %s",
                     lat, alpha_cpu_name[alpha_cpu]);
@@ -335,12 +342,26 @@ override_options ()
   if (!g_switch_set)
     g_switch_value = 8;
 
+  /* Align labels and loops for optimal branching.  */
+  /* ??? Kludge these by not doing anything if we don't optimize and also if
+     we are writing ECOFF symbols to work around a bug in DEC's assembler. */
+  if (optimize > 0 && write_symbols != SDB_DEBUG)
+    {
+      if (align_loops <= 0)
+       align_loops = 16;
+      if (align_jumps <= 0)
+       align_jumps = 16;
+    }
+  if (align_functions <= 0)
+    align_functions = 16;
+
   /* Acquire a unique set number for our register saves and restores.  */
   alpha_sr_alias_set = new_alias_set ();
 
   /* Set up function hooks.  */
   init_machine_status = alpha_init_machine_status;
   mark_machine_status = alpha_mark_machine_status;
+  free_machine_status = alpha_free_machine_status;
 }
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -1614,10 +1635,21 @@ alpha_emit_conditional_branch (code)
            1  true
         Convert the compare against the raw return value.  */
 
-      op0 = alpha_emit_xfloating_compare (code, op0, op1);
+      if (code == UNORDERED || code == ORDERED)
+       cmp_code = EQ;
+      else
+       cmp_code = code;
+
+      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
       op1 = const0_rtx;
       alpha_compare.fp_p = 0;
-      code = GT;
+
+      if (code == UNORDERED)
+       code = LT;
+      else if (code == ORDERED)
+       code = GE;
+      else
+        code = GT;
     }
 
   /* The general case: fold the comparison code to the types of compares
@@ -1658,7 +1690,7 @@ alpha_emit_conditional_branch (code)
   if (alpha_compare.fp_p)
     {
       cmp_mode = DFmode;
-      if (flag_fast_math)
+      if (flag_unsafe_math_optimizations)
        {
          /* When we are not as concerned about non-finite values, and we
             are comparing against zero, we can branch directly.  */
@@ -1707,11 +1739,12 @@ alpha_emit_conditional_branch (code)
                }
            }
        }
-    }
 
-  /* Force op0 into a register.  */
-  if (GET_CODE (op0) != REG)
-    op0 = force_reg (cmp_mode, op0);
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (cmp_code != PLUS && !reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
 
   /* Emit an initial compare instruction, if necessary.  */
   tem = op0;
@@ -1728,6 +1761,115 @@ alpha_emit_conditional_branch (code)
   return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
 }
 
+/* Certain simplifications can be done to make invalid setcc operations
+   valid.  Return the final comparison, or NULL if we can't work.  */
+
+rtx
+alpha_emit_setcc (code)
+     enum rtx_code code;
+{
+  enum rtx_code cmp_code;
+  rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
+  int fp_p = alpha_compare.fp_p;
+  rtx tmp;
+
+  /* Zero the operands.  */
+  memset (&alpha_compare, 0, sizeof (alpha_compare));
+
+  if (fp_p && GET_MODE (op0) == TFmode)
+    {
+      if (! TARGET_HAS_XFLOATING_LIBS)
+       abort ();
+
+      /* X_floating library comparison functions return
+          -1  unordered
+           0  false
+           1  true
+        Convert the compare against the raw return value.  */
+
+      if (code == UNORDERED || code == ORDERED)
+       cmp_code = EQ;
+      else
+       cmp_code = code;
+
+      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+      op1 = const0_rtx;
+      fp_p = 0;
+
+      if (code == UNORDERED)
+       code = LT;
+      else if (code == ORDERED)
+       code = GE;
+      else
+        code = GT;
+    }
+
+  if (fp_p && !TARGET_FIX)
+    return NULL_RTX;
+
+  /* The general case: fold the comparison code to the types of compares
+     that we have, choosing the branch as necessary.  */
+
+  cmp_code = NIL;
+  switch (code)
+    {
+    case EQ:  case LE:  case LT:  case LEU:  case LTU:
+    case UNORDERED:
+      /* We have these compares.  */
+      if (fp_p)
+       cmp_code = code, code = NE;
+      break;
+
+    case NE:
+      if (!fp_p && op1 == const0_rtx)
+       break;
+      /* FALLTHRU */
+
+    case ORDERED:
+      cmp_code = reverse_condition (code);
+      code = EQ;
+      break;
+
+    case GE:  case GT: case GEU:  case GTU:
+      /* These are normally need swapping, but for integer zero we have
+        special patterns that recognize swapped operands.  */
+      if (!fp_p && op1 == const0_rtx)
+       break;
+      code = swap_condition (code);
+      if (fp_p)
+       cmp_code = code, code = NE;
+      tmp = op0, op0 = op1, op1 = tmp;
+      break;
+
+    default:
+      abort ();
+    }
+
+  if (!fp_p)
+    {
+      if (!register_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
+
+  /* Emit an initial compare instruction, if necessary.  */
+  if (cmp_code != NIL)
+    {
+      enum machine_mode mode = fp_p ? DFmode : DImode;
+
+      tmp = gen_reg_rtx (mode);
+      emit_insn (gen_rtx_SET (VOIDmode, tmp,
+                             gen_rtx_fmt_ee (cmp_code, mode, op0, op1)));
+
+      op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp;
+      op1 = const0_rtx;
+    }
+
+  /* Return the setcc comparison.  */
+  return gen_rtx_fmt_ee (code, DImode, op0, op1);
+}
+
 
 /* Rewrite a comparison against zero CMP of the form
    (CODE (cc0) (const_int 0)) so it can be written validly in
@@ -1749,7 +1891,7 @@ alpha_emit_conditional_move (cmp, mode)
     = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0));
   enum machine_mode cmp_op_mode = fp_p ? DFmode : DImode;
   enum machine_mode cmov_mode = VOIDmode;
-  int local_fast_math = flag_fast_math;
+  int local_fast_math = flag_unsafe_math_optimizations;
   rtx tem;
 
   /* Zero the operands.  */
@@ -1781,9 +1923,14 @@ alpha_emit_conditional_move (cmp, mode)
 
        case GE: case GT: case GEU: case GTU:
          /* These must be swapped.  */
-         cmp_code = swap_condition (code);
-         code = NE;
-         tem = op0, op0 = op1, op1 = tem;
+         if (op1 == CONST0_RTX (cmp_mode))
+           cmp_code = code, code = NE;
+         else
+           {
+             cmp_code = swap_condition (code);
+             code = NE;
+             tem = op0, op0 = op1, op1 = tem;
+           }
          break;
 
        default:
@@ -1830,17 +1977,26 @@ alpha_emit_conditional_move (cmp, mode)
       break;
 
     case GE:  case GT:  case GEU:  case GTU:
-      /* These must be swapped.  Make sure the new first operand is in
-        a register.  */
-      code = swap_condition (code);
-      tem = op0, op0 = op1, op1 = tem;
-      op0 = force_reg (cmp_mode, op0);
+      /* These must be swapped.  */
+      if (op1 != CONST0_RTX (cmp_mode))
+       {
+         code = swap_condition (code);
+         tem = op0, op0 = op1, op1 = tem;
+       }
       break;
 
     default:
       abort ();
     }
 
+  if (!fp_p)
+    {
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
+    }
+
   /* ??? We mark the branch mode to be CCmode to prevent the compare
      and cmov from being combined, since the compare insn follows IEEE
      rules that the cmov does not.  */
@@ -2224,6 +2380,10 @@ alpha_emit_xfloating_cvt (code, operands)
                                               operands[1]));
 }
 
+/* Split a TFmode OP[1] into DImode OP[2,3] and likewise for
+   OP[0] into OP[0,1].  Naturally, output operand ordering is
+   little-endian.  */
+
 void
 alpha_split_tfmode_pair (operands)
      rtx operands[4];
@@ -2258,6 +2418,52 @@ alpha_split_tfmode_pair (operands)
   else
     abort ();
 }
+
+/* Implement negtf2 or abstf2.  Op0 is destination, op1 is source, 
+   op2 is a register containing the sign bit, operation is the 
+   logical operation to be performed.  */
+
+void
+alpha_split_tfmode_frobsign (operands, operation)
+     rtx operands[3];
+     rtx (*operation) PARAMS ((rtx, rtx, rtx));
+{
+  rtx high_bit = operands[2];
+  rtx scratch;
+  int move;
+
+  alpha_split_tfmode_pair (operands);
+
+  /* Detect three flavours of operand overlap.  */
+  move = 1;
+  if (rtx_equal_p (operands[0], operands[2]))
+    move = 0;
+  else if (rtx_equal_p (operands[1], operands[2]))
+    {
+      if (rtx_equal_p (operands[0], high_bit))
+       move = 2;
+      else
+       move = -1;
+    }
+
+  if (move < 0)
+    emit_move_insn (operands[0], operands[2]);
+
+  /* ??? If the destination overlaps both source tf and high_bit, then
+     assume source tf is dead in its entirety and use the other half
+     for a scratch register.  Otherwise "scratch" is just the proper
+     destination register.  */
+  scratch = operands[move < 2 ? 1 : 3];
+
+  emit_insn ((*operation) (scratch, high_bit, operands[3]));
+
+  if (move > 0)
+    {
+      emit_move_insn (operands[0], operands[2]);
+      if (move > 1)
+       emit_move_insn (operands[1], scratch);
+    }
+}
 \f
 /* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
    unaligned data:
@@ -2292,7 +2498,7 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
      HOST_WIDE_INT size, ofs;
      int sign;
 {
-  rtx meml, memh, addr, extl, exth;
+  rtx meml, memh, addr, extl, exth, tmp;
   enum machine_mode mode;
 
   meml = gen_reg_rtx (DImode);
@@ -2301,19 +2507,24 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
   extl = gen_reg_rtx (DImode);
   exth = gen_reg_rtx (DImode);
 
-  emit_move_insn (meml,
-                 change_address (mem, DImode,
-                                 gen_rtx_AND (DImode, 
-                                              plus_constant (XEXP (mem, 0),
-                                                             ofs),
-                                              GEN_INT (-8))));
-
-  emit_move_insn (memh,
-                 change_address (mem, DImode,
-                                 gen_rtx_AND (DImode, 
-                                              plus_constant (XEXP (mem, 0),
-                                                             ofs + size - 1),
-                                              GEN_INT (-8))));
+  /* AND addresses cannot be in any alias set, since they may implicitly
+     alias surrounding code.  Ideally we'd have some alias set that 
+     covered all types except those with alignment 8 or higher.  */
+
+  tmp = change_address (mem, DImode,
+                       gen_rtx_AND (DImode, 
+                                    plus_constant (XEXP (mem, 0), ofs),
+                                    GEN_INT (-8)));
+  MEM_ALIAS_SET (tmp) = 0;
+  emit_move_insn (meml, tmp);
+
+  tmp = change_address (mem, DImode,
+                       gen_rtx_AND (DImode, 
+                                    plus_constant (XEXP (mem, 0),
+                                                   ofs + size - 1),
+                                    GEN_INT (-8)));
+  MEM_ALIAS_SET (tmp) = 0;
+  emit_move_insn (memh, tmp);
 
   if (sign && size == 2)
     {
@@ -2377,15 +2588,22 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
   insl = gen_reg_rtx (DImode);
   insh = gen_reg_rtx (DImode);
 
+  /* AND addresses cannot be in any alias set, since they may implicitly
+     alias surrounding code.  Ideally we'd have some alias set that 
+     covered all types except those with alignment 8 or higher.  */
+
   meml = change_address (dst, DImode,
                         gen_rtx_AND (DImode, 
                                      plus_constant (XEXP (dst, 0), ofs),
                                      GEN_INT (-8)));
+  MEM_ALIAS_SET (meml) = 0;
+
   memh = change_address (dst, DImode,
                         gen_rtx_AND (DImode, 
                                      plus_constant (XEXP (dst, 0),
                                                     ofs+size-1),
                                      GEN_INT (-8)));
+  MEM_ALIAS_SET (memh) = 0;
 
   emit_move_insn (dsth, memh);
   emit_move_insn (dstl, meml);
@@ -2462,7 +2680,7 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
   rtx const im8 = GEN_INT (-8);
   rtx const i64 = GEN_INT (64);
   rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1];
-  rtx sreg, areg;
+  rtx sreg, areg, tmp;
   HOST_WIDE_INT i;
 
   /* Generate all the tmp registers we need.  */
@@ -2480,19 +2698,20 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
   /* Load up all of the source data.  */
   for (i = 0; i < words; ++i)
     {
-      emit_move_insn (data_regs[i],
-                     change_address (smem, DImode,
-                                     gen_rtx_AND (DImode,
-                                                  plus_constant (XEXP(smem,0),
-                                                                 8*i),
-                                                  im8)));
+      tmp = change_address (smem, DImode,
+                           gen_rtx_AND (DImode,
+                                        plus_constant (XEXP(smem,0), 8*i),
+                                        im8));
+      MEM_ALIAS_SET (tmp) = 0;
+      emit_move_insn (data_regs[i], tmp);
     }
-  emit_move_insn (data_regs[words],
-                 change_address (smem, DImode,
-                                 gen_rtx_AND (DImode,
-                                              plus_constant (XEXP(smem,0),
-                                                             8*words - 1),
-                                              im8)));
+
+  tmp = change_address (smem, DImode,
+                       gen_rtx_AND (DImode,
+                                    plus_constant (XEXP(smem,0), 8*words - 1),
+                                    im8));
+  MEM_ALIAS_SET (tmp) = 0;
+  emit_move_insn (data_regs[words], tmp);
 
   /* Extract the half-word fragments.  Unfortunately DEC decided to make
      extxh with offset zero a noop instead of zeroing the register, so 
@@ -2559,10 +2778,13 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
                                           plus_constant (XEXP(dmem,0),
                                                          words*8 - 1),
                                       im8));
+  MEM_ALIAS_SET (st_addr_2) = 0;
+
   st_addr_1 = change_address (dmem, DImode,
                              gen_rtx_AND (DImode, 
                                           XEXP (dmem, 0),
                                           im8));
+  MEM_ALIAS_SET (st_addr_1) = 0;
 
   /* Load up the destination end bits.  */
   emit_move_insn (st_tmp_2, st_addr_2);
@@ -2601,12 +2823,12 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
   emit_move_insn (st_addr_2, st_tmp_2);
   for (i = words-1; i > 0; --i)
     {
-      emit_move_insn (change_address (dmem, DImode,
-                                     gen_rtx_AND (DImode,
-                                                  plus_constant(XEXP (dmem,0),
-                                                                i*8),
-                                              im8)),
-                     data_regs ? ins_tmps[i-1] : const0_rtx);
+      rtx tmp = change_address (dmem, DImode,
+                               gen_rtx_AND (DImode,
+                                            plus_constant(XEXP (dmem,0), i*8),
+                                            im8));
+      MEM_ALIAS_SET (tmp) = 0;
+      emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx);
     }
   emit_move_insn (st_addr_1, st_tmp_1);
 }
@@ -2626,18 +2848,18 @@ alpha_expand_block_move (operands)
   rtx bytes_rtx        = operands[2];
   rtx align_rtx = operands[3];
   HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
-  unsigned HOST_WIDE_INT bytes = orig_bytes;
-  unsigned HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT;
-  unsigned HOST_WIDE_INT dst_align = src_align;
+  HOST_WIDE_INT bytes = orig_bytes;
+  HOST_WIDE_INT src_align = INTVAL (align_rtx) * BITS_PER_UNIT;
+  HOST_WIDE_INT dst_align = src_align;
   rtx orig_src = operands[1];
   rtx orig_dst = operands[0];
   rtx data_regs[2 * MAX_MOVE_WORDS + 16];
   rtx tmp;
-  unsigned int i, words, ofs, nregs = 0;
+  int i, words, ofs, nregs = 0;
   
   if (orig_bytes <= 0)
     return 1;
-  else if (bytes > MAX_MOVE_WORDS * BITS_PER_UNIT)
+  else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
     return 0;
 
   /* Look for additional alignment information from recorded register info.  */
@@ -2713,6 +2935,7 @@ alpha_expand_block_move (operands)
       /* No appropriate mode; fall back on memory.  */
       orig_src = change_address (orig_src, GET_MODE (orig_src),
                                 copy_addr_to_reg (XEXP (orig_src, 0)));
+      src_align = GET_MODE_BITSIZE (GET_MODE (tmp));
     }
 
   ofs = 0;
@@ -2752,7 +2975,7 @@ alpha_expand_block_move (operands)
       ofs += words * 4;
     }
 
-  if (bytes >= 16)
+  if (bytes >= 8)
     {
       words = bytes / 8;
 
@@ -2767,14 +2990,6 @@ alpha_expand_block_move (operands)
       ofs += words * 8;
     }
 
-  if (! TARGET_BWX && bytes >= 8)
-    {
-      data_regs[nregs++] = tmp = gen_reg_rtx (DImode);
-      alpha_expand_unaligned_load (tmp, orig_src, 8, ofs, 0);
-      bytes -= 8;
-      ofs += 8;
-    }
-
   if (! TARGET_BWX && bytes >= 4)
     {
       data_regs[nregs++] = tmp = gen_reg_rtx (SImode);
@@ -2797,7 +3012,6 @@ alpha_expand_block_move (operands)
            ofs += 2;
          } while (bytes >= 2);
        }
-
       else if (! TARGET_BWX)
        {
          data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
@@ -2875,7 +3089,7 @@ alpha_expand_block_move (operands)
         up by recognizing extra alignment information.  */
       orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
                                 copy_addr_to_reg (XEXP (orig_dst, 0)));
-      dst_align = GET_MODE_SIZE (GET_MODE (tmp));
+      dst_align = GET_MODE_BITSIZE (GET_MODE (tmp));
     }
 
   /* Write out the data in whatever chunks reading the source allowed.  */
@@ -2995,15 +3209,16 @@ alpha_expand_block_clear (operands)
   rtx bytes_rtx        = operands[1];
   rtx align_rtx = operands[2];
   HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
-  unsigned HOST_WIDE_INT bytes = orig_bytes;
-  unsigned HOST_WIDE_INT align = INTVAL (align_rtx);
+  HOST_WIDE_INT bytes = orig_bytes;
+  HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT;
+  HOST_WIDE_INT alignofs = 0;
   rtx orig_dst = operands[0];
   rtx tmp;
-  unsigned HOST_WIDE_INT i, words, ofs = 0;
+  int i, words, ofs = 0;
   
   if (orig_bytes <= 0)
     return 1;
-  if (bytes > MAX_MOVE_WORDS*8)
+  if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
     return 0;
 
   /* Look for stricter alignment.  */
@@ -3014,20 +3229,19 @@ alpha_expand_block_clear (operands)
           && GET_CODE (XEXP (tmp, 0)) == REG
           && GET_CODE (XEXP (tmp, 1)) == CONST_INT)
     {
-      unsigned HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
-      unsigned int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
+      HOST_WIDE_INT c = INTVAL (XEXP (tmp, 1));
+      int a = REGNO_POINTER_ALIGN (REGNO (XEXP (tmp, 0)));
 
       if (a > align)
        {
-          if (a >= 64 && c % 8 == 0)
-           align = 64;
-          else if (a >= 32 && c % 4 == 0)
-           align = 32;
-          else if (a >= 16 && c % 2 == 0)
-           align = 16;
+          if (a >= 64)
+           align = a, alignofs = 8 - c % 8;
+          else if (a >= 32)
+           align = a, alignofs = 4 - c % 4;
+          else if (a >= 16)
+           align = a, alignofs = 2 - c % 2;
        }
     }
-
   else if (GET_CODE (tmp) == ADDRESSOF)
     {
       enum machine_mode mode;
@@ -3042,10 +3256,93 @@ alpha_expand_block_clear (operands)
       /* No appropriate mode; fall back on memory.  */
       orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
                                 copy_addr_to_reg (tmp));
-      align = GET_MODE_SIZE (GET_MODE (XEXP (tmp, 0)));
+      align = GET_MODE_BITSIZE (GET_MODE (XEXP (tmp, 0)));
     }
 
-  /* Handle a block of contiguous words first.  */
+  /* Handle an unaligned prefix first.  */
+
+  if (alignofs > 0)
+    {
+#if HOST_BITS_PER_WIDE_INT >= 64
+      /* Given that alignofs is bounded by align, the only time BWX could
+        generate three stores is for a 7 byte fill.  Prefer two individual
+        stores over a load/mask/store sequence.  */
+      if ((!TARGET_BWX || alignofs == 7)
+              && align >= 32
+              && !(alignofs == 4 && bytes >= 4))
+       {
+         enum machine_mode mode = (align >= 64 ? DImode : SImode);
+         int inv_alignofs = (align >= 64 ? 8 : 4) - alignofs;
+         rtx mem, tmp;
+         HOST_WIDE_INT mask;
+
+         mem = change_address (orig_dst, mode,
+                               plus_constant (XEXP (orig_dst, 0),
+                                              ofs - inv_alignofs));
+         MEM_ALIAS_SET (mem) = 0;
+
+         mask = ~(~(HOST_WIDE_INT)0 << (inv_alignofs * 8));
+         if (bytes < alignofs)
+           {
+             mask |= ~(HOST_WIDE_INT)0 << ((inv_alignofs + bytes) * 8);
+             ofs += bytes;
+             bytes = 0;
+           }
+         else
+           {
+             bytes -= alignofs;
+             ofs += alignofs;
+           }
+         alignofs = 0;
+
+         tmp = expand_binop (mode, and_optab, mem, GEN_INT (mask),
+                             NULL_RTX, 1, OPTAB_WIDEN);
+
+         emit_move_insn (mem, tmp);
+       }
+#endif
+
+      if (TARGET_BWX && (alignofs & 1) && bytes >= 1)
+       {
+         emit_move_insn (change_address (orig_dst, QImode,
+                                         plus_constant (XEXP (orig_dst, 0),
+                                                        ofs)),
+                         const0_rtx);
+         bytes -= 1;
+         ofs += 1;
+         alignofs -= 1;
+       }
+      if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2)
+       {
+         emit_move_insn (change_address (orig_dst, HImode,
+                                         plus_constant (XEXP (orig_dst, 0),
+                                                        ofs)),
+                         const0_rtx);
+         bytes -= 2;
+         ofs += 2;
+         alignofs -= 2;
+       }
+      if (alignofs == 4 && bytes >= 4)
+       {
+         emit_move_insn (change_address (orig_dst, SImode,
+                                         plus_constant (XEXP (orig_dst, 0),
+                                                        ofs)),
+                         const0_rtx);
+         bytes -= 4;
+         ofs += 4;
+         alignofs = 0;
+       }
+
+      /* If we've not used the extra lead alignment information by now,
+        we won't be able to.  Downgrade align to match what's left over.  */
+      if (alignofs > 0)
+       {
+         alignofs = alignofs & -alignofs;
+         align = MIN (align, alignofs * BITS_PER_UNIT);
+       }
+    }
+
+  /* Handle a block of contiguous long-words.  */
 
   if (align >= 64 && bytes >= 8)
     {
@@ -3061,7 +3358,42 @@ alpha_expand_block_clear (operands)
       ofs += words * 8;
     }
 
-  if (align >= 16 && bytes >= 4)
+  /* If the block is large and appropriately aligned, emit a single
+     store followed by a sequence of stq_u insns.  */
+
+  if (align >= 32 && bytes > 16)
+    {
+      emit_move_insn (change_address (orig_dst, SImode,
+                                     plus_constant (XEXP (orig_dst, 0), ofs)),
+                     const0_rtx);
+      bytes -= 4;
+      ofs += 4;
+
+      words = bytes / 8;
+      for (i = 0; i < words; ++i)
+       {
+         rtx mem;
+         mem = change_address (orig_dst, DImode,
+                               gen_rtx_AND (DImode,
+                                            plus_constant (XEXP (orig_dst, 0),
+                                                           ofs + i*8),
+                                            GEN_INT (-8)));
+         MEM_ALIAS_SET (mem) = 0;
+         emit_move_insn (mem, const0_rtx);
+       }
+
+      /* Depending on the alignment, the first stq_u may have overlapped
+        with the initial stl, which means that the last stq_u didn't
+        write as much as it would appear.  Leave those questionable bytes
+        unaccounted for.  */
+      bytes -= words * 8 - 4;
+      ofs += words * 8 - 4;
+    }
+
+  /* Handle a smaller block of aligned words.  */
+
+  if ((align >= 64 && bytes == 4)
+      || (align == 32 && bytes >= 4))
     {
       words = bytes / 4;
 
@@ -3075,7 +3407,9 @@ alpha_expand_block_clear (operands)
       ofs += words * 4;
     }
 
-  if (bytes >= 16)
+  /* An unaligned block uses stq_u stores for as many as possible.  */
+
+  if (bytes >= 8)
     {
       words = bytes / 8;
 
@@ -3085,15 +3419,56 @@ alpha_expand_block_clear (operands)
       ofs += words * 8;
     }
 
-  /* Next clean up any trailing pieces.  We know from the contiguous
-     block move that there are no aligned SImode or DImode hunks left.  */
+  /* Next clean up any trailing pieces.  */
 
-  if (! TARGET_BWX && bytes >= 8)
-    {
-      alpha_expand_unaligned_store (orig_dst, const0_rtx, 8, ofs);
-      bytes -= 8;
-      ofs += 8;
+#if HOST_BITS_PER_WIDE_INT >= 64
+  /* Count the number of bits in BYTES for which aligned stores could
+     be emitted.  */
+  words = 0;
+  for (i = (TARGET_BWX ? 1 : 4); i * BITS_PER_UNIT <= align ; i <<= 1)
+    if (bytes & i)
+      words += 1;
+
+  /* If we have appropriate alignment (and it wouldn't take too many
+     instructions otherwise), mask out the bytes we need.  */
+  if (TARGET_BWX ? words > 2 : bytes > 0)
+    {
+      if (align >= 64)
+       {
+         rtx mem, tmp;
+         HOST_WIDE_INT mask;
+
+         mem = change_address (orig_dst, DImode,
+                               plus_constant (XEXP (orig_dst, 0), ofs));
+         MEM_ALIAS_SET (mem) = 0;
+
+         mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
+
+         tmp = expand_binop (DImode, and_optab, mem, GEN_INT (mask),
+                             NULL_RTX, 1, OPTAB_WIDEN);
+
+         emit_move_insn (mem, tmp);
+         return 1;
+       }
+      else if (align >= 32 && bytes < 4)
+       {
+         rtx mem, tmp;
+         HOST_WIDE_INT mask;
+
+         mem = change_address (orig_dst, SImode,
+                               plus_constant (XEXP (orig_dst, 0), ofs));
+         MEM_ALIAS_SET (mem) = 0;
+
+         mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
+
+         tmp = expand_binop (SImode, and_optab, mem, GEN_INT (mask),
+                             NULL_RTX, 1, OPTAB_WIDEN);
+
+         emit_move_insn (mem, tmp);
+         return 1;
+       }
     }
+#endif
 
   if (!TARGET_BWX && bytes >= 4)
     {
@@ -3300,8 +3675,19 @@ alpha_mark_machine_status (p)
 {
   struct machine_function *machine = p->machine;
 
-  ggc_mark_rtx (machine->eh_epilogue_sp_ofs);
-  ggc_mark_rtx (machine->ra_rtx);
+  if (machine)
+    {
+      ggc_mark_rtx (machine->ra_rtx);
+      ggc_mark_rtx (machine->gp_save_rtx);
+    }
+}
+
+static void
+alpha_free_machine_status (p)
+     struct function *p;
+{
+  free (p->machine);
+  p->machine = NULL;
 }
 
 /* Start the ball rolling with RETURN_ADDR_RTX.  */
@@ -3334,6 +3720,29 @@ alpha_return_addr (count, frame)
   return reg;
 }
 
+/* Return or create a pseudo containing the gp value for the current
+   function.  Needed only if TARGET_LD_BUGGY_LDGP.  */
+
+rtx
+alpha_gp_save_rtx ()
+{
+  rtx init, reg;
+
+  reg = cfun->machine->gp_save_rtx;
+  if (reg == NULL)
+    {
+      reg = gen_reg_rtx (DImode);
+      cfun->machine->gp_save_rtx = reg;
+      init = gen_rtx_SET (VOIDmode, reg, gen_rtx_REG (DImode, 29));
+
+      push_topmost_sequence ();
+      emit_insn_after (init, get_insns ());
+      pop_topmost_sequence ();
+    }
+
+  return reg;
+}
+
 static int
 alpha_ra_ever_killed ()
 {
@@ -3645,7 +4054,7 @@ print_operand (file, x, code)
         if (GET_RTX_CLASS (c) != '<')
          output_operand_lossage ("invalid %%C value");
 
-       if (code == 'D')
+       else if (code == 'D')
          c = reverse_condition (c);
        else if (code == 'c')
          c = swap_condition (c);
@@ -3726,7 +4135,8 @@ print_operand_address (file, addr)
     basereg = REGNO (addr);
   else if (GET_CODE (addr) == SUBREG
           && GET_CODE (SUBREG_REG (addr)) == REG)
-    basereg = REGNO (SUBREG_REG (addr)) + SUBREG_WORD (addr);
+    basereg = REGNO (SUBREG_REG (addr))
+             + SUBREG_BYTE (addr) / GET_MODE_SIZE (GET_MODE (addr));
   else if (GET_CODE (addr) == CONST_INT)
     offset = INTVAL (addr);
   else
@@ -3943,6 +4353,7 @@ alpha_va_arg (valist, type)
   tree t;
   tree offset_field, base_field, addr_tree, addend;
   tree wide_type, wide_ofs;
+  int indirect = 0;
 
   if (TARGET_OPEN_VMS)
     return std_expand_builtin_va_arg (valist, type);
@@ -3961,7 +4372,13 @@ alpha_va_arg (valist, type)
   wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field));
 
   addend = wide_ofs;
-  if (FLOAT_TYPE_P (type))
+
+  if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode)
+    {
+      indirect = 1;
+      tsize = UNITS_PER_WORD;
+    }
+  else if (FLOAT_TYPE_P (type))
     {
       tree fpaddend, cond;
 
@@ -3987,6 +4404,12 @@ alpha_va_arg (valist, type)
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
+  if (indirect)
+    {
+      addr = force_reg (Pmode, addr);
+      addr = gen_rtx_MEM (Pmode, addr);
+    }
+
   return addr;
 }
 \f
@@ -4043,6 +4466,18 @@ alpha_sa_mask (imaskP, fmaskP)
              fmask |= (1L << (i - 32));
          }
 
+      /* We need to restore these for the handler.  */
+      if (current_function_calls_eh_return)
+       {
+         for (i = 0; ; ++i)
+           {
+             unsigned regno = EH_RETURN_DATA_REGNO (i);
+             if (regno == INVALID_REGNUM)
+               break;
+             imask |= 1L << regno;
+           }
+       }
+
       if (imask || fmask || alpha_ra_ever_killed ())
        imask |= (1L << REG_RA);
     }
@@ -4321,10 +4756,8 @@ alpha_expand_prologue ()
        }
 
       if (frame_size != 0)
-       {
-         FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                     GEN_INT (-frame_size))));
-       }
+       FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                   GEN_INT (-frame_size))));
     }
   else
     {
@@ -4448,28 +4881,24 @@ alpha_expand_prologue ()
   if (TARGET_OPEN_VMS)
     {
       if (!vms_is_stack_procedure)
-       {
-         /* Register frame procedures fave the fp.  */
-         FRP (emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
-                              hard_frame_pointer_rtx));
-       }
+       /* Register frame procedures fave the fp.  */
+       FRP (emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
+                            hard_frame_pointer_rtx));
 
       if (vms_base_regno != REG_PV)
        FRP (emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
                             gen_rtx_REG (DImode, REG_PV)));
 
       if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
-       {
-         FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
-       }
+       FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
 
       /* If we have to allocate space for outgoing args, do it now.  */
       if (current_function_outgoing_args_size != 0)
-       {
-         FRP (emit_move_insn (stack_pointer_rtx, 
-               plus_constant (hard_frame_pointer_rtx,
-                - ALPHA_ROUND (current_function_outgoing_args_size))));
-       }
+       FRP (emit_move_insn
+            (stack_pointer_rtx, 
+             plus_constant (hard_frame_pointer_rtx,
+                            - (ALPHA_ROUND
+                               (current_function_outgoing_args_size)))));
     }
   else
     {
@@ -4479,12 +4908,10 @@ alpha_expand_prologue ()
          if (TARGET_CAN_FAULT_IN_PROLOGUE)
            FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
          else
-           {
-             /* This must always be the last instruction in the
-                prologue, thus we emit a special move + clobber.  */
+           /* This must always be the last instruction in the
+              prologue, thus we emit a special move + clobber.  */
              FRP (emit_insn (gen_init_fp (hard_frame_pointer_rtx,
                                           stack_pointer_rtx, sa_reg)));
-           }
        }
     }
 
@@ -4747,16 +5174,18 @@ alpha_expand_epilogue ()
   fp_offset = 0;
   sa_reg = stack_pointer_rtx;
 
-  eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
+  if (current_function_calls_eh_return)
+    eh_ofs = EH_RETURN_STACKADJ_RTX;
+  else
+    eh_ofs = NULL_RTX;
+
   if (sa_size)
     {
       /* If we have a frame pointer, restore SP from it.  */
       if ((TARGET_OPEN_VMS
           && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
          || (!TARGET_OPEN_VMS && frame_pointer_needed))
-       {
-         FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
-       }
+       FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
 
       /* Cope with very large offsets to the register save area.  */
       if (reg_offset + sa_size > 0x8000)
@@ -4777,12 +5206,11 @@ alpha_expand_epilogue ()
          
       /* Restore registers in order, excepting a true frame pointer. */
 
+      mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
       if (! eh_ofs)
-       {
-         mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
-         MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-          FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
-       }
+        MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+      FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
+
       reg_offset += 8;
       imask &= ~(1L << REG_RA);
 
@@ -4861,7 +5289,7 @@ alpha_expand_epilogue ()
       if (fp_is_frame_pointer)
        {
          emit_insn (gen_blockage ());
-         mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, fp_offset));
+         mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, fp_offset));
          MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
          FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
        }
@@ -4967,7 +5395,7 @@ alpha_output_filename (stream, name)
   else if (write_symbols == DBX_DEBUG)
     {
       ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
-      fprintf (stream, "%s ", ASM_STABS_OP);
+      fprintf (stream, "%s", ASM_STABS_OP);
       output_quoted_string (stream, name);
       fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
     }
@@ -5000,7 +5428,7 @@ alpha_output_lineno (stream, line)
     {
       /* mips-tfile doesn't understand .stabd directives.  */
       ++sym_lineno;
-      fprintf (stream, "$LM%d:\n\t%s %d,0,%d,$LM%d\n",
+      fprintf (stream, "$LM%d:\n%s%d,0,%d,$LM%d\n",
               sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
     }
   else
@@ -5071,7 +5499,7 @@ summarize_insn (x, sum, set)
     case REG:
       {
        int regno = REGNO (x);
-       unsigned long mask = 1UL << (regno % 32);
+       unsigned long mask = ((unsigned long) 1) << (regno % 32);
 
        if (regno == 31 || regno == 63)
          break;
@@ -5919,29 +6347,27 @@ check_float_value (mode, d, overflow)
       else
        fvptr = &float_values[4];
 
-      bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE));
+      memcpy (&r, d, sizeof (REAL_VALUE_TYPE));
       if (REAL_VALUES_LESS (fvptr[0], r))
        {
-         bcopy ((char *) &fvptr[0], (char *) d,
-                sizeof (REAL_VALUE_TYPE));
+         memcpy (d, &fvptr[0], sizeof (REAL_VALUE_TYPE));
          return 1;
        }
       else if (REAL_VALUES_LESS (r, fvptr[1]))
        {
-         bcopy ((char *) &fvptr[1], (char *) d,
-                sizeof (REAL_VALUE_TYPE));
+         memcpy (d, &fvptr[1], sizeof (REAL_VALUE_TYPE));
          return 1;
        }
       else if (REAL_VALUES_LESS (dconst0, r)
                && REAL_VALUES_LESS (r, fvptr[2]))
        {
-         bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+         memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
          return 1;
        }
       else if (REAL_VALUES_LESS (r, dconst0)
                && REAL_VALUES_LESS (fvptr[3], r))
        {
-         bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+         memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
          return 1;
        }
     }
@@ -6083,12 +6509,12 @@ alpha_need_linkage (name, is_local)
   /* Construct a SYMBOL_REF for us to call.  */
   {
     size_t name_len = strlen (name);
-    char *linksym = ggc_alloc_string (NULL, name_len + 6);
-
+    char *linksym = alloca (name_len + 6);
     linksym[0] = '$';
     memcpy (linksym + 1, name, name_len);
     memcpy (linksym + 1 + name_len, "..lk", 5);
-    al->linkage = gen_rtx_SYMBOL_REF (Pmode, linksym);
+    al->linkage = gen_rtx_SYMBOL_REF (Pmode,
+                                     ggc_alloc_string (linksym, name_len + 5));
   }
 
   splay_tree_insert (alpha_links, (splay_tree_key) name,