OSDN Git Service

(alpha_need_linkage): Call get_identifier.
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 3de0175..46f621a 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines used for code generation on the DEC Alpha.
-   Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1992, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
@@ -16,7 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #include <stdio.h>
@@ -37,6 +38,27 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "obstack.h"
 #include "tree.h"
 
+/* Specify which cpu to schedule for. */
+ enum processor_type alpha_cpu;
+
+/* Specify how accurate floating-point traps need to be.  */
+
+enum alpha_trap_precision alpha_tp;
+
+/* Specify the floating-point rounding mode.  */
+
+enum alpha_fp_rounding_mode alpha_fprm;
+
+/* Specify which things cause traps.  */
+
+enum alpha_fp_trap_mode alpha_fptm;
+
+/* Strings decoded into the above options.  */
+char *alpha_cpu_string;                /* -mcpu=ev[4|5] */
+char *alpha_tp_string;         /* -mtrap-precision=[p|s|i] */
+char *alpha_fprm_string;       /* -mfp-rounding-mode=[n|m|c|d] */
+char *alpha_fptm_string;       /* -mfp-trap-mode=[n|u|su|sui] */
+
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
 
@@ -53,15 +75,130 @@ char *alpha_function_name;
 
 static int inside_function = FALSE;
 
+/* Non-zero if an instruction that may cause a trap is pending.  */
+
+static int trap_pending = 0;
+
 /* Nonzero if the current function needs gp.  */
 
 int alpha_function_needs_gp;
 
 extern char *version_string;
+extern int rtx_equal_function_value_matters;
 
 /* Declarations of static functions.  */
 static void alpha_set_memflags_1  PROTO((rtx, int, int, int));
+static rtx alpha_emit_set_const_1 PROTO((rtx, enum machine_mode,
+                                        HOST_WIDE_INT, int));
 static void add_long_const     PROTO((FILE *, HOST_WIDE_INT, int, int, int));
+
+/* Compute the size of the save area in the stack.  */
+static void alpha_sa_mask      PROTO((unsigned long *imaskP,
+                                      unsigned long *fmaskP));
+/* Strip type information.  */
+#define CURRENT_FUNCTION_ARGS_INFO  \
+(TARGET_OPEN_VMS ? current_function_args_info & 0xff \
+ : current_function_args_info)
+\f
+/* Parse target option strings. */
+
+void
+override_options ()
+{
+  alpha_cpu = PROCESSOR_EV4;
+
+  if (alpha_cpu_string)
+    {
+      if (! strcmp (alpha_cpu_string, "ev4")
+         || ! strcmp (alpha_cpu_string, "21064"))
+       alpha_cpu = PROCESSOR_EV4;
+      else if (! strcmp (alpha_cpu_string, "ev5")
+              || ! strcmp (alpha_cpu_string, "21164"))
+       alpha_cpu = PROCESSOR_EV5;
+      else
+       error ("bad value `%s' for -mcpu switch", alpha_cpu_string);
+    }
+
+  alpha_tp = ALPHA_TP_PROG;
+  alpha_fprm = ALPHA_FPRM_NORM;
+  alpha_fptm = ALPHA_FPTM_N;
+
+  if (TARGET_IEEE)
+    {
+      alpha_tp = ALPHA_TP_INSN;
+      alpha_fptm = ALPHA_FPTM_SU;
+    }
+
+  if (TARGET_IEEE_WITH_INEXACT)
+    {
+      alpha_tp = ALPHA_TP_INSN;
+      alpha_fptm = ALPHA_FPTM_SUI;
+    }
+
+  if (alpha_tp_string)
+    {
+      if (! strcmp (alpha_tp_string, "p"))
+       alpha_tp = ALPHA_TP_PROG;
+      else if (! strcmp (alpha_tp_string, "f"))
+       alpha_tp = ALPHA_TP_FUNC;
+      else if (! strcmp (alpha_tp_string, "i"))
+       alpha_tp = ALPHA_TP_INSN;
+      else
+       error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string);
+    }
+
+  if (alpha_fprm_string)
+    {
+      if (! strcmp (alpha_fprm_string, "n"))
+       alpha_fprm = ALPHA_FPRM_NORM;
+      else if (! strcmp (alpha_fprm_string, "m"))
+       alpha_fprm = ALPHA_FPRM_MINF;
+      else if (! strcmp (alpha_fprm_string, "c"))
+       alpha_fprm = ALPHA_FPRM_CHOP;
+      else if (! strcmp (alpha_fprm_string,"d"))
+       alpha_fprm = ALPHA_FPRM_DYN;
+      else
+       error ("bad value `%s' for -mfp-rounding-mode switch",
+              alpha_fprm_string);
+    }
+
+  if (alpha_fptm_string)
+    {
+      if (strcmp (alpha_fptm_string, "n") == 0)
+       alpha_fptm = ALPHA_FPTM_N;
+      else if (strcmp (alpha_fptm_string, "u") == 0)
+       alpha_fptm = ALPHA_FPTM_U;
+      else if (strcmp (alpha_fptm_string, "su") == 0)
+       alpha_fptm = ALPHA_FPTM_SU;
+      else if (strcmp (alpha_fptm_string, "sui") == 0)
+       alpha_fptm = ALPHA_FPTM_SUI;
+      else
+       error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string);
+    }
+
+  /* Do some sanity checks on the above option. */
+
+  if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
+      && alpha_tp != ALPHA_TP_INSN)
+    {
+      warning ("fp software completion requires -mtrap-precision=i");
+      alpha_tp = ALPHA_TP_INSN;
+    }
+
+  if (TARGET_FLOAT_VAX)
+    {
+      if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN)
+       {
+         warning ("rounding mode not supported for VAX floats");
+         alpha_fprm = ALPHA_FPRM_NORM;
+       }
+      if (alpha_fptm == ALPHA_FPTM_SUI)
+       {
+         warning ("trap mode not supported for VAX floats");
+         alpha_fptm = ALPHA_FPTM_SU;
+       }
+    }
+}
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
 
@@ -135,10 +272,9 @@ add_operand (op, mode)
      enum machine_mode mode;
 {
   if (GET_CODE (op) == CONST_INT)
-    return ((unsigned HOST_WIDE_INT) (INTVAL (op) + 0x8000) < 0x10000
-           || ((INTVAL (op) & 0xffff) == 0
-               && (INTVAL (op) >> 31 == -1
-                   || INTVAL (op) >> 31 == 0)));
+    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
+           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L')
+           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
 
   return register_operand (op, mode);
 }
@@ -333,7 +469,8 @@ input_operand (op, mode)
        return 1;
       /* ... fall through ... */
     case MEM:
-      return mode != HImode && mode != QImode && general_operand (op, mode);
+      return (TARGET_BYTE_OPS || (mode != HImode && mode != QImode)
+             && general_operand (op, mode));
 
     case CONST_DOUBLE:
       return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
@@ -354,6 +491,7 @@ current_file_function_operand (op, mode)
      enum machine_mode mode;
 {
   return (GET_CODE (op) == SYMBOL_REF
+         && ! profile_flag && ! profile_block_flag
          && (SYMBOL_REF_FLAG (op)
              || op == XEXP (DECL_RTL (current_function_decl), 0)));
 }
@@ -369,8 +507,7 @@ call_operand (op, mode)
     return 0;
 
   return (GET_CODE (op) == SYMBOL_REF
-         || (GET_CODE (op) == REG
-             && (REGNO (op) == 27 || WINDOWS_NT)));
+         || (GET_CODE (op) == REG && (TARGET_OPEN_VMS || REGNO (op) == 27)));
 }
 
 /* Return 1 if OP is a valid Alpha comparison operator.  Here we know which
@@ -390,6 +527,23 @@ alpha_comparison_operator (op, mode)
          || (mode == DImode && (code == LEU || code == LTU)));
 }
 
+/* Return 1 if OP is a valid Alpha swapped comparison operator.  */
+
+int
+alpha_swapped_comparison_operator (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (op);
+
+  if (mode != GET_MODE (op) || GET_RTX_CLASS (code) != '<')
+    return 0;
+
+  code = swap_condition (code);
+  return (code == EQ || code == LE || code == LT
+         || (mode == DImode && (code == LEU || code == LTU)));
+}
+
 /* Return 1 if OP is a signed comparison operation.  */
 
 int
@@ -459,10 +613,7 @@ aligned_memory_operand (op, mode)
     op = XEXP (op, 0);
 
   return (GET_CODE (op) == REG
-         && (REGNO (op) == STACK_POINTER_REGNUM
-             || op == hard_frame_pointer_rtx
-             || (REGNO (op) >= FIRST_VIRTUAL_REGISTER
-                 && REGNO (op) <= LAST_VIRTUAL_REGISTER)));
+         && REGNO_POINTER_ALIGN (REGNO (op)) >= 4);
 }
 
 /* Similar, but return 1 if OP is a MEM which is not alignable.  */
@@ -496,10 +647,17 @@ unaligned_memory_operand (op, mode)
     op = XEXP (op, 0);
 
   return (GET_CODE (op) != REG
-         || (REGNO (op) != STACK_POINTER_REGNUM
-             && op != hard_frame_pointer_rtx
-             && (REGNO (op) < FIRST_VIRTUAL_REGISTER
-                 || REGNO (op) > LAST_VIRTUAL_REGISTER)));
+         || REGNO_POINTER_ALIGN (REGNO (op)) < 4);
+}
+
+/* Return 1 if OP is either a register or an unaligned memory location.  */
+
+int
+reg_or_unaligned_mem_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  return register_operand (op, mode) || unaligned_memory_operand (op, mode);
 }
 
 /* Return 1 if OP is any memory location.  During reload a pseudo matches.  */
@@ -560,11 +718,13 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
   *pbitnum = GEN_INT ((offset & 3) * 8);
 }
 
-/* Similar, but just get the address.  Handle the two reload cases.  */
+/* Similar, but just get the address.  Handle the two reload cases.  
+   Add EXTRA_OFFSET to the address we return.  */
 
 rtx
-get_unaligned_address (ref)
+get_unaligned_address (ref, extra_offset)
      rtx ref;
+     int extra_offset;
 {
   rtx base;
   HOST_WIDE_INT offset = 0;
@@ -590,7 +750,7 @@ get_unaligned_address (ref)
   if (GET_CODE (base) == PLUS)
     offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  return plus_constant (base, offset);
+  return plus_constant (base, offset + extra_offset);
 }
 \f
 /* Subfunction of the following function.  Update the flags of any MEM
@@ -657,34 +817,63 @@ alpha_set_memflags (insn, ref)
 }
 \f
 /* Try to output insns to set TARGET equal to the constant C if it can be
-   done in less than N insns.  Returns 1 if it can be done and the
-   insns have been emitted.  If it would take more than N insns, zero is
-   returned and no insns and emitted.  */
+   done in less than N insns.  Do all computations in MODE.  Returns the place
+   where the output has been placed if it can be done and the insns have been
+   emitted.  If it would take more than N insns, zero is returned and no
+   insns and emitted.  */
 
-int
-alpha_emit_set_const (target, c, n)
+rtx
+alpha_emit_set_const (target, mode, c, n)
+     rtx target;
+     enum machine_mode mode;
+     HOST_WIDE_INT c;
+     int n;
+{
+  rtx pat;
+  int i;
+
+  /* Try 1 insn, then 2, then up to N. */
+  for (i = 1; i <= n; i++)
+    if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
+      return pat;
+
+  return 0;
+}
+
+/* Internal routine for the above to check for N or below insns.  */
+
+static rtx
+alpha_emit_set_const_1 (target, mode, c, n)
      rtx target;
+     enum machine_mode mode;
      HOST_WIDE_INT c;
      int n;
 {
   HOST_WIDE_INT new = c;
   int i, bits;
+  /* Use a pseudo if highly optimizing and still generating RTL.  */
+  rtx subtarget
+    = (flag_expensive_optimizations && rtx_equal_function_value_matters
+       ? 0 : target);
+  rtx temp;
 
 #if HOST_BITS_PER_WIDE_INT == 64
   /* We are only called for SImode and DImode.  If this is SImode, ensure that
      we are sign extended to a full word.  This does not make any sense when
      cross-compiling on a narrow machine.  */
 
-  if (GET_MODE (target) == SImode)
+  if (mode == SImode)
     c = (c & 0xffffffff) - 2 * (c & 0x80000000);
 #endif
 
   /* If this is a sign-extended 32-bit constant, we can do this in at most
      three insns, so do it if we have enough insns left.  We always have
-     a sign-extended 32-bit constant when compiling on a narrow machine.  */
+     a sign-extended 32-bit constant when compiling on a narrow machine. 
+     Note that we cannot handle the constant 0x80000000.  */
 
-  if (HOST_BITS_PER_WIDE_INT != 64
-      || c >> 31 == -1 || c >> 31 == 0)
+  if ((HOST_BITS_PER_WIDE_INT != 64
+       || c >> 31 == -1 || c >> 31 == 0)
+      && c != 0x80000000U)
     {
       HOST_WIDE_INT low = (c & 0xffff) - 2 * (c & 0x8000);
       HOST_WIDE_INT tmp1 = c - low;
@@ -703,30 +892,30 @@ alpha_emit_set_const (target, c, n)
        }
 
       if (c == low || (low == 0 && extra == 0))
-       {
-         emit_move_insn (target, GEN_INT (c));
-         return 1;
-       }
+       return copy_to_suggested_reg (GEN_INT (c), target, mode);
       else if (n >= 2 + (extra != 0))
        {
-         emit_move_insn (target, GEN_INT (low));
+         temp = copy_to_suggested_reg (GEN_INT (low), subtarget, mode);
+
          if (extra != 0)
-           emit_insn (gen_add2_insn (target, GEN_INT (extra << 16)));
+           temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16),
+                                subtarget, 0, OPTAB_WIDEN);
 
-         emit_insn (gen_add2_insn (target, GEN_INT (high << 16)));
-         return 1;
+         return expand_binop (mode, add_optab, temp, GEN_INT (high << 16),
+                              target, 0, OPTAB_WIDEN);
        }
     }
 
-  /* If we couldn't do it that way, try some other methods (that depend on
-     being able to compute in the target's word size).  But if we have no
-     instructions left, don't bother.  Also, don't even try if this is 
-     SImode (in which case we should have already done something, but
-     do a sanity check here).  */
+  /* If we couldn't do it that way, try some other methods.  But if we have
+     no instructions left, don't bother.  Likewise, if this is SImode and
+     we can't make pseudos, we can't do anything since the expand_binop
+     and expand_unop calls will widen and try to make pseudos.  */
 
-  if (n == 1 || HOST_BITS_PER_WIDE_INT < 64 || GET_MODE (target) != DImode)
+  if (n == 1
+      || (mode == SImode && ! rtx_equal_function_value_matters))
     return 0;
 
+#if HOST_BITS_PER_WIDE_INT == 64
   /* First, see if can load a value into the target that is the same as the
      constant except that all bytes that are 0 are changed to be 0xff.  If we
      can, then we can do a ZAPNOT to obtain the desired constant.  */
@@ -735,26 +924,29 @@ alpha_emit_set_const (target, c, n)
     if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0)
       new |= (HOST_WIDE_INT) 0xff << i;
 
-  if (alpha_emit_set_const (target, new, n - 1))
-    {
-      emit_insn (gen_anddi3 (target, target, GEN_INT (c | ~ new)));
-      return 1;
-    }
+  /* We are only called for SImode and DImode.  If this is SImode, ensure that
+     we are sign extended to a full word.  */
+
+  if (mode == SImode)
+    new = (new & 0xffffffff) - 2 * (new & 0x80000000);
+
+  if (new != c
+      && (temp = alpha_emit_set_const (subtarget, mode, new, n - 1)) != 0)
+    return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
+                        target, 0, OPTAB_WIDEN);
+#endif
 
-  /* Find, see if we can load a related constant and then shift and possibly
+  /* Next, see if we can load a related constant and then shift and possibly
      negate it to get the constant we want.  Try this once each increasing
      numbers of insns.  */
 
   for (i = 1; i < n; i++)
     {
       /* First try complementing.  */
-      if (alpha_emit_set_const (target, ~ c, i))
-       {
-         emit_insn (gen_one_cmpldi2 (target, target));
-         return 1;
-       }
+      if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
+       return expand_unop (mode, one_cmpl_optab, temp, target, 0);
 
-      /* First try to form a constant and do a left shift.  We can do this
+      /* Next try to form a constant and do a left shift.  We can do this
         if some low-order bits are zero; the exact_log2 call below tells
         us that information.  The bits we are shifting out could be any
         value, but here we'll just try the 0- and sign-extended forms of
@@ -765,48 +957,181 @@ alpha_emit_set_const (target, c, n)
 
       if ((bits = exact_log2 (c & - c)) > 0)
        for (; bits > 0; bits--)
-         if (alpha_emit_set_const (target, c >> bits, i)
-             || alpha_emit_set_const (target,
-                                      ((unsigned HOST_WIDE_INT) c) >> bits,
-                                      i))
-           {
-             emit_insn (gen_ashldi3 (target, target, GEN_INT (bits)));
-             return 1;
-           }
+         if ((temp = (alpha_emit_set_const
+                      (subtarget, mode,
+                       (unsigned HOST_WIDE_INT) c >> bits, i))) != 0
+             || ((temp = (alpha_emit_set_const
+                         (subtarget, mode,
+                          ((unsigned HOST_WIDE_INT) c) >> bits, i)))
+                 != 0))
+           return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
+                                target, 0, OPTAB_WIDEN);
 
       /* Now try high-order zero bits.  Here we try the shifted-in bits as
-        all zero and all ones.  */
+        all zero and all ones.  Be careful to avoid shifting outside the
+        mode and to avoid shifting outside the host wide int size.  */
 
-      if ((bits = HOST_BITS_PER_WIDE_INT - floor_log2 (c) - 1) > 0)
+      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+                  - floor_log2 (c) - 1)) > 0)
        for (; bits > 0; bits--)
-         if (alpha_emit_set_const (target, c << bits, i)
-             || alpha_emit_set_const (target,
-                                      ((c << bits)
-                                       | (((HOST_WIDE_INT) 1 << bits) - 1)),
-                                      i))
-           {
-             emit_insn (gen_lshrdi3 (target, target, GEN_INT (bits)));
-             return 1;
-           }
+         if ((temp = alpha_emit_set_const (subtarget, mode,
+                                           c << bits, i)) != 0
+             || ((temp = (alpha_emit_set_const
+                          (subtarget, mode,
+                           ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
+                           i)))
+                 != 0))
+           return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
+                                target, 1, OPTAB_WIDEN);
 
       /* Now try high-order 1 bits.  We get that with a sign-extension.
-        But one bit isn't enough here.  */
+        But one bit isn't enough here.  Be careful to avoid shifting outside
+        the mode and to avoid shifting outside the host wide int size. */
       
-      if ((bits = HOST_BITS_PER_WIDE_INT - floor_log2 (~ c) - 2) > 0)
+      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+                  - floor_log2 (~ c) - 2)) > 0)
        for (; bits > 0; bits--)
-         if (alpha_emit_set_const (target, c << bits, i)
-             || alpha_emit_set_const (target,
-                                      ((c << bits)
-                                       | (((HOST_WIDE_INT) 1 << bits) - 1)),
-                                      i))
-           {
-             emit_insn (gen_ashrdi3 (target, target, GEN_INT (bits)));
-             return 1;
-           }
+         if ((temp = alpha_emit_set_const (subtarget, mode,
+                                           c << bits, i)) != 0
+             || ((temp = (alpha_emit_set_const
+                          (subtarget, mode,
+                           ((c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1)),
+                           i)))
+                 != 0))
+           return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
+                                target, 0, OPTAB_WIDEN);
     }
 
   return 0;
 }
+
+#if HOST_BITS_PER_WIDE_INT == 64
+/* Having failed to find a 3 insn sequence in alpha_emit_set_const,
+   fall back to a straight forward decomposition.  We do this to avoid
+   exponential run times encountered when looking for longer sequences
+   with alpha_emit_set_const.  */
+
+rtx
+alpha_emit_set_long_const (target, c)
+     rtx target;
+     HOST_WIDE_INT c;
+{
+  /* Use a pseudo if highly optimizing and still generating RTL.  */
+  rtx subtarget
+    = (flag_expensive_optimizations && rtx_equal_function_value_matters
+       ? 0 : target);
+  HOST_WIDE_INT d1, d2, d3, d4;
+  rtx r1, r2;
+
+  /* Decompose the entire word */
+  d1 = ((c & 0xffff) ^ 0x8000) - 0x8000;
+  c -= d1;
+  d2 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  c = (c - d2) >> 32;
+  d3 = ((c & 0xffff) ^ 0x8000) - 0x8000;
+  c -= d3;
+  d4 = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+  if (c - d4 != 0)
+    abort();
+
+  /* Construct the high word */
+  if (d3 == 0)
+    r1 = copy_to_suggested_reg (GEN_INT (d4), subtarget, DImode);
+  else if (d4 == 0)
+    r1 = copy_to_suggested_reg (GEN_INT (d3), subtarget, DImode);
+  else
+    r1 = expand_binop (DImode, add_optab, GEN_INT (d3), GEN_INT (d4),
+                      subtarget, 0, OPTAB_WIDEN);
+
+  /* Shift it into place */
+  r2 = expand_binop (DImode, ashl_optab, r1, GEN_INT (32), 
+                    subtarget, 0, OPTAB_WIDEN);
+
+  if (subtarget == 0 && d1 == d3 && d2 == d4)
+    r1 = expand_binop (DImode, add_optab, r1, r2, subtarget, 0, OPTAB_WIDEN);
+  else
+    {
+      r1 = r2;
+
+      /* Add in the low word */
+      if (d2 != 0)
+       r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d2),
+                          subtarget, 0, OPTAB_WIDEN);
+      if (d1 != 0)
+       r1 = expand_binop (DImode, add_optab, r1, GEN_INT (d1),
+                          subtarget, 0, OPTAB_WIDEN);
+    }
+
+  if (subtarget == 0)
+    r1 = copy_to_suggested_reg(r1, target, DImode);
+
+  return r1;
+}
+#endif /* HOST_BITS_PER_WIDE_INT == 64 */
+
+/* Rewrite a comparison against zero CMP of the form
+   (CODE (cc0) (const_int 0)) so it can be written validly in
+   a conditional move (if_then_else CMP ...).
+   If both of the operands that set cc0 are non-zero we must emit
+   an insn to perform the compare (it can't be done within
+   the conditional move). */
+rtx
+alpha_emit_conditional_move (cmp, mode)
+     rtx cmp;
+     enum machine_mode mode;
+{
+  enum rtx_code code = GET_CODE (cmp);
+  enum rtx_code cmov_code = NE;
+  rtx op0 = alpha_compare_op0;
+  rtx op1 = alpha_compare_op1;
+  enum machine_mode cmp_mode
+    = (GET_MODE (op0) == VOIDmode ? DImode : GET_MODE (op0));
+  enum machine_mode cmp_op_mode = alpha_compare_fp_p ? DFmode : DImode;
+  rtx tem;
+
+  if (alpha_compare_fp_p != FLOAT_MODE_P (mode))
+    return 0;
+
+  /* We may be able to use a conditional move directly.
+     This avoids emitting spurious compares. */
+  if (signed_comparison_operator (cmp, cmp_op_mode)
+      && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
+    return gen_rtx (code, VOIDmode, op0, op1);
+
+  /* We can't put the comparison insides a conditional move;
+     emit a compare instruction and put that inside the
+     conditional move.  Make sure we emit only comparisons we have;
+     swap or reverse as necessary.  */
+
+  switch (code)
+    {
+    case EQ:  case LE:  case LT:  case LEU:  case LTU:
+      /* We have these compares: */
+      break;
+
+    case NE:
+      /* This must be reversed. */
+      code = reverse_condition (code);
+      cmov_code = EQ;
+      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);
+      break;
+
+    default:
+      abort ();
+    }
+
+  tem = gen_reg_rtx (cmp_op_mode);
+  emit_move_insn (tem, gen_rtx (code, cmp_op_mode, op0, op1));
+  return gen_rtx (cmov_code, VOIDmode, tem, CONST0_RTX (cmp_op_mode));
+}
 \f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
@@ -827,6 +1152,29 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
   if (REG_NOTE_KIND (link) != 0)
     return 0;
 
+  /* EV5 costs are as given in alpha.md; exceptions are given here. */
+  if (alpha_cpu == PROCESSOR_EV5)
+    {
+      /* And the lord DEC sayeth:  "A special bypass provides an effective
+        latency of 0 cycles for an ICMP or ILOG insn producing the test
+        operand of an IBR or CMOV insn." */
+      if (recog_memoized (dep_insn) >= 0
+         && (get_attr_type (dep_insn) == TYPE_ICMP
+             || get_attr_type (dep_insn) == TYPE_ILOG)
+         && recog_memoized (insn) >= 0
+         && (get_attr_type (insn) == TYPE_IBR
+             || (get_attr_type (insn) == TYPE_CMOV
+                 && !((set = single_set (dep_insn)) != 0
+                      && GET_CODE (PATTERN (insn)) == SET
+                      && GET_CODE (SET_SRC (PATTERN (insn))) == IF_THEN_ELSE
+                      && (rtx_equal_p (SET_DEST (set),
+                                       XEXP (SET_SRC (PATTERN (insn)), 1))
+                          || rtx_equal_p (SET_DEST (set),
+                                          XEXP (SET_SRC (PATTERN (insn)), 2)))))))
+       return 1;
+      return cost;
+    } 
+
   /* If INSN is a store insn and DEP_INSN is setting the data being stored,
      we can sometimes lower the cost.  */
 
@@ -856,7 +1204,8 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
      for the address in loads and stores.  */
 
   if (recog_memoized (dep_insn) >= 0
-      && get_attr_type (dep_insn) == TYPE_IADDLOG)
+      && (get_attr_type (dep_insn) == TYPE_IADD
+         || get_attr_type (dep_insn) == TYPE_ILOG))
     switch (get_attr_type (insn))
       {
       case TYPE_LD:
@@ -893,6 +1242,77 @@ print_operand (file, x, code)
 
   switch (code)
     {
+    case '&':
+      /* Generates fp-rounding mode suffix: nothing for normal, 'c' for
+        chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
+        mode.  alpha_fprm controls which suffix is generated.  */
+      switch (alpha_fprm)
+       {
+       case ALPHA_FPRM_NORM:
+         break;
+       case ALPHA_FPRM_MINF: 
+         fputc ('m', file);
+         break;
+       case ALPHA_FPRM_CHOP:
+         fputc ('c', file);
+         break;
+       case ALPHA_FPRM_DYN:
+         fputc ('d', file);
+         break;
+       }
+      break;
+
+    case '\'':
+      /* Generates trap-mode suffix for instructions that accept the su
+        suffix only (cmpt et al).  */
+      if (alpha_tp == ALPHA_TP_INSN)
+       fputs ("su", file);
+      break;
+
+    case ')':
+      /* Generates trap-mode suffix for instructions that accept the u, su,
+        and sui suffix.  This is the bulk of the IEEE floating point
+        instructions (addt et al).  */
+      switch (alpha_fptm)
+       {
+       case ALPHA_FPTM_N:
+         break;
+       case ALPHA_FPTM_U:
+         fputc ('u', file);
+         break;
+       case ALPHA_FPTM_SU:
+         fputs ("su", file);
+         break;
+       case ALPHA_FPTM_SUI:
+         fputs ("sui", file);
+         break;
+       }
+      break;
+
+    case '+':
+      /* Generates trap-mode suffix for instructions that accept the sui
+        suffix (cvtqt and cvtqs).  */
+      switch (alpha_fptm)
+       {
+       case ALPHA_FPTM_N: case ALPHA_FPTM_U:
+       case ALPHA_FPTM_SU:     /* cvtqt/cvtqs can't cause underflow */
+         break;
+       case ALPHA_FPTM_SUI:
+         fputs ("sui", file);
+         break;
+       }
+      break;
+
+    case ',':
+      /* Generates single precision instruction suffix.  */
+      fprintf (file, "%c", (TARGET_FLOAT_VAX?'f':'s'));
+      break;
+
+    case '-':
+      /* Generates double precision instruction suffix.  */
+      fprintf (file, "%c", (TARGET_FLOAT_VAX?'g':'t'));
+      break;
+
     case 'r':
       /* If this operand is the constant zero, write it as "$31".  */
       if (GET_CODE (x) == REG)
@@ -920,7 +1340,7 @@ print_operand (file, x, code)
       if (GET_CODE (x) != CONST_INT)
        output_operand_lossage ("invalid %%N value");
 
-      fprintf (file, "%ld", ~ INTVAL (x));
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, ~ INTVAL (x));
       break;
 
     case 'P':
@@ -928,7 +1348,7 @@ print_operand (file, x, code)
       if (GET_CODE (x) != CONST_INT)
        output_operand_lossage ("invalid %%P value");
 
-      fprintf (file, "%ld", (HOST_WIDE_INT) 1 << INTVAL (x));
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, (HOST_WIDE_INT) 1 << INTVAL (x));
       break;
 
     case 'h':
@@ -936,7 +1356,7 @@ print_operand (file, x, code)
       if (GET_CODE (x) != CONST_INT)
        output_operand_lossage ("invalid %%h value");
 
-      fprintf (file, "%ld", INTVAL (x) >> 16);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) >> 16);
       break;
 
     case 'L':
@@ -944,7 +1364,8 @@ print_operand (file, x, code)
       if (GET_CODE (x) != CONST_INT)
        output_operand_lossage ("invalid %%L value");
 
-      fprintf (file, "%ld", (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000));
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+              (INTVAL (x) & 0xffff) - 2 * (INTVAL (x) & 0x8000));
       break;
 
     case 'm':
@@ -966,7 +1387,7 @@ print_operand (file, x, code)
            if (value & 0xff)
              mask |= (1 << (i + sizeof (int)));
 
-         fprintf (file, "%ld", mask & 0xff);
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask & 0xff);
        }
 
       else if (GET_CODE (x) == CONST_INT)
@@ -977,7 +1398,7 @@ print_operand (file, x, code)
            if (value & 0xff)
              mask |= (1 << i);
 
-         fprintf (file, "%ld", mask);
+         fprintf (file, HOST_WIDE_INT_PRINT_DEC, mask);
        }
       else
        output_operand_lossage ("invalid %%m value");
@@ -1019,7 +1440,7 @@ print_operand (file, x, code)
          && (INTVAL (x) & 7) != 8)
        output_operand_lossage ("invalid %%s value");
 
-      fprintf (file, "%ld", INTVAL (x) / 8);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8);
       break;
 
     case 'S':
@@ -1030,46 +1451,31 @@ print_operand (file, x, code)
          && (INTVAL (x) & 7) != 8)
        output_operand_lossage ("invalid %%s value");
 
-      fprintf (file, "%ld", (64 - INTVAL (x)) / 8);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8);
       break;
 
-    case 'C':
+    case 'C': case 'D': case 'c': case 'd':
       /* Write out comparison name.  */
-      if (GET_RTX_CLASS (GET_CODE (x)) != '<')
-       output_operand_lossage ("invalid %%C value");
-
-      if (GET_CODE (x) == LEU)
-       fprintf (file, "ule");
-      else if (GET_CODE (x) == LTU)
-       fprintf (file, "ult");
-      else
-       fprintf (file, "%s", GET_RTX_NAME (GET_CODE (x)));
-      break;
-
-    case 'D':
-      /* Similar, but write reversed code.  We can't get an unsigned code
-        here.  */
-      if (GET_RTX_CLASS (GET_CODE (x)) != '<')
-       output_operand_lossage ("invalid %%D value");
-
-      fprintf (file, "%s", GET_RTX_NAME (reverse_condition (GET_CODE (x))));
-      break;
-
-    case 'c':
-      /* Similar to `c', but swap.  We can't get unsigned here either.  */
-      if (GET_RTX_CLASS (GET_CODE (x)) != '<')
-       output_operand_lossage ("invalid %%D value");
-
-      fprintf (file, "%s", GET_RTX_NAME (swap_condition (GET_CODE (x))));
-      break;
-
-    case 'd':
-      /* Similar, but reverse and swap.  We can't get unsigned here either.  */
-      if (GET_RTX_CLASS (GET_CODE (x)) != '<')
-       output_operand_lossage ("invalid %%D value");
-
-      fprintf (file, "%s",
-              GET_RTX_NAME (swap_condition (reverse_condition ((GET_CODE (x))))));
+      {
+       enum rtx_code c = GET_CODE (x);
+
+        if (GET_RTX_CLASS (c) != '<')
+         output_operand_lossage ("invalid %%C value");
+
+       if (code == 'D')
+         c = reverse_condition (c);
+       else if (code == 'c')
+         c = swap_condition (c);
+       else if (code == 'd')
+         c = swap_condition (reverse_condition (c));
+
+        if (c == LEU)
+         fprintf (file, "ule");
+        else if (c == LTU)
+         fprintf (file, "ult");
+        else
+         fprintf (file, "%s", GET_RTX_NAME (c));
+      }
       break;
 
     case 'E':
@@ -1133,9 +1539,9 @@ alpha_builtin_saveregs (arglist)
      both registers and memory.  Both of these are already included in
      current_function_args_info.  */
 
-  argsize = GEN_INT (current_function_args_info * UNITS_PER_WORD);
+  argsize = GEN_INT (CURRENT_FUNCTION_ARGS_INFO * UNITS_PER_WORD);
 
-  /* SETUP_INCOMING_VARARGS moves the starting address base up by 48,
+  /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base up by 48,
      storing fp arg registers in the first 48 bytes, and the integer arg
      registers in the next 48 bytes.  This is only done, however, if any
      integer registers need to be stored.
@@ -1144,30 +1550,54 @@ alpha_builtin_saveregs (arglist)
      order to account for the integer arg registers which are counted in
      argsize above, but which are not actually stored on the stack.  */
 
-  addr = (current_function_args_info <= 6
-         ? plus_constant (virtual_incoming_args_rtx, 6 * UNITS_PER_WORD)
-         : plus_constant (virtual_incoming_args_rtx, - (6 * UNITS_PER_WORD)));
-
-  /* Allocate the va_list constructor */
-  block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD);
-  RTX_UNCHANGING_P (block) = 1;
-  RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
-
-  /* Store the address of the first integer register in the
-     __va_base member.  */
-  emit_move_insn (change_address (block, Pmode, XEXP (block, 0)),
-                 force_operand (addr, NULL_RTX));
-
-  /* Store the argsize as the __va_offset member.  */
-  emit_move_insn (change_address (block, Pmode,
-                                 plus_constant (XEXP (block, 0),
-                                                UNITS_PER_WORD)),
-                 force_operand (argsize, NULL_RTX));
-
-  /* Return the address of the va_list constructor, but don't put it in a
-     register.  Doing so would fail when not optimizing and produce worse
-     code when optimizing.  */
-  return XEXP (block, 0);
+  if (TARGET_OPEN_VMS)
+    addr = plus_constant (virtual_incoming_args_rtx,
+                         CURRENT_FUNCTION_ARGS_INFO <= 5 + stdarg
+                         ? UNITS_PER_WORD : - 6 * UNITS_PER_WORD);
+  else
+    addr = (CURRENT_FUNCTION_ARGS_INFO <= 5 + stdarg
+           ? plus_constant (virtual_incoming_args_rtx,
+                            6 * UNITS_PER_WORD)
+           : plus_constant (virtual_incoming_args_rtx,
+                            - (6 * UNITS_PER_WORD)));
+
+  /* For VMS, we include the argsize, while on Unix, it's handled as
+     a separate field.  */
+  if (TARGET_OPEN_VMS)
+    addr = plus_constant (addr, INTVAL (argsize));
+
+  addr = force_operand (addr, NULL_RTX);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+  addr = convert_memory_address (ptr_mode, addr);
+#endif
+
+  if (TARGET_OPEN_VMS)
+    return addr;
+  else
+    {
+      /* Allocate the va_list constructor */
+      block = assign_stack_local (BLKmode, 2 * UNITS_PER_WORD, BITS_PER_WORD);
+      RTX_UNCHANGING_P (block) = 1;
+      RTX_UNCHANGING_P (XEXP (block, 0)) = 1;
+
+      /* Store the address of the first integer register in the __base
+        member.  */
+
+      emit_move_insn (change_address (block, ptr_mode, XEXP (block, 0)), addr);
+
+      /* Store the argsize as the __va_offset member.  */
+      emit_move_insn
+       (change_address (block, TYPE_MODE (integer_type_node),
+                        plus_constant (XEXP (block, 0),
+                                       POINTER_SIZE/BITS_PER_UNIT)),
+        argsize);
+
+      /* Return the address of the va_list constructor, but don't put it in a
+        register.  Doing so would fail when not optimizing and produce worse
+        code when optimizing.  */
+      return XEXP (block, 0);
+    }
 }
 \f
 /* This page contains routines that are used to determine what the function
@@ -1175,6 +1605,128 @@ alpha_builtin_saveregs (arglist)
 
 /* Compute the size of the save area in the stack.  */
 
+#if OPEN_VMS
+
+#define REG_PV 27
+#define REG_RA 26
+
+/* These variables are used for communication between the following functions.
+   They indicate various things about the current function being compiled
+   that are used to tell what kind of prologue, epilogue and procedure
+   descriptior to generate. */
+
+/* Nonzero if we need a stack procedure.  */
+static int is_stack_procedure;
+
+/* Register number (either FP or SP) that is used to unwind the frame.  */
+static int unwind_regno;
+
+/* Register number used to save FP.  We need not have one for RA since
+   we don't modify it for register procedures.  This is only defined
+   for register frame procedures.  */
+static int save_fp_regno;
+
+/* Register number used to reference objects off our PV.  */
+static int base_regno;
+
+/*  Compute register masks for saved registers.  */
+
+static void
+alpha_sa_mask (imaskP, fmaskP)
+    unsigned long *imaskP;
+    unsigned long *fmaskP;
+{
+  unsigned long imask = 0;
+  unsigned long fmask = 0;
+  int i;
+
+  if (is_stack_procedure)
+    imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+
+  /* One for every register we have to save.  */
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i])
+      {
+       if (i < 32)
+         imask |= (1L << i);
+       else
+         fmask |= (1L << (i - 32));
+      }
+
+  *imaskP = imask;
+  *fmaskP = fmask;
+
+  return;
+}
+
+int
+alpha_sa_size ()
+{
+  int sa_size = 0;
+  HOST_WIDE_INT stack_needed;
+  int i;
+
+  /* One for every register we have to save.  */
+
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (! fixed_regs[i] && ! call_used_regs[i] && regs_ever_live[i])
+      sa_size++;
+
+  /* Start by assuming we can use a register procedure if we don't make any
+     calls (REG_RA not used) or need to save any registers and a stack
+     procedure if we do.  */
+  is_stack_procedure = regs_ever_live[REG_RA] || sa_size != 0;
+
+  /* Decide whether to refer to objects off our PV via FP or PV.
+     If we need need FP for something else or if we receive a nonlocal
+     goto (which expects PV to contain the value), we must use PV.
+     Otherwise, start by assuming we can use FP.  */
+  base_regno = (frame_pointer_needed || current_function_has_nonlocal_label
+               || is_stack_procedure
+               || current_function_outgoing_args_size
+               ? REG_PV : HARD_FRAME_POINTER_REGNUM);
+
+  /* If we want to copy PV into FP, we need to find some register in which to
+     save FP.  */
+
+  save_fp_regno = -1;
+
+  if (base_regno == HARD_FRAME_POINTER_REGNUM)
+    for (i = 0; i < 32; i++)
+      if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
+       save_fp_regno = i;
+
+  if (save_fp_regno == -1)
+    base_regno = REG_PV, is_stack_procedure = 1;
+
+  /* Stack unwinding should be done via FP unless we use it for PV.  */
+  unwind_regno
+    = base_regno == REG_PV ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
+
+  /* If this is a stack procedure, allow space for saving FP and RA.  */
+  if (is_stack_procedure)
+    sa_size += 2;
+
+  return sa_size * 8;
+}
+
+int
+alpha_pv_save_size ()
+{
+  alpha_sa_size ();
+  return is_stack_procedure ? 8 : 0;
+}
+
+int
+alpha_using_fp ()
+{
+  alpha_sa_size ();
+  return unwind_regno == HARD_FRAME_POINTER_REGNUM;
+}
+
+#else /* ! OPEN_VMS */
+
 int
 alpha_sa_size ()
 {
@@ -1197,12 +1749,14 @@ alpha_sa_size ()
   return size * 8;
 }
 
+#endif /* ! OPEN_VMS */
+
 /* Return 1 if this function can directly return via $26.  */
 
 int
 direct_return ()
 {
-  return (reload_completed && alpha_sa_size () == 0
+  return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0
          && get_frame_size () == 0
          && current_function_outgoing_args_size == 0
          && current_function_pretend_args_size == 0);
@@ -1211,7 +1765,7 @@ direct_return ()
 /* Write a version stamp.  Don't write anything if we are running as a
    cross-compiler.  Otherwise, use the versions in /usr/include/stamp.h.  */
 
-#if !defined(CROSS_COMPILE) && !defined(WINNT)
+#if !defined(CROSS_COMPILE) && !defined(_WIN32) && !defined(__linux__) && !defined(VMS)
 #include <stamp.h>
 #endif
 
@@ -1220,12 +1774,7 @@ alpha_write_verstamp (file)
      FILE *file;
 {
 #ifdef MS_STAMP
-  char *p;
-
-  fprintf (file, "\t.verstamp %d %d ", MS_STAMP, LS_STAMP);
-  for (p = version_string; *p != ' ' && *p != 0; p++)
-    fprintf (file, "%c", *p == '.' ? ' ' : *p);
-  fprintf (file, "\n");
+  fprintf (file, "\t.verstamp %d %d\n", MS_STAMP, LS_STAMP);
 #endif
 }
 \f
@@ -1289,11 +1838,452 @@ add_long_const (file, c, in_reg, out_reg, temp_reg)
 
 /* Write function prologue.  */
 
-void
-output_prolog (file, size)
-     FILE *file;
-     int size;
-{
+#if OPEN_VMS
+
+/* 
+   Quick and dirty vmskrunch routine to ensure symbols are within the
+   64 bytes limit imposed by VMS.
+
+   This is written specifically for GNAT, and may not work for C++.
+
+   This routine duplicates every symbol passed to it whether it is too
+   long or not, which is a waste of space, fix later.
+*/
+#include <string.h>
+char*
+vmskrunch (name)
+     char *name;
+{
+  char *foo;
+  int max = 60; /* Allow for the ..xx extension */
+  int len, tlen;
+
+  if (name[0] == '*')
+    return (&name[1]);
+
+  len = tlen = strlen (name);
+  foo = xstrdup (name);
+
+  /* Don't muck with the ..xx extenstion */
+  if ((foo [tlen-4] == '.') && (foo [tlen-3] == '.'))
+    {
+      max = max + 4;
+      if (tlen > max)
+       {
+         foo [tlen-4] = 0;
+         len = len - 4;
+         max = max - 4;
+       }
+    }
+
+  if (len > max)
+    {
+      char *bar;
+      int i, j, slen, nlen, xlen, chopchar;
+
+      nlen = len;
+
+      /* Change all _ and . characters to spaces, if thats enough then quit.
+        For example: "foobar__foo__bar" becomes "foobar  foo  bar" */
+
+      for (i = 0; bar = index (foo, '_'); i++)
+       *bar = ' ';
+      nlen = nlen - i;
+
+      for (i = 0; bar = index (foo, '.'); i++)
+       *bar = ' ';
+      nlen = nlen - i;
+
+      for (i = 0; bar = index (foo, '$'); i++)
+       *bar = ' ';
+      nlen = nlen - i;
+
+      /* Iteratively make blank the rightmost non-blank character on the
+        longest leftmost substring delmited by blanks, until it's short
+        enough. For example: "foobar  foo  bar" becomes, successively:
+        "fooba   foo bar"
+        "foob    foo bar"
+        "foo     foo bar"
+        "fo      foo bar"
+        "fo      fo  bar"
+        "fo      fo  ba "
+        "f       fo  ba "
+        "f       f   ba "
+        "f       f   b  "
+        etc.  */
+
+      while (nlen > max)
+       {
+         j = 0;
+         xlen = 0;
+
+         while (foo[j])
+           {
+             /* Find first non-blank */
+             if (foo[j])
+               for (i = j; foo[i]==' ' && foo[i]; i++)
+                 ;
+
+             /* Find the first blank */
+             j = i;
+             if (foo[j])
+               for (i = j + 1; foo[i] != ' ' && foo[i]; i++)
+                 ;
+
+             /* If this substring is the longest so far, remember the
+                position of the character to chop off. */
+             slen = i - j;
+             if (slen > xlen)
+               {
+                 chopchar = i - 1;
+                 xlen = slen;
+               }
+
+             j = i;
+           }
+
+         /* Try to avoid chopping uppercase suffix letters */
+         if (isupper (foo [chopchar]))
+           {
+             for (i = chopchar;
+                  isupper (foo[i]) && foo[i] != ' ' && i >= 0;
+                  i--)
+               ;
+             if (islower (foo[i]))
+               chopchar = i;
+           }
+         foo [chopchar] = ' ';
+         nlen--;
+       }
+
+      /* Put the ..xx extension back */
+      if (len != tlen)
+       {
+         foo [len] = '.';
+         len = len + 4;
+       }
+
+      /* Collapse all the blanks */
+      j = 0;
+      for (i = 0; foo[i]; i++)
+       if (foo[i] != ' ')
+         foo[j++] = foo[i];
+      foo[j] = 0;
+
+      return foo;
+    }
+
+  /* Put back the ..xx extension */
+  if (len != tlen)
+    {
+      foo [len] = '.';
+      len = len + 4;
+    }
+
+  free (foo);
+  return name;
+}
+
+/* On vms we have two kinds of functions:
+
+   - stack frame (PROC_STACK)
+       these are 'normal' functions with local vars and which are
+       calling other functions
+   - register frame (PROC_REGISTER)
+       keeps all data in registers, needs no stack
+
+   We must pass this to the assembler so it can generate the
+   proper pdsc (procedure descriptor)
+   This is done with the '.pdesc' command.
+
+   size is the stack size needed for local variables.  */
+
+void
+output_prolog (file, size)
+     FILE *file;
+     HOST_WIDE_INT size;
+{
+  unsigned long imask = 0;
+  unsigned long fmask = 0;
+  /* Stack space needed for pushing registers clobbered by us.  */
+  HOST_WIDE_INT sa_size;
+  /* Complete stack size needed.  */
+  HOST_WIDE_INT frame_size;
+  /* Offset from base reg to register save area.  */
+  int rsa_offset = 8;
+  /* Offset during register save.  */
+  int reg_offset;
+  /* Label for the procedure entry.  */
+  char entry_label[70];
+  int i;
+
+  sa_size = alpha_sa_size ();
+  frame_size
+    = ALPHA_ROUND (sa_size 
+                  + (is_stack_procedure ? 8 : 0)
+                  + size + current_function_pretend_args_size);
+
+  /* Issue function start and label.  */
+  fprintf (file, "\t.ent ");
+  assemble_name (file, alpha_function_name);
+  fprintf (file, "\n");
+  sprintf (entry_label, "%.64s..en", alpha_function_name);
+  ASM_OUTPUT_LABEL (file, entry_label);
+  inside_function = TRUE;
+
+  fprintf (file, "\t.base $%d\n", base_regno);
+
+  /* Calculate register masks for clobbered registers.  */
+
+  if (is_stack_procedure)
+    alpha_sa_mask (&imask, &fmask);
+
+  /* Adjust the stack by the frame size.  If the frame size is > 4096
+     bytes, we need to be sure we probe somewhere in the first and last
+     4096 bytes (we can probably get away without the latter test) and
+     every 8192 bytes in between.  If the frame size is > 32768, we
+     do this in a loop.  Otherwise, we generate the explicit probe
+     instructions. 
+
+     Note that we are only allowed to adjust sp once in the prologue.  */
+
+  if (frame_size < 32768)
+    {
+      if (frame_size > 4096)
+       {
+         int probed = 4096;
+
+         fprintf (file, "\tstq $31,-%d($30)\n", probed);
+
+         while (probed + 8192 < frame_size)
+           fprintf (file, "\tstq $31,-%d($30)\n", probed += 8192);
+
+         /* We only have to do this probe if we aren't saving registers.  */
+         if (sa_size == 0 && probed + 4096 < frame_size)
+           fprintf (file, "\tstq $31,-%d($30)\n", frame_size);
+       }
+
+      if (frame_size != 0)
+         fprintf (file, "\tlda $30,-%d($30)\n", frame_size);
+    }
+  else
+    {
+      /* Here we generate code to set R4 to SP + 4096 and set R23 to the
+        number of 8192 byte blocks to probe.  We then probe each block
+        in the loop and then set SP to the proper location.  If the
+        amount remaining is > 4096, we have to do one more probe if we
+        are not saving any registers.  */
+
+      HOST_WIDE_INT blocks = (frame_size + 4096) / 8192;
+      HOST_WIDE_INT leftover = frame_size + 4096 - blocks * 8192;
+
+      add_long_const (file, blocks, 31, 23, 23);
+
+      fprintf (file, "\tlda $22,4096($30)\n");
+
+      assemble_name (file, alpha_function_name);
+      fprintf (file, "..sc:\n");
+
+      fprintf (file, "\tstq $31,-8192($22)\n");
+      fprintf (file, "\tsubq $23,1,$23\n");
+      fprintf (file, "\tlda $22,-8192($22)\n");
+
+      fprintf (file, "\tbne $23,");
+      assemble_name (file, alpha_function_name);
+      fprintf (file, "..sc\n");
+
+      if (leftover > 4096 && sa_size == 0)
+       fprintf (file, "\tstq $31,-%d($22)\n", leftover);
+
+      fprintf (file, "\tlda $30,-%d($22)\n", leftover);
+    }
+
+  if (is_stack_procedure)
+    {
+      int reg_offset = rsa_offset;
+
+      /* Store R26 (RA) first.  */
+      fprintf (file, "\tstq $26,%d($30)\n", reg_offset);
+      reg_offset += 8;
+
+      /* Store integer regs. according to mask.  */
+      for (i = 0; i < 32; i++)
+        if (imask & (1L<<i))
+         {
+           fprintf (file, "\tstq $%d,%d($30)\n", i, reg_offset);
+           reg_offset += 8;
+         }
+
+      /* Print the register mask and do floating-point saves.  */
+
+      if (imask)
+       fprintf (file, "\t.mask 0x%x,0\n", imask);
+
+      for (i = 0; i < 32; i++)
+       {
+         if (fmask & (1L << i))
+           {
+             fprintf (file, "\tstt $f%d,%d($30)\n", i, reg_offset);
+             reg_offset += 8;
+           }
+       }
+
+      /* Print the floating-point mask, if we've saved any fp register.  */
+      if (fmask)
+       fprintf (file, "\t.fmask 0x%x,0\n", fmask);
+
+      fprintf (file, "\tstq $27,0($30)\n");
+    }
+  else 
+    {
+      fprintf (file, "\t.fp_save $%d\n", save_fp_regno);
+      fprintf (file, "\tbis $%d,$%d,$%d\n", HARD_FRAME_POINTER_REGNUM,
+              HARD_FRAME_POINTER_REGNUM, save_fp_regno);
+    }
+
+  if (base_regno != REG_PV)
+    fprintf (file, "\tbis $%d,$%d,$%d\n", REG_PV, REG_PV, base_regno);
+
+  if (unwind_regno == HARD_FRAME_POINTER_REGNUM)
+    fprintf (file, "\tbis $%d,$%d,$%d\n", STACK_POINTER_REGNUM,
+            STACK_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM);
+
+  /* Describe our frame.  */
+  fprintf (file, "\t.frame $%d,%d,$26,%d\n", 
+          unwind_regno, frame_size, rsa_offset);
+
+  /* If we have to allocate space for outgoing args, do it now.  */
+  if (current_function_outgoing_args_size != 0)
+    fprintf (file, "\tlda $%d,%d($%d)\n", STACK_POINTER_REGNUM,
+            - ALPHA_ROUND (current_function_outgoing_args_size),
+            HARD_FRAME_POINTER_REGNUM);
+
+  fprintf (file, "\t.prologue\n");
+
+  link_section ();
+  fprintf (file, "\t.align 3\n");
+  ASM_OUTPUT_LABEL (file, alpha_function_name);
+  fprintf (file, "\t.pdesc ");
+  assemble_name (file, alpha_function_name);
+  fprintf (file, "..en,%s\n", is_stack_procedure ? "stack" : "reg");
+  alpha_need_linkage (alpha_function_name, 1);
+  text_section ();
+
+  return;
+}
+
+/* Write function epilogue.  */
+
+void
+output_epilog (file, size)
+     FILE *file;
+     int size;
+{
+  unsigned long imask = 0;
+  unsigned long fmask = 0;
+  /* Stack space needed for pushing registers clobbered by us.  */
+  HOST_WIDE_INT sa_size = alpha_sa_size ();
+  /* Complete stack size needed.  */
+  HOST_WIDE_INT frame_size
+    = ALPHA_ROUND (sa_size
+                  + (is_stack_procedure ? 8 : 0)
+                  + size + current_function_pretend_args_size);
+  int i;
+  rtx insn = get_last_insn ();
+
+  /* If the last insn was a BARRIER, we don't have to write anything except
+     the .end pseudo-op.  */
+
+  if (GET_CODE (insn) == NOTE)
+    insn = prev_nonnote_insn (insn);
+
+  if (insn == 0 || GET_CODE (insn) != BARRIER)
+    {
+      /* Restore clobbered registers, load FP last.  */
+
+      if (is_stack_procedure)
+       {
+         int rsa_offset = 8;
+         int reg_offset;
+         int fp_offset;
+
+         if (unwind_regno == HARD_FRAME_POINTER_REGNUM)
+           fprintf (file, "\tbis $%d,$%d,$%d\n", HARD_FRAME_POINTER_REGNUM,
+                    HARD_FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM);
+
+         alpha_sa_mask (&imask, &fmask);
+
+         /* Start reloading registers after RA.  */
+         reg_offset = rsa_offset + 8;
+
+         for (i = 0; i < 32; i++)
+           if (imask & (1L<<i))
+             {
+               if (i == HARD_FRAME_POINTER_REGNUM)
+                 fp_offset = reg_offset;
+               else
+                 fprintf (file, "\tldq $%d,%d($30)\n",
+                                 i, reg_offset);
+               reg_offset += 8;
+             }
+
+         for (i = 0; i < 32; i++)
+           if (fmask & (1L << i))
+             {
+               fprintf (file, "\tldt $f%d,%d($30)\n", i, reg_offset);
+               reg_offset += 8;
+             }
+
+         /* Restore R26 (RA).  */
+         fprintf (file, "\tldq $26,%d($30)\n", rsa_offset);
+
+         /* Restore R29 (FP).  */
+         fprintf (file, "\tldq $29,%d($30)\n", fp_offset);
+       }
+      else
+       fprintf (file, "\tbis $%d,$%d,$%d\n", save_fp_regno, save_fp_regno,
+                HARD_FRAME_POINTER_REGNUM);
+
+      if (frame_size != 0)
+       {
+         if (frame_size < 32768)
+           fprintf (file, "\tlda $30,%d($30)\n", frame_size);
+         else
+           {
+             long high = frame_size >> 16;
+             long low = frame_size & 0xffff;
+             if (low & 0x8000)
+               {
+                 high++;
+                 low = -32768 + (low & 0x7fff);
+               }
+             fprintf (file, "\tldah $2,%ld($31)\n", high);
+             fprintf (file, "\tlda $2,%ld($2)\n", low);
+             fprintf (file, "\taddq $30,$2,$30\n");
+           }
+       }
+
+      /* Finally return to the caller.  */
+      fprintf (file, "\tret $31,($26),1\n");
+    }
+
+  /* End the function.  */
+  fprintf (file, "\t.end ");
+  assemble_name (file,  alpha_function_name);
+  fprintf (file, "\n");
+  inside_function = FALSE;
+
+  /* Show that we know this function if it is called again.  */
+  SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+}
+
+#else /* !OPEN_VMS */
+
+void
+output_prolog (file, size)
+     FILE *file;
+     int size;
+{
   HOST_WIDE_INT out_args_size
     = ALPHA_ROUND (current_function_outgoing_args_size);
   HOST_WIDE_INT sa_size = alpha_sa_size ();
@@ -1314,7 +2304,7 @@ output_prolog (file, size)
      linked to procedure descriptors.
      Outputting the lineno helps debugging of one line functions as they
      would otherwise get no line number at all. Please note that we would
-     like to put out last_linenum from final.c, but it is not accesible.  */
+     like to put out last_linenum from final.c, but it is not accessible.  */
 
   if (write_symbols == SDB_DEBUG)
     {
@@ -1329,12 +2319,21 @@ output_prolog (file, size)
      to the .ent directive, the lex_level, is ignored by the assembler,
      so we might as well omit it.  */
      
-  fprintf (file, "\t.ent ");
-  assemble_name (file, alpha_function_name);
-  fprintf (file, "\n");
+  if (!flag_inhibit_size_directive)
+    {
+      fprintf (file, "\t.ent ");
+      assemble_name (file, alpha_function_name);
+      fprintf (file, "\n");
+    }
   ASM_OUTPUT_LABEL (file, alpha_function_name);
   inside_function = TRUE;
 
+  if (TARGET_IEEE_CONFORMANT && !flag_inhibit_size_directive)
+    /* Set flags in procedure descriptor to request IEEE-conformant
+       math-library routines.  The value we set it to is PDSC_EXC_IEEE
+       (/usr/include/pdsc.h). */
+    fprintf (file, "\t.eflag 48\n");
+
   /* Set up offsets to alpha virtual arg/local debugging pointer.  */
 
   alpha_auto_offset = -frame_size + current_function_pretend_args_size;
@@ -1347,6 +2346,12 @@ output_prolog (file, size)
      We never need a GP for Windows/NT.  */
 
   alpha_function_needs_gp = 0;
+
+#ifdef TARGET_PROFILING_NEEDS_GP
+  if (profile_flag)
+    alpha_function_needs_gp = 1;
+#endif
+
   for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     if ((GET_CODE (insn) == CALL_INSN)
        || (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
@@ -1359,7 +2364,7 @@ output_prolog (file, size)
        break;
       }
 
-  if (WINDOWS_NT == 0)
+  if (TARGET_WINDOWS_NT == 0)
     {
       if (alpha_function_needs_gp)
        fprintf (file, "\tldgp $29,0($27)\n");
@@ -1430,10 +2435,13 @@ output_prolog (file, size)
     }
 
   /* Describe our frame.  */
-  fprintf (file, "\t.frame $%d,%d,$26,%d\n", 
-          (frame_pointer_needed
-           ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM),
-          frame_size, current_function_pretend_args_size);
+  if (!flag_inhibit_size_directive)
+    {
+      fprintf (file, "\t.frame $%d,%d,$26,%d\n", 
+              (frame_pointer_needed
+               ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM),
+              frame_size, current_function_pretend_args_size);
+    }
     
   /* Save register 26 if any other register needs to be saved.  */
   if (sa_size != 0)
@@ -1455,7 +2463,7 @@ output_prolog (file, size)
       }
 
   /* Print the register mask and do floating-point saves.  */
-  if (reg_mask)
+  if (reg_mask && !flag_inhibit_size_directive)
     fprintf (file, "\t.mask 0x%x,%d\n", reg_mask,
             actual_start_reg_offset - frame_size);
 
@@ -1472,7 +2480,7 @@ output_prolog (file, size)
       }
 
   /* Print the floating-point mask, if we've saved any fp register.  */
-  if (reg_mask)
+  if (reg_mask && !flag_inhibit_size_directive)
     fprintf (file, "\t.fmask 0x%x,%d\n", reg_mask,
             actual_start_reg_offset - frame_size + int_reg_save_area_size);
 
@@ -1482,7 +2490,8 @@ output_prolog (file, size)
     fprintf (file, "\tbis $30,$30,$15\n");
 
   /* End the prologue and say if we used gp.  */
-  fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+  if (!flag_inhibit_size_directive)
+    fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
 }
 
 /* Write function epilogue.  */
@@ -1511,7 +2520,9 @@ output_epilog (file, size)
     insn = prev_nonnote_insn (insn);
   if (insn == 0 || GET_CODE (insn) != BARRIER)
     {
-      int fp_offset;
+      int fp_offset = 0;
+
+      final_prescan_insn (NULL_RTX, NULL_PTR, 0);
 
       /* If we have a frame pointer, restore SP from it.  */
       if (frame_pointer_needed)
@@ -1558,7 +2569,7 @@ output_epilog (file, size)
       /* If we needed a frame pointer and we have to restore it, do it
         now.  This must be done in one instruction immediately
         before the SP update.  */
-      if (restore_fp)
+      if (restore_fp && fp_offset)
        fprintf (file, "\tldq $15,%d($30)\n", fp_offset);
 
       /* Now update the stack pointer, if needed.  Only one instruction must
@@ -1576,14 +2587,18 @@ output_epilog (file, size)
     }
 
   /* End the function.  */
-  fprintf (file, "\t.end ");
-  assemble_name (file, alpha_function_name);
-  fprintf (file, "\n");
+  if (!flag_inhibit_size_directive)
+    {
+      fprintf (file, "\t.end ");
+      assemble_name (file, alpha_function_name);
+      fprintf (file, "\n");
+    }
   inside_function = FALSE;
 
   /* Show that we know this function if it is called again.  */
   SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
 }
+#endif /* !OPEN_VMS */
 \f
 /* Debugging support.  */
 
@@ -1633,7 +2648,7 @@ alpha_output_filename (stream, name)
        fprintf (stream, "\t#@stabs\n");
     }
 
-  else if (!TARGET_GAS && write_symbols == DBX_DEBUG)
+  else if (write_symbols == DBX_DEBUG)
     {
       ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
       fprintf (stream, "%s ", ASM_STABS_OP);
@@ -1665,7 +2680,7 @@ alpha_output_lineno (stream, line)
      FILE *stream;
      int line;
 {
-  if (! TARGET_GAS && write_symbols == DBX_DEBUG)
+  if (write_symbols == DBX_DEBUG)
     {
       /* mips-tfile doesn't understand .stabd directives.  */
       ++sym_lineno;
@@ -1675,3 +2690,486 @@ alpha_output_lineno (stream, line)
   else
     fprintf (stream, "\n\t.loc\t%d %d\n", num_source_filenames, line);
 }
+\f
+/* Structure to show the current status of registers and memory.  */
+
+struct shadow_summary
+{
+  struct {
+    unsigned long i     : 32;  /* Mask of int regs */
+    unsigned long fp    : 32;  /* Mask of fp regs */
+    unsigned long mem   :  1;  /* mem == imem | fpmem */
+  } used, defd;
+};
+
+/* Summary the effects of expression X on the machine.  Update SUM, a pointer
+   to the summary structure.  SET is nonzero if the insn is setting the
+   object, otherwise zero.  */
+
+static void
+summarize_insn (x, sum, set)
+     rtx x;
+     struct shadow_summary *sum;
+     int set;
+{
+  char *format_ptr;
+  int i, j;
+
+  if (x == 0)
+    return;
+
+  switch (GET_CODE (x))
+    {
+      /* ??? Note that this case would be incorrect if the Alpha had a
+        ZERO_EXTRACT in SET_DEST.  */
+    case SET:
+      summarize_insn (SET_SRC (x), sum, 0);
+      summarize_insn (SET_DEST (x), sum, 1);
+      break;
+
+    case CLOBBER:
+      summarize_insn (XEXP (x, 0), sum, 1);
+      break;
+
+    case USE:
+      summarize_insn (XEXP (x, 0), sum, 0);
+      break;
+
+    case PARALLEL:
+      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
+       summarize_insn (XVECEXP (x, 0, i), sum, 0);
+      break;
+
+    case REG:
+      {
+       int regno = REGNO (x);
+       unsigned long mask = 1UL << (regno % 32);
+
+       if (regno == 31 || regno == 63)
+         break;
+
+       if (set)
+         {
+           if (regno < 32)
+             sum->defd.i |= mask;
+           else
+             sum->defd.fp |= mask;
+         }
+       else
+         {
+           if (regno < 32)
+             sum->used.i  |= mask;
+           else
+             sum->used.fp |= mask;
+         }
+       }
+      break;
+
+    case MEM:
+      if (set)
+       sum->defd.mem = 1;
+      else
+       sum->used.mem = 1;
+
+      /* Find the regs used in memory address computation: */
+      summarize_insn (XEXP (x, 0), sum, 0);
+      break;
+
+    case SUBREG:
+      summarize_insn (SUBREG_REG (x), sum, 0);
+      break;
+
+    case CONST_INT:   case CONST_DOUBLE:
+    case SYMBOL_REF:  case LABEL_REF:     case CONST:
+      break;
+
+      /* Handle common unary and binary ops for efficiency.  */
+    case COMPARE:  case PLUS:    case MINUS:   case MULT:      case DIV:
+    case MOD:      case UDIV:    case UMOD:    case AND:       case IOR:
+    case XOR:      case ASHIFT:  case ROTATE:  case ASHIFTRT:  case LSHIFTRT:
+    case ROTATERT: case SMIN:    case SMAX:    case UMIN:      case UMAX:
+    case NE:       case EQ:      case GE:      case GT:        case LE:
+    case LT:       case GEU:     case GTU:     case LEU:       case LTU:
+      summarize_insn (XEXP (x, 0), sum, 0);
+      summarize_insn (XEXP (x, 1), sum, 0);
+      break;
+
+    case NEG:  case NOT:  case SIGN_EXTEND:  case ZERO_EXTEND:
+    case TRUNCATE:  case FLOAT_EXTEND:  case FLOAT_TRUNCATE:  case FLOAT:
+    case FIX:  case UNSIGNED_FLOAT:  case UNSIGNED_FIX:  case ABS:
+    case SQRT:  case FFS: 
+      summarize_insn (XEXP (x, 0), sum, 0);
+      break;
+
+    default:
+      format_ptr = GET_RTX_FORMAT (GET_CODE (x));
+      for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+       switch (format_ptr[i])
+         {
+         case 'e':
+           summarize_insn (XEXP (x, i), sum, 0);
+           break;
+
+         case 'E':
+           for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+             summarize_insn (XVECEXP (x, i, j), sum, 0);
+           break;
+
+         default:
+           abort ();
+         }
+    }
+}
+\f
+/* This function is executed just prior to the output of assembler code for
+   INSN to modify the extracted operands so they will be output differently.
+
+   OPVEC is the vector containing the operands extracted from INSN, and
+   NOPERANDS is the number of elements of the vector which contain meaningful
+   data for this insn.  The contents of this vector are what will be used to
+   convert the insn template into assembler code, so you can change the
+   assembler output by changing the contents of the vector.
+
+   We use this function to ensure a sufficient number of `trapb' instructions
+   are in the code when the user requests code with a trap precision of
+   functions or instructions.
+
+   In naive mode, when the user requests a trap-precision of "instruction", a
+   trapb is needed after every instruction that may generate a trap (and after
+   jsr/bsr instructions, because called functions may import a trap from the
+   caller).  This ensures that the code is resumption safe but it is also slow.
+
+   When optimizations are turned on, we delay issuing a trapb as long as
+   possible.  In this context, a trap shadow is the sequence of instructions
+   that starts with a (potentially) trap generating instruction and extends to
+   the next trapb or call_pal instruction (but GCC never generates call_pal by
+   itself).  We can delay (and therefore sometimes omit) a trapb subject to the
+   following conditions:
+
+   (a) On entry to the trap shadow, if any Alpha register or memory location
+   contains a value that is used as an operand value by some instruction in
+   the trap shadow (live on entry), then no instruction in the trap shadow
+   may modify the register or memory location.
+
+   (b) Within the trap shadow, the computation of the base register for a
+   memory load or store instruction may not involve using the result
+   of an instruction that might generate an UNPREDICTABLE result.
+
+   (c) Within the trap shadow, no register may be used more than once as a
+   destination register.  (This is to make life easier for the trap-handler.)
+
+   (d) The trap shadow may not include any branch instructions.
+
+     */
+
+void
+final_prescan_insn (insn, opvec, noperands)
+     rtx insn;
+     rtx *opvec;
+     int noperands;
+{
+  static struct shadow_summary shadow = {0, 0, 0, 0, 0};
+
+#define CLOSE_SHADOW                           \
+  do                                           \
+    {                                          \
+      fputs ("\ttrapb\n", asm_out_file);       \
+      trap_pending = 0;                                \
+      bzero ((char *) &shadow,  sizeof shadow);        \
+    }                                          \
+  while (0)
+
+  if (alpha_tp == ALPHA_TP_PROG)
+    return;
+
+  if (trap_pending)
+    switch (alpha_tp)
+      {
+      case ALPHA_TP_FUNC:
+       /* Generate one trapb before epilogue (indicated by INSN==0) */
+       if (insn == 0)
+         CLOSE_SHADOW;
+       break;
+
+      case ALPHA_TP_INSN:
+       if (optimize && insn != 0)
+         {
+           struct shadow_summary sum = {0, 0, 0};
+
+           switch (GET_CODE(insn))
+             {
+             case INSN:
+               summarize_insn (PATTERN (insn), &sum, 0);
+
+               if ((sum.defd.i & shadow.defd.i)
+                   || (sum.defd.fp & shadow.defd.fp))
+                 {
+                   /* (c) would be violated */
+                   CLOSE_SHADOW;
+                   break;
+                 }
+
+               /* Combine shadow with summary of current insn: */
+               shadow.used.i     |= sum.used.i;
+               shadow.used.fp    |= sum.used.fp;
+               shadow.used.mem   |= sum.used.mem;
+               shadow.defd.i     |= sum.defd.i;
+               shadow.defd.fp    |= sum.defd.fp;
+               shadow.defd.mem   |= sum.defd.mem;
+
+               if ((sum.defd.i & shadow.used.i)
+                   || (sum.defd.fp & shadow.used.fp)
+                   || (sum.defd.mem & shadow.used.mem))
+                 {
+                   /* (a) would be violated (also takes care of (b)).  */
+                   if (get_attr_trap (insn) == TRAP_YES
+                       && ((sum.defd.i & sum.used.i)
+                           || (sum.defd.fp & sum.used.fp)))
+                     abort ();
+
+                   CLOSE_SHADOW;
+                   break;
+                 }
+               break;
+
+             case JUMP_INSN:
+             case CALL_INSN:
+             case CODE_LABEL:
+               CLOSE_SHADOW;
+               break;
+
+             default:
+               abort ();
+             }
+         }
+       else
+         CLOSE_SHADOW;
+       break;
+      }
+
+  if (insn != 0 && get_attr_trap (insn) == TRAP_YES)
+    {
+      if (optimize && !trap_pending && GET_CODE (insn) == INSN)
+       summarize_insn (PATTERN (insn), &shadow, 0);
+      trap_pending = 1;
+    }
+}
+
+/* Check a floating-point value for validity for a particular machine mode.  */
+
+static char *float_strings[] =
+{
+   "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
+  "-1.70141173319264430e+38",
+   "2.93873587705571877e-39", /* 2^-128 */
+  "-2.93873587705571877e-39"
+};
+
+static REAL_VALUE_TYPE float_values[4];
+static int inited_float_values = 0;
+
+int
+check_float_value (mode, d, overflow)
+     enum machine_mode mode;
+     REAL_VALUE_TYPE *d;
+     int overflow;
+{
+
+  if (TARGET_IEEE || TARGET_IEEE_CONFORMANT || TARGET_IEEE_WITH_INEXACT)
+    return 0;
+
+  if (TARGET_FLOAT_VAX)
+    return 0;
+
+  if (inited_float_values == 0)
+    {
+      int i;
+      for (i = 0; i < 4; i++)
+       float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode);
+
+      inited_float_values = 1;
+    }
+
+  if (mode == SFmode)
+    {
+      REAL_VALUE_TYPE r;
+
+      bcopy ((char *) d, (char *) &r, sizeof (REAL_VALUE_TYPE));
+      if (REAL_VALUES_LESS (float_values[0], r))
+       {
+         bcopy ((char *) &float_values[0], (char *) d,
+                sizeof (REAL_VALUE_TYPE));
+         return 1;
+       }
+      else if (REAL_VALUES_LESS (r, float_values[1]))
+       {
+         bcopy ((char *) &float_values[1], (char *) d,
+                sizeof (REAL_VALUE_TYPE));
+         return 1;
+       }
+      else if (REAL_VALUES_LESS (dconst0, r)
+               && REAL_VALUES_LESS (r, float_values[2]))
+       {
+         bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+         return 1;
+       }
+      else if (REAL_VALUES_LESS (r, dconst0)
+               && REAL_VALUES_LESS (float_values[3], r))
+       {
+         bcopy ((char *) &dconst0, (char *) d, sizeof (REAL_VALUE_TYPE));
+         return 1;
+       }
+    }
+
+  return 0;
+}
+
+#if OPEN_VMS
+
+void *
+function_arg (cum, mode, type, named)
+    CUMULATIVE_ARGS *cum;
+    enum machine_mode mode;
+    tree type;
+    int named;
+{
+  int arg;
+
+  if (mode == VOIDmode)                /* final call, return argument information  */
+    {
+      return GEN_INT (*cum);
+    }
+
+  arg = *cum & 0xff;
+
+  switch (mode)
+    {
+      case SFmode:
+       *cum |= (((TARGET_FLOAT_VAX)?1:4) << ((arg * 3)+8));      /* 4 = AI$K_AR_FS, IEEE single */
+        break;
+      case DFmode:
+        *cum |= (((TARGET_FLOAT_VAX)?3:5) << ((arg * 3)+8));      /* 5 = AI$K_AR_FT, IEEE double */
+        break;
+      case TFmode:
+        *cum |= (7 << ((arg * 3)+8));        /* 5 = AI$K_AR_FT, IEEE double */
+        break;
+      default:
+        break;
+    }
+
+  return (arg < 6 && ! MUST_PASS_IN_STACK (mode, type)
+        ? gen_rtx(REG, mode,
+                  (*cum & 0xff) + 16 + ((TARGET_FPREGS
+                         && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+                             || GET_MODE_CLASS (mode) == MODE_FLOAT))
+                        * 32))
+        : 0);
+}
+
+/* Structure to collect function names for final output
+   in link section.  */
+
+enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
+
+
+struct alpha_links {
+  struct alpha_links *next;
+  char *name;
+  enum links_kind kind;
+};
+
+static struct alpha_links *alpha_links_base = 0;
+
+/* Make (or fake) .linkage entry for function call.
+
+   IS_LOCAL is 0 if name is used in call, 1 if name is used in definition.  */
+
+void
+alpha_need_linkage (name, is_local)
+    char *name;
+    int is_local;
+{
+  rtx x;
+  struct alpha_links *lptr, *nptr;
+
+  if (name[0] == '*')
+    name++;
+
+  /* Is this name already defined ?  */
+
+  for (lptr = alpha_links_base; lptr; lptr = lptr->next)
+    if (strcmp (lptr->name, name) == 0)
+      {
+       if (is_local)
+         {
+           /* Defined here but external assumed.  */
+           if (lptr->kind == KIND_EXTERN)
+             lptr->kind = KIND_LOCAL;
+         }
+       else
+         {
+           /* Used here but unused assumed.  */
+           if (lptr->kind == KIND_UNUSED)
+             lptr->kind = KIND_LOCAL;
+         }
+       return;
+      }
+
+  nptr = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
+  nptr->next = alpha_links_base;
+  nptr->name = xstrdup (name);
+
+  /* Assume external if no definition.  */
+  nptr->kind = (is_local ? KIND_UNUSED : KIND_EXTERN);
+
+  /* Ensure we have an IDENTIFIER so assemble_name can mark is used.  */
+  get_identifier (name);
+
+  alpha_links_base = nptr;
+
+  return;
+}
+
+
+void
+alpha_write_linkage (stream)
+    FILE *stream;
+{
+  struct alpha_links *lptr, *nptr;
+
+  readonly_section ();
+
+  fprintf (stream, "\t.align 3\n");
+
+  for (lptr = alpha_links_base; lptr; lptr = nptr)
+    {
+      nptr = lptr->next;
+
+      if (lptr->kind == KIND_UNUSED
+         || ! TREE_SYMBOL_REFERENCED (get_identifier (lptr->name)))
+       continue;
+
+      fprintf (stream, "%s..lk:\n", lptr->name);
+      if (lptr->kind == KIND_LOCAL)   
+       {
+         /*  Local and used, build linkage pair.  */
+         fprintf (stream, "\t.quad %s..en\n", lptr->name);
+         fprintf (stream, "\t.quad %s\n", lptr->name);
+       }
+      else
+       /* External and used, request linkage pair.  */
+       fprintf (stream, "\t.linkage %s\n", lptr->name);
+    }
+}
+
+#else
+
+void
+alpha_need_linkage (name, is_local)
+     char *name;
+     int is_local;
+{
+}
+
+#endif /* OPEN_VMS */
+