OSDN Git Service

PR target/21390
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 701d4cf..66f9f48 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, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. 
+   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GCC.
@@ -53,11 +53,16 @@ Boston, MA 02111-1307, USA.  */
 #include <splay-tree.h>
 #include "cfglayout.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
+#include "tree-stdarg.h"
 
 /* Specify which cpu to schedule for.  */
+enum processor_type alpha_tune;
 
+/* Which cpu we're generating code for.  */
 enum processor_type alpha_cpu;
-static const char * const alpha_cpu_name[] = 
+
+static const char * const alpha_cpu_name[] =
 {
   "ev4", "ev5", "ev6"
 };
@@ -80,13 +85,12 @@ int alpha_tls_size = 32;
 
 /* 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] */
-const char *alpha_mlat_string; /* -mmemory-latency= */
-const char *alpha_tls_size_string; /* -mtls-size=[16|32|64] */
+static const char *alpha_cpu_string;   /* -mcpu= */
+static const char *alpha_tune_string;  /* -mtune= */
+static const char *alpha_tp_string;    /* -mtrap-precision=[p|s|i] */
+static const char *alpha_fprm_string;  /* -mfp-rounding-mode=[n|m|c|d] */
+static const char *alpha_fptm_string;  /* -mfp-trap-mode=[n|u|su|sui] */
+static const char *alpha_mlat_string;  /* -mmemory-latency= */
 
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
@@ -207,7 +211,7 @@ static struct alpha_rtx_cost_data const alpha_rtx_cost_size =
 
 /* Declarations of static functions.  */
 static struct machine_function *alpha_init_machine_status (void);
-static rtx alpha_emit_xfloating_compare (enum rtx_code, rtx, rtx);
+static rtx alpha_emit_xfloating_compare (enum rtx_code *, rtx, rtx);
 
 #if TARGET_ABI_OPEN_VMS
 static void alpha_write_linkage (FILE *, const char *, tree);
@@ -218,45 +222,100 @@ static void unicosmk_gen_dsib (unsigned long *);
 static void unicosmk_output_ssib (FILE *, const char *);
 static int unicosmk_need_dex (rtx);
 \f
+/* Implement TARGET_HANDLE_OPTION.  */
+
+static bool
+alpha_handle_option (size_t code, const char *arg, int value)
+{
+  switch (code)
+    {
+    case OPT_mfp_regs:
+      if (value == 0)
+       target_flags |= MASK_SOFT_FP;
+      break;
+
+    case OPT_mieee:
+    case OPT_mieee_with_inexact:
+      target_flags |= MASK_IEEE_CONFORMANT;
+      break;
+
+    case OPT_mcpu_:
+      alpha_cpu_string = arg;
+      break;
+
+    case OPT_mtune_:
+      alpha_tune_string = arg;
+      break;
+
+    case OPT_mfp_rounding_mode_:
+      alpha_fprm_string = arg;
+      break;
+
+    case OPT_mfp_trap_mode_:
+      alpha_fptm_string = arg;
+      break;
+
+    case OPT_mtrap_precision_:
+      alpha_tp_string = arg;
+      break;
+
+    case OPT_mmemory_latency_:
+      alpha_mlat_string = arg;
+      break;
+
+    case OPT_mtls_size_:
+      if (strcmp (arg, "16") == 0)
+       alpha_tls_size = 16;
+      else if (strcmp (arg, "32") == 0)
+       alpha_tls_size = 32;
+      else if (strcmp (arg, "64") == 0)
+       alpha_tls_size = 64;
+      else
+       error ("bad value %qs for -mtls-size switch", arg);
+      break;
+    }
+
+  return true;
+}
+
 /* Parse target option strings.  */
 
 void
 override_options (void)
 {
-  int i;
   static const struct cpu_table {
     const char *const name;
     const enum processor_type processor;
     const 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 },
+    { "ev5",   PROCESSOR_EV5, 0 },
+    { "21164", PROCESSOR_EV5, 0 },
+    { "ev56",  PROCESSOR_EV5, MASK_BWX },
+    { "21164a",        PROCESSOR_EV5, MASK_BWX },
+    { "pca56", PROCESSOR_EV5, MASK_BWX|MASK_MAX },
+    { "21164PC",PROCESSOR_EV5, MASK_BWX|MASK_MAX },
+    { "21164pc",PROCESSOR_EV5, MASK_BWX|MASK_MAX },
+    { "ev6",   PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX },
+    { "21264", PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX },
+    { "ev67",  PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX },
+    { "21264a",        PROCESSOR_EV6, MASK_BWX|MASK_MAX|MASK_FIX|MASK_CIX },
     { 0, 0, 0 }
   };
-                  
+
+  int i;
+
   /* Unicos/Mk doesn't have shared libraries.  */
   if (TARGET_ABI_UNICOSMK && flag_pic)
     {
-      warning ("-f%s ignored for Unicos/Mk (not supported)",
+      warning (0, "-f%s ignored for Unicos/Mk (not supported)",
               (flag_pic > 1) ? "PIC" : "pic");
       flag_pic = 0;
     }
 
-  /* On Unicos/Mk, the native compiler consistently generates /d suffices for 
+  /* On Unicos/Mk, the native compiler consistently generates /d suffices for
      floating-point instructions.  Make that the default for this target.  */
   if (TARGET_ABI_UNICOSMK)
     alpha_fprm = ALPHA_FPRM_DYN;
@@ -266,7 +325,7 @@ override_options (void)
   alpha_tp = ALPHA_TP_PROG;
   alpha_fptm = ALPHA_FPTM_N;
 
-  /* We cannot use su and sui qualifiers for conversion instructions on 
+  /* We cannot use su and sui qualifiers for conversion instructions on
      Unicos/Mk.  I'm not sure if this is due to assembler or hardware
      limitations.  Right now, we issue a warning if -mieee is specified
      and then ignore it; eventually, we should either get it right or
@@ -275,7 +334,7 @@ override_options (void)
   if (TARGET_IEEE)
     {
       if (TARGET_ABI_UNICOSMK)
-       warning ("-mieee not supported on Unicos/Mk");
+       warning (0, "-mieee not supported on Unicos/Mk");
       else
        {
          alpha_tp = ALPHA_TP_INSN;
@@ -286,7 +345,7 @@ override_options (void)
   if (TARGET_IEEE_WITH_INEXACT)
     {
       if (TARGET_ABI_UNICOSMK)
-       warning ("-mieee-with-inexact not supported on Unicos/Mk");
+       warning (0, "-mieee-with-inexact not supported on Unicos/Mk");
       else
        {
          alpha_tp = ALPHA_TP_INSN;
@@ -303,7 +362,7 @@ override_options (void)
       else if (! strcmp (alpha_tp_string, "i"))
        alpha_tp = ALPHA_TP_INSN;
       else
-       error ("bad value `%s' for -mtrap-precision switch", alpha_tp_string);
+       error ("bad value %qs for -mtrap-precision switch", alpha_tp_string);
     }
 
   if (alpha_fprm_string)
@@ -317,7 +376,7 @@ override_options (void)
       else if (! strcmp (alpha_fprm_string,"d"))
        alpha_fprm = ALPHA_FPRM_DYN;
       else
-       error ("bad value `%s' for -mfp-rounding-mode switch",
+       error ("bad value %qs for -mfp-rounding-mode switch",
               alpha_fprm_string);
     }
 
@@ -332,38 +391,21 @@ override_options (void)
       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);
-    }
-
-  if (alpha_tls_size_string)
-    {
-      if (strcmp (alpha_tls_size_string, "16") == 0)
-       alpha_tls_size = 16;
-      else if (strcmp (alpha_tls_size_string, "32") == 0)
-       alpha_tls_size = 32;
-      else if (strcmp (alpha_tls_size_string, "64") == 0)
-       alpha_tls_size = 64;
-      else
-       error ("bad value `%s' for -mtls-size switch", alpha_tls_size_string);
+       error ("bad value %qs for -mfp-trap-mode switch", alpha_fptm_string);
     }
 
-  alpha_cpu
-    = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6
-      : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4);
-
   if (alpha_cpu_string)
     {
       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);
+           alpha_tune = alpha_cpu = cpu_table [i].processor;
+           target_flags &= ~ (MASK_BWX | MASK_MAX | MASK_FIX | MASK_CIX);
            target_flags |= cpu_table [i].flags;
            break;
          }
       if (! cpu_table [i].name)
-       error ("bad value `%s' for -mcpu switch", alpha_cpu_string);
+       error ("bad value %qs for -mcpu switch", alpha_cpu_string);
     }
 
   if (alpha_tune_string)
@@ -371,29 +413,29 @@ override_options (void)
       for (i = 0; cpu_table [i].name; i++)
        if (! strcmp (alpha_tune_string, cpu_table [i].name))
          {
-           alpha_cpu = cpu_table [i].processor;
+           alpha_tune = cpu_table [i].processor;
            break;
          }
       if (! cpu_table [i].name)
-       error ("bad value `%s' for -mcpu switch", alpha_tune_string);
+       error ("bad value %qs for -mcpu switch", alpha_tune_string);
     }
 
   /* Do some sanity checks on the above options.  */
 
   if (TARGET_ABI_UNICOSMK && alpha_fptm != ALPHA_FPTM_N)
     {
-      warning ("trap mode not supported on Unicos/Mk");
+      warning (0, "trap mode not supported on Unicos/Mk");
       alpha_fptm = ALPHA_FPTM_N;
     }
 
   if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
-      && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6)
+      && alpha_tp != ALPHA_TP_INSN && alpha_cpu != PROCESSOR_EV6)
     {
-      warning ("fp software completion requires -mtrap-precision=i");
+      warning (0, "fp software completion requires -mtrap-precision=i");
       alpha_tp = ALPHA_TP_INSN;
     }
 
-  if (TARGET_CPU_EV6)
+  if (alpha_cpu == PROCESSOR_EV6)
     {
       /* Except for EV6 pass 1 (not released), we always have precise
         arithmetic traps.  Which means we can do software completion
@@ -405,16 +447,16 @@ override_options (void)
     {
       if (alpha_fprm == ALPHA_FPRM_MINF || alpha_fprm == ALPHA_FPRM_DYN)
        {
-         warning ("rounding mode not supported for VAX floats");
+         warning (0, "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");
+         warning (0, "trap mode not supported for VAX floats");
          alpha_fptm = ALPHA_FPTM_SU;
        }
       if (target_flags_explicit & MASK_LONG_DOUBLE_128)
-       warning ("128-bit long double not supported for VAX floats");
+       warning (0, "128-bit long double not supported for VAX floats");
       target_flags &= ~MASK_LONG_DOUBLE_128;
     }
 
@@ -432,7 +474,7 @@ override_options (void)
             && ISDIGIT ((unsigned char)alpha_mlat_string[1])
             && alpha_mlat_string[2] == '\0')
       {
-       static int const cache_latency[][4] = 
+       static int const cache_latency[][4] =
        {
          { 3, 30, -1 },        /* ev4 -- Bcache is a guess */
          { 2, 12, 38 },        /* ev5 -- Bcache from PC164 LMbench numbers */
@@ -440,14 +482,14 @@ override_options (void)
        };
 
        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_tune][lat-1] == -1)
          {
-           warning ("L%d cache latency unknown for %s",
-                    lat, alpha_cpu_name[alpha_cpu]);
+           warning (0, "L%d cache latency unknown for %s",
+                    lat, alpha_cpu_name[alpha_tune]);
            lat = 3;
          }
        else
-         lat = cache_latency[alpha_cpu][lat-1];
+         lat = cache_latency[alpha_tune][lat-1];
       }
     else if (! strcmp (alpha_mlat_string, "main"))
       {
@@ -457,7 +499,7 @@ override_options (void)
       }
     else
       {
-       warning ("bad value `%s' for -mmemory-latency", alpha_mlat_string);
+       warning (0, "bad value %qs for -mmemory-latency", alpha_mlat_string);
        lat = 3;
       }
 
@@ -519,333 +561,290 @@ zap_mask (HOST_WIDE_INT value)
   return 1;
 }
 
-/* Returns 1 if OP is either the constant zero or a register.  If a
-   register, it must be in the proper mode unless MODE is VOIDmode.  */
-
-int
-reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  return op == CONST0_RTX (mode) || register_operand (op, mode);
-}
-
-/* Return 1 if OP is a constant in the range of 0-63 (for a shift) or
-   any register.  */
+/* Return true if OP is valid for a particular TLS relocation.
+   We are already guaranteed that OP is a CONST.  */
 
 int
-reg_or_6bit_operand (rtx op, enum machine_mode mode)
+tls_symbolic_operand_1 (rtx op, int size, int unspec)
 {
-  return ((GET_CODE (op) == CONST_INT
-          && (unsigned HOST_WIDE_INT) INTVAL (op) < 64)
-         || register_operand (op, mode));
-}
-
+  op = XEXP (op, 0);
 
-/* Return 1 if OP is an 8-bit constant or any register.  */
+  if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec)
+    return 0;
+  op = XVECEXP (op, 0, 0);
 
-int
-reg_or_8bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT
-          && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100)
-         || register_operand (op, mode));
-}
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
 
-/* Return 1 if OP is a constant or any register.  */
+  if (SYMBOL_REF_LOCAL_P (op))
+    {
+      if (alpha_tls_size > size)
+       return 0;
+    }
+  else
+    {
+      if (size != 64)
+       return 0;
+    }
 
-int
-reg_or_const_int_operand (rtx op, enum machine_mode mode)
-{
-  return GET_CODE (op) == CONST_INT || register_operand (op, mode);
+  switch (SYMBOL_REF_TLS_MODEL (op))
+    {
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      return unspec == UNSPEC_DTPREL;
+    case TLS_MODEL_INITIAL_EXEC:
+      return unspec == UNSPEC_TPREL && size == 64;
+    case TLS_MODEL_LOCAL_EXEC:
+      return unspec == UNSPEC_TPREL;
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* Return 1 if OP is an 8-bit constant.  */
+/* Used by aligned_memory_operand and unaligned_memory_operand to
+   resolve what reload is going to do with OP if it's a register.  */
 
-int
-cint8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+rtx
+resolve_reload_operand (rtx op)
 {
-  return ((GET_CODE (op) == CONST_INT
-          && (unsigned HOST_WIDE_INT) INTVAL (op) < 0x100));
+  if (reload_in_progress)
+    {
+      rtx tmp = op;
+      if (GET_CODE (tmp) == SUBREG)
+       tmp = SUBREG_REG (tmp);
+      if (GET_CODE (tmp) == REG
+         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
+       {
+         op = reg_equiv_memory_loc[REGNO (tmp)];
+         if (op == 0)
+           return 0;
+       }
+    }
+  return op;
 }
 
-/* Return 1 if the operand is a valid second operand to an add insn.  */
+/* Implements CONST_OK_FOR_LETTER_P.  Return true if the value matches
+   the range defined for C in [I-P].  */
 
-int
-add_operand (rtx op, enum machine_mode mode)
+bool
+alpha_const_ok_for_letter_p (HOST_WIDE_INT value, int c)
 {
-  if (GET_CODE (op) == CONST_INT)
-    /* Constraints I, J, O and P are covered by K.  */
-    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'K')
-           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'));
+  switch (c)
+    {
+    case 'I':
+      /* An unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) value < 0x100;
+    case 'J':
+      /* The constant zero.  */
+      return value == 0;
+    case 'K':
+      /* A signed 16 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000;
+    case 'L':
+      /* A shifted signed 16 bit constant appropriate for LDAH.  */
+      return ((value & 0xffff) == 0
+              && ((value) >> 31 == -1 || value >> 31 == 0));
+    case 'M':
+      /* A constant that can be AND'ed with using a ZAP insn.  */
+      return zap_mask (value);
+    case 'N':
+      /* A complemented unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (~ value) < 0x100;
+    case 'O':
+      /* A negated unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (- value) < 0x100;
+    case 'P':
+      /* The constant 1, 2 or 3.  */
+      return value == 1 || value == 2 || value == 3;
 
-  return register_operand (op, mode);
+    default:
+      return false;
+    }
 }
 
-/* Return 1 if the operand is a valid second operand to a sign-extending
-   add insn.  */
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
+   matches for C in [GH].  */
 
-int
-sext_add_operand (rtx op, enum machine_mode mode)
+bool
+alpha_const_double_ok_for_letter_p (rtx value, int c)
 {
-  if (GET_CODE (op) == CONST_INT)
-    return (CONST_OK_FOR_LETTER_P (INTVAL (op), 'I')
-           || CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'));
+  switch (c)
+    {
+    case 'G':
+      /* The floating point zero constant.  */
+      return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT
+             && value == CONST0_RTX (GET_MODE (value)));
+
+    case 'H':
+      /* A valid operand of a ZAP insn.  */
+      return (GET_MODE (value) == VOIDmode
+             && zap_mask (CONST_DOUBLE_LOW (value))
+             && zap_mask (CONST_DOUBLE_HIGH (value)));
 
-  return reg_not_elim_operand (op, mode);
+    default:
+      return false;
+    }
 }
 
-/* Return 1 if OP is the constant 4 or 8.  */
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
+   matches for C.  */
 
-int
-const48_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+bool
+alpha_extra_constraint (rtx value, int c)
 {
-  return (GET_CODE (op) == CONST_INT
-         && (INTVAL (op) == 4 || INTVAL (op) == 8));
+  switch (c)
+    {
+    case 'Q':
+      return normal_memory_operand (value, VOIDmode);
+    case 'R':
+      return direct_call_operand (value, Pmode);
+    case 'S':
+      return (GET_CODE (value) == CONST_INT
+             && (unsigned HOST_WIDE_INT) INTVAL (value) < 64);
+    case 'T':
+      return GET_CODE (value) == HIGH;
+    case 'U':
+      return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode);
+    case 'W':
+      return (GET_CODE (value) == CONST_VECTOR
+             && value == CONST0_RTX (GET_MODE (value)));
+    default:
+      return false;
+    }
 }
 
-/* Return 1 if OP is a valid first operand to an AND insn.  */
+/* The scalar modes supported differs from the default check-what-c-supports
+   version in that sometimes TFmode is available even when long double
+   indicates only DFmode.  On unicosmk, we have the situation that HImode
+   doesn't map to any C type, but of course we still support that.  */
 
-int
-and_operand (rtx op, enum machine_mode mode)
+static bool
+alpha_scalar_mode_supported_p (enum machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == VOIDmode)
-    return (zap_mask (CONST_DOUBLE_LOW (op))
-           && zap_mask (CONST_DOUBLE_HIGH (op)));
+  switch (mode)
+    {
+    case QImode:
+    case HImode:
+    case SImode:
+    case DImode:
+    case TImode: /* via optabs.c */
+      return true;
+
+    case SFmode:
+    case DFmode:
+      return true;
 
-  if (GET_CODE (op) == CONST_INT)
-    return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
-           || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100
-           || zap_mask (INTVAL (op)));
+    case TFmode:
+      return TARGET_HAS_XFLOATING_LIBS;
 
-  return register_operand (op, mode);
+    default:
+      return false;
+    }
 }
 
-/* Return 1 if OP is a valid first operand to an IOR or XOR insn.  */
+/* Alpha implements a couple of integer vector mode operations when
+   TARGET_MAX is enabled.  We do not check TARGET_MAX here, however,
+   which allows the vectorizer to operate on e.g. move instructions,
+   or when expand_vector_operations can do something useful.  */
 
-int
-or_operand (rtx op, enum machine_mode mode)
+static bool
+alpha_vector_mode_supported_p (enum machine_mode mode)
 {
-  if (GET_CODE (op) == CONST_INT)
-    return ((unsigned HOST_WIDE_INT) INTVAL (op) < 0x100
-           || (unsigned HOST_WIDE_INT) ~ INTVAL (op) < 0x100);
-
-  return register_operand (op, mode);
+  return mode == V8QImode || mode == V4HImode || mode == V2SImode;
 }
 
-/* Return 1 if OP is a constant that is the width, in bits, of an integral
-   mode smaller than DImode.  */
+/* Return 1 if this function can directly return via $26.  */
 
 int
-mode_width_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+direct_return (void)
 {
-  return (GET_CODE (op) == CONST_INT
-         && (INTVAL (op) == 8 || INTVAL (op) == 16
-             || INTVAL (op) == 32 || INTVAL (op) == 64));
+  return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK
+         && reload_completed
+         && alpha_sa_size () == 0
+         && get_frame_size () == 0
+         && current_function_outgoing_args_size == 0
+         && current_function_pretend_args_size == 0);
 }
 
-/* Return 1 if OP is a constant that is the width of an integral machine mode
-   smaller than an integer.  */
+/* Return the ADDR_VEC associated with a tablejump insn.  */
 
-int
-mode_mask_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+rtx
+alpha_tablejump_addr_vec (rtx insn)
 {
-  if (GET_CODE (op) == CONST_INT)
-    {
-      HOST_WIDE_INT value = INTVAL (op);
-
-      if (value == 0xff)
-       return 1;
-      if (value == 0xffff)
-       return 1;
-      if (value == 0xffffffff)
-       return 1;
-      if (value == -1)
-       return 1;
-    }
-  else if (HOST_BITS_PER_WIDE_INT == 32 && GET_CODE (op) == CONST_DOUBLE)
-    {
-      if (CONST_DOUBLE_LOW (op) == 0xffffffff && CONST_DOUBLE_HIGH (op) == 0)
-       return 1;
-    }
+  rtx tmp;
 
-  return 0;
+  tmp = JUMP_LABEL (insn);
+  if (!tmp)
+    return NULL_RTX;
+  tmp = NEXT_INSN (tmp);
+  if (!tmp)
+    return NULL_RTX;
+  if (GET_CODE (tmp) == JUMP_INSN
+      && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)
+    return PATTERN (tmp);
+  return NULL_RTX;
 }
 
-/* Return 1 if OP is a multiple of 8 less than 64.  */
+/* Return the label of the predicted edge, or CONST0_RTX if we don't know.  */
 
-int
-mul8_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+rtx
+alpha_tablejump_best_label (rtx insn)
 {
-  return (GET_CODE (op) == CONST_INT
-         && (unsigned HOST_WIDE_INT) INTVAL (op) < 64
-         && (INTVAL (op) & 7) == 0);
-}
+  rtx jump_table = alpha_tablejump_addr_vec (insn);
+  rtx best_label = NULL_RTX;
 
-/* Return 1 if OP is the zero constant for MODE.  */
+  /* ??? Once the CFG doesn't keep getting completely rebuilt, look
+     there for edge frequency counts from profile data.  */
 
-int
-const0_operand (rtx op, enum machine_mode mode)
-{
-  return op == CONST0_RTX (mode);
-}
+  if (jump_table)
+    {
+      int n_labels = XVECLEN (jump_table, 1);
+      int best_count = -1;
+      int i, j;
+
+      for (i = 0; i < n_labels; i++)
+       {
+         int count = 1;
 
-/* Return 1 if OP is a hard floating-point register.  */
+         for (j = i + 1; j < n_labels; j++)
+           if (XEXP (XVECEXP (jump_table, 1, i), 0)
+               == XEXP (XVECEXP (jump_table, 1, j), 0))
+             count++;
 
-int
-hard_fp_register_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
+         if (count > best_count)
+           best_count = count, best_label = XVECEXP (jump_table, 1, i);
+       }
+    }
 
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == FLOAT_REGS;
+  return best_label ? best_label : const0_rtx;
 }
 
-/* Return 1 if OP is a hard general register.  */
+/* Return the TLS model to use for SYMBOL.  */
 
-int
-hard_int_register_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  return GET_CODE (op) == REG && REGNO_REG_CLASS (REGNO (op)) == GENERAL_REGS;
-}
-
-/* Return 1 if OP is a register or a constant integer.  */
-
-
-int
-reg_or_cint_operand (rtx op, enum machine_mode mode)
-{
-     return (GET_CODE (op) == CONST_INT
-            || register_operand (op, mode));
-}
-
-/* Return 1 if OP is something that can be reloaded into a register;
-   if it is a MEM, it need not be valid.  */
-
-int
-some_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  switch (GET_CODE (op))
-    {
-    case REG:
-    case MEM:
-    case CONST_INT:
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-    case LABEL_REF:
-    case SYMBOL_REF:
-    case CONST:
-    case HIGH:
-      return 1;
-
-    case SUBREG:
-      return some_operand (SUBREG_REG (op), VOIDmode);
-
-    default:
-      break;
-    }
-
-  return 0;
-}
-
-/* Likewise, but don't accept constants.  */
-
-int
-some_ni_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return 0;
-
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-
-  return (GET_CODE (op) == REG || GET_CODE (op) == MEM);
-}
-
-/* Return 1 if OP is a valid operand for the source of a move insn.  */
-
-int
-input_operand (rtx op, enum machine_mode mode)
+static enum tls_model
+tls_symbolic_operand_type (rtx symbol)
 {
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
+  enum tls_model model;
 
-  if (GET_MODE_CLASS (mode) == MODE_FLOAT && GET_MODE (op) != mode)
+  if (GET_CODE (symbol) != SYMBOL_REF)
     return 0;
+  model = SYMBOL_REF_TLS_MODEL (symbol);
 
-  switch (GET_CODE (op))
-    {
-    case LABEL_REF:
-    case SYMBOL_REF:
-    case CONST:
-      if (TARGET_EXPLICIT_RELOCS)
-       {
-         /* We don't split symbolic operands into something unintelligable
-            until after reload, but we do not wish non-small, non-global
-            symbolic operands to be reconstructed from their high/lo_sum
-            form.  */
-         return (small_symbolic_operand (op, mode)
-                 || global_symbolic_operand (op, mode)
-                 || gotdtp_symbolic_operand (op, mode)
-                 || gottp_symbolic_operand (op, mode));
-       }
-
-      /* This handles both the Windows/NT and OSF cases.  */
-      return mode == ptr_mode || mode == DImode;
-
-    case HIGH:
-      return (TARGET_EXPLICIT_RELOCS
-             && local_symbolic_operand (XEXP (op, 0), mode));
-
-    case REG:
-      return 1;
-
-    case SUBREG:
-      if (register_operand (op, mode))
-       return 1;
-      /* ... fall through ...  */
-    case MEM:
-      return ((TARGET_BWX || (mode != HImode && mode != QImode))
-             && general_operand (op, mode));
-
-    case CONST_DOUBLE:
-    case CONST_VECTOR:
-      return op == CONST0_RTX (mode);
-
-    case CONST_INT:
-      return mode == QImode || mode == HImode || add_operand (op, mode);
-
-    default:
-      break;
-    }
+  /* Local-exec with a 64-bit size is the same code as initial-exec.  */
+  if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64)
+    model = TLS_MODEL_INITIAL_EXEC;
 
-  return 0;
+  return model;
 }
+\f
+/* Return true if the function DECL will share the same GP as any
+   function in the current unit of translation.  */
 
-/* Return 1 if OP is a SYMBOL_REF for a function known to be in this
-   file, and in the same section as the current function.  */
-
-int
-samegp_function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+static bool
+decl_has_samegp (tree decl)
 {
-  if (GET_CODE (op) != SYMBOL_REF)
-    return false;
-
-  /* Easy test for recursion.  */
-  if (op == XEXP (DECL_RTL (current_function_decl), 0))
-    return true;
-
   /* Functions that are not local can be overridden, and thus may
      not share the same gp.  */
-  if (! SYMBOL_REF_LOCAL_P (op))
+  if (!(*targetm.binds_local_p) (decl))
     return false;
 
   /* If -msmall-data is in effect, assume that there is only one GP
@@ -855,3485 +854,2946 @@ samegp_function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
   if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
     return true;
 
-  /* Functions that are not external are defined in this UoT,
-     and thus must share the same gp.  */
-  return ! SYMBOL_REF_EXTERNAL_P (op);
+  /* Functions that are not external are defined in this UoT.  */
+  /* ??? Irritatingly, static functions not yet emitted are still
+     marked "external".  Apply this to non-static functions only.  */
+  return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl);
 }
 
-/* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr.  */
+/* Return true if EXP should be placed in the small data section.  */
 
-int
-direct_call_operand (rtx op, enum machine_mode mode)
+static bool
+alpha_in_small_data_p (tree exp)
 {
-  tree op_decl, cfun_sec, op_sec;
-
-  /* Must share the same GP.  */
-  if (!samegp_function_operand (op, mode))
-    return false;
-
-  /* If profiling is implemented via linker tricks, we can't jump
-     to the nogp alternate entry point.  Note that current_function_profile
-     would not be correct, since that doesn't indicate if the target
-     function uses profiling.  */
-  /* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
-     but is approximately correct for the OSF ABIs.  Don't know
-     what to do for VMS, NT, or UMK.  */
-  if (!TARGET_PROFILING_NEEDS_GP && profile_flag)
+  /* We want to merge strings, so we never consider them small data.  */
+  if (TREE_CODE (exp) == STRING_CST)
     return false;
 
-  /* Must be a function.  In some cases folks create thunks in static
-     data structures and then make calls to them.  If we allow the
-     direct call, we'll get an error from the linker about !samegp reloc
-     against a symbol without a .prologue directive.  */
-  if (!SYMBOL_REF_FUNCTION_P (op))
+  /* Functions are never in the small data area.  Duh.  */
+  if (TREE_CODE (exp) == FUNCTION_DECL)
     return false;
-  
-  /* Must be "near" so that the branch is assumed to reach.  With
-     -msmall-text, this is assumed true of all local symbols.  Since
-     we've already checked samegp, locality is already assured.  */
-  if (TARGET_SMALL_TEXT)
-    return true;
 
-  /* Otherwise, a decl is "near" if it is defined in the same section.  */
-  if (flag_function_sections)
-    return false;
+  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
+    {
+      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
+      if (strcmp (section, ".sdata") == 0
+         || strcmp (section, ".sbss") == 0)
+       return true;
+    }
+  else
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
 
-  op_decl = SYMBOL_REF_DECL (op);
-  if (DECL_ONE_ONLY (current_function_decl)
-      || (op_decl && DECL_ONE_ONLY (op_decl)))
-    return false;
+      /* If this is an incomplete type with size 0, then we can't put it
+        in sdata because it might be too big when completed.  */
+      if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
+       return true;
+    }
 
-  cfun_sec = DECL_SECTION_NAME (current_function_decl);
-  op_sec = op_decl ? DECL_SECTION_NAME (op_decl) : NULL;
-  return ((!cfun_sec && !op_sec)
-         || (cfun_sec && op_sec
-             && strcmp (TREE_STRING_POINTER (cfun_sec),
-                        TREE_STRING_POINTER (op_sec)) == 0));
+  return false;
 }
 
-/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
-   a (non-tls) variable known to be defined in this file.  */
-
-int
-local_symbolic_operand (rtx op, enum machine_mode mode)
+#if TARGET_ABI_OPEN_VMS
+static bool
+alpha_linkage_symbol_p (const char *symname)
 {
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) == LABEL_REF)
-    return 1;
-
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
-    op = XEXP (XEXP (op, 0), 0);
+  int symlen = strlen (symname);
 
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
+  if (symlen > 4)
+    return strcmp (&symname [symlen - 4], "..lk") == 0;
 
-  return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
+  return false;
 }
 
-/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
-   known to be defined in this file in the small data area.  */
-
-int
-small_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (! TARGET_SMALL_DATA)
-    return 0;
-
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
-    op = XEXP (XEXP (op, 0), 0);
-
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
-
-  /* ??? There's no encode_section_info equivalent for the rtl
-     constant pool, so SYMBOL_FLAG_SMALL never gets set.  */
-  if (CONSTANT_POOL_ADDRESS_P (op))
-    return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value;
+#define LINKAGE_SYMBOL_REF_P(X) \
+  ((GET_CODE (X) == SYMBOL_REF   \
+    && alpha_linkage_symbol_p (XSTR (X, 0))) \
+   || (GET_CODE (X) == CONST                 \
+       && GET_CODE (XEXP (X, 0)) == PLUS     \
+       && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \
+       && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0))))
+#endif
 
-  return (SYMBOL_REF_LOCAL_P (op)
-         && SYMBOL_REF_SMALL_P (op)
-         && SYMBOL_REF_TLS_MODEL (op) == 0);
-}
+/* legitimate_address_p recognizes an RTL expression that is a valid
+   memory address for an instruction.  The MODE argument is the
+   machine mode for the MEM expression that wants to use this address.
 
-/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
-   not known (or known not) to be defined in this file.  */
+   For Alpha, we have either a constant address or the sum of a
+   register and a constant address, or just a register.  For DImode,
+   any of those forms can be surrounded with an AND that clear the
+   low-order three bits; this is an "unaligned" access.  */
 
-int
-global_symbolic_operand (rtx op, enum machine_mode mode)
+bool
+alpha_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
 {
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
-    op = XEXP (XEXP (op, 0), 0);
+  /* If this is an ldq_u type address, discard the outer AND.  */
+  if (mode == DImode
+      && GET_CODE (x) == AND
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && INTVAL (XEXP (x, 1)) == -8)
+    x = XEXP (x, 0);
 
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
+  /* Discard non-paradoxical subregs.  */
+  if (GET_CODE (x) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (x))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+    x = SUBREG_REG (x);
 
-  return !SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
-}
+  /* Unadorned general registers are valid.  */
+  if (REG_P (x)
+      && (strict
+         ? STRICT_REG_OK_FOR_BASE_P (x)
+         : NONSTRICT_REG_OK_FOR_BASE_P (x)))
+    return true;
 
-/* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
+  /* Constant addresses (i.e. +/- 32k) are valid.  */
+  if (CONSTANT_ADDRESS_P (x))
+    return true;
 
-int
-call_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != Pmode)
-    return 0;
+#if TARGET_ABI_OPEN_VMS
+  if (LINKAGE_SYMBOL_REF_P (x))
+    return true;
+#endif
 
-  if (GET_CODE (op) == REG)
+  /* Register plus a small constant offset is valid.  */
+  if (GET_CODE (x) == PLUS)
     {
-      if (TARGET_ABI_OSF)
+      rtx ofs = XEXP (x, 1);
+      x = XEXP (x, 0);
+
+      /* Discard non-paradoxical subregs.  */
+      if (GET_CODE (x) == SUBREG
+          && (GET_MODE_SIZE (GET_MODE (x))
+             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+       x = SUBREG_REG (x);
+
+      if (REG_P (x))
        {
-         /* Disallow virtual registers to cope with pathological test cases
-            such as compile/930117-1.c in which the virtual reg decomposes
-            to the frame pointer.  Which is a hard reg that is not $27.  */
-         return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER);
+         if (! strict
+             && NONSTRICT_REG_OK_FP_BASE_P (x)
+             && GET_CODE (ofs) == CONST_INT)
+           return true;
+         if ((strict
+              ? STRICT_REG_OK_FOR_BASE_P (x)
+              : NONSTRICT_REG_OK_FOR_BASE_P (x))
+             && CONSTANT_ADDRESS_P (ofs))
+           return true;
        }
-      else
-       return 1;
     }
-  if (TARGET_ABI_UNICOSMK)
-    return 0;
-  if (GET_CODE (op) == SYMBOL_REF)
-    return 1;
 
-  return 0;
-}
+  /* If we're managing explicit relocations, LO_SUM is valid, as
+     are small data symbols.  */
+  else if (TARGET_EXPLICIT_RELOCS)
+    {
+      if (small_symbolic_operand (x, Pmode))
+       return true;
 
-/* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
-   possibly with an offset.  */
+      if (GET_CODE (x) == LO_SUM)
+       {
+         rtx ofs = XEXP (x, 1);
+         x = XEXP (x, 0);
 
-int
-symbolic_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-  if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
-    return 1;
-  if (GET_CODE (op) == CONST
-      && GET_CODE (XEXP (op,0)) == PLUS
-      && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
-      && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT)
-    return 1;
-  return 0;
-}
+         /* Discard non-paradoxical subregs.  */
+         if (GET_CODE (x) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (x))
+                 < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+           x = SUBREG_REG (x);
 
-/* Return true if OP is valid for a particular TLS relocation.  */
-
-static int
-tls_symbolic_operand_1 (rtx op, enum machine_mode mode, int size, int unspec)
-{
-  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
-    return 0;
-
-  if (GET_CODE (op) != CONST)
-    return 0;
-  op = XEXP (op, 0);
-
-  if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec)
-    return 0;
-  op = XVECEXP (op, 0, 0);
-
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
+         /* Must have a valid base register.  */
+         if (! (REG_P (x)
+                && (strict
+                    ? STRICT_REG_OK_FOR_BASE_P (x)
+                    : NONSTRICT_REG_OK_FOR_BASE_P (x))))
+           return false;
 
-  if (SYMBOL_REF_LOCAL_P (op))
-    {
-      if (alpha_tls_size > size)
-       return 0;
-    }
-  else
-    {
-      if (size != 64)
-       return 0;
+         /* The symbol must be local.  */
+         if (local_symbolic_operand (ofs, Pmode)
+             || dtp32_symbolic_operand (ofs, Pmode)
+             || tp32_symbolic_operand (ofs, Pmode))
+           return true;
+       }
     }
 
-  switch (SYMBOL_REF_TLS_MODEL (op))
-    {
-    case TLS_MODEL_LOCAL_DYNAMIC:
-      return unspec == UNSPEC_DTPREL;
-    case TLS_MODEL_INITIAL_EXEC:
-      return unspec == UNSPEC_TPREL && size == 64;
-    case TLS_MODEL_LOCAL_EXEC:
-      return unspec == UNSPEC_TPREL;
-    default:
-      abort ();
-    }
+  return false;
 }
 
-/* Return true if OP is valid for 16-bit DTP relative relocations.  */
-
-int
-dtp16_symbolic_operand (rtx op, enum machine_mode mode)
-{
-  return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_DTPREL);
-}
+/* Build the SYMBOL_REF for __tls_get_addr.  */
 
-/* Return true if OP is valid for 32-bit DTP relative relocations.  */
+static GTY(()) rtx tls_get_addr_libfunc;
 
-int
-dtp32_symbolic_operand (rtx op, enum machine_mode mode)
+static rtx
+get_tls_get_addr (void)
 {
-  return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_DTPREL);
+  if (!tls_get_addr_libfunc)
+    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+  return tls_get_addr_libfunc;
 }
 
-/* Return true if OP is valid for 64-bit DTP relative relocations.  */
+/* Try machine-dependent ways of modifying an illegitimate address
+   to be legitimate.  If we find one, return the new, valid address.  */
 
-int
-gotdtp_symbolic_operand (rtx op, enum machine_mode mode)
+rtx
+alpha_legitimize_address (rtx x, rtx scratch,
+                         enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_DTPREL);
-}
+  HOST_WIDE_INT addend;
 
-/* Return true if OP is valid for 16-bit TP relative relocations.  */
+  /* If the address is (plus reg const_int) and the CONST_INT is not a
+     valid offset, compute the high part of the constant and add it to
+     the register.  Then our address is (plus temp low-part-const).  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && ! CONSTANT_ADDRESS_P (XEXP (x, 1)))
+    {
+      addend = INTVAL (XEXP (x, 1));
+      x = XEXP (x, 0);
+      goto split_addend;
+    }
 
-int
-tp16_symbolic_operand (rtx op, enum machine_mode mode)
-{
-  return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_TPREL);
-}
+  /* If the address is (const (plus FOO const_int)), find the low-order
+     part of the CONST_INT.  Then load FOO plus any high-order part of the
+     CONST_INT into a register.  Our address is (plus reg low-part-const).
+     This is done to reduce the number of GOT entries.  */
+  if (!no_new_pseudos
+      && GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+    {
+      addend = INTVAL (XEXP (XEXP (x, 0), 1));
+      x = force_reg (Pmode, XEXP (XEXP (x, 0), 0));
+      goto split_addend;
+    }
 
-/* Return true if OP is valid for 32-bit TP relative relocations.  */
+  /* If we have a (plus reg const), emit the load as in (2), then add
+     the two registers, and finally generate (plus reg low-part-const) as
+     our address.  */
+  if (!no_new_pseudos
+      && GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST
+      && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT)
+    {
+      addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1));
+      x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0),
+                              XEXP (XEXP (XEXP (x, 1), 0), 0),
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+      goto split_addend;
+    }
 
-int
-tp32_symbolic_operand (rtx op, enum machine_mode mode)
-{
-  return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_TPREL);
-}
+  /* If this is a local symbol, split the address into HIGH/LO_SUM parts.  */
+  if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode))
+    {
+      rtx r0, r16, eqv, tga, tp, insn, dest, seq;
 
-/* Return true if OP is valid for 64-bit TP relative relocations.  */
+      switch (tls_symbolic_operand_type (x))
+       {
+       case TLS_MODEL_GLOBAL_DYNAMIC:
+         start_sequence ();
 
-int
-gottp_symbolic_operand (rtx op, enum machine_mode mode)
-{
-  return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_TPREL);
-}
+         r0 = gen_rtx_REG (Pmode, 0);
+         r16 = gen_rtx_REG (Pmode, 16);
+         tga = get_tls_get_addr ();
+         dest = gen_reg_rtx (Pmode);
+         seq = GEN_INT (alpha_next_sequence_number++);
 
-/* Return 1 if OP is a valid Alpha comparison operator.  Here we know which
-   comparisons are valid in which insn.  */
+         emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
+         insn = gen_call_value_osf_tlsgd (r0, tga, seq);
+         insn = emit_call_insn (insn);
+         CONST_OR_PURE_CALL_P (insn) = 1;
+         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
 
-int
-alpha_comparison_operator (rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
+          insn = get_insns ();
+         end_sequence ();
 
-  if (mode != GET_MODE (op) && mode != VOIDmode)
-    return 0;
+         emit_libcall_block (insn, dest, r0, x);
+         return dest;
 
-  return (code == EQ || code == LE || code == LT
-         || code == LEU || code == LTU);
-}
+       case TLS_MODEL_LOCAL_DYNAMIC:
+         start_sequence ();
 
-/* Return 1 if OP is a valid Alpha comparison operator against zero. 
-   Here we know which comparisons are valid in which insn.  */
+         r0 = gen_rtx_REG (Pmode, 0);
+         r16 = gen_rtx_REG (Pmode, 16);
+         tga = get_tls_get_addr ();
+         scratch = gen_reg_rtx (Pmode);
+         seq = GEN_INT (alpha_next_sequence_number++);
 
-int
-alpha_zero_comparison_operator (rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
+         emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
+         insn = gen_call_value_osf_tlsldm (r0, tga, seq);
+         insn = emit_call_insn (insn);
+         CONST_OR_PURE_CALL_P (insn) = 1;
+         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
 
-  if (mode != GET_MODE (op) && mode != VOIDmode)
-    return 0;
+          insn = get_insns ();
+         end_sequence ();
 
-  return (code == EQ || code == NE || code == LE || code == LT
-         || code == LEU || code == LTU);
-}
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+                               UNSPEC_TLSLDM_CALL);
+         emit_libcall_block (insn, scratch, r0, eqv);
 
-/* Return 1 if OP is a valid Alpha swapped comparison operator.  */
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
 
-int
-alpha_swapped_comparison_operator (rtx op, enum machine_mode mode)
-{
-  enum rtx_code code;
+         if (alpha_tls_size == 64)
+           {
+             dest = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, dest, eqv));
+             emit_insn (gen_adddi3 (dest, dest, scratch));
+             return dest;
+           }
+         if (alpha_tls_size == 32)
+           {
+             insn = gen_rtx_HIGH (Pmode, eqv);
+             insn = gen_rtx_PLUS (Pmode, scratch, insn);
+             scratch = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, scratch, insn));
+           }
+         return gen_rtx_LO_SUM (Pmode, scratch, eqv);
 
-  if ((mode != GET_MODE (op) && mode != VOIDmode)
-      || !COMPARISON_P (op))
-    return 0;
+       case TLS_MODEL_INITIAL_EXEC:
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
+         tp = gen_reg_rtx (Pmode);
+         scratch = gen_reg_rtx (Pmode);
+         dest = gen_reg_rtx (Pmode);
 
-  code = swap_condition (GET_CODE (op));
-  return (code == EQ || code == LE || code == LT
-         || code == LEU || code == LTU);
-}
+         emit_insn (gen_load_tp (tp));
+         emit_insn (gen_rtx_SET (VOIDmode, scratch, eqv));
+         emit_insn (gen_adddi3 (dest, tp, scratch));
+         return dest;
 
-/* Return 1 if OP is a signed comparison operation.  */
+       case TLS_MODEL_LOCAL_EXEC:
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
+         tp = gen_reg_rtx (Pmode);
 
-int
-signed_comparison_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  enum rtx_code code = GET_CODE (op);
+         emit_insn (gen_load_tp (tp));
+         if (alpha_tls_size == 32)
+           {
+             insn = gen_rtx_HIGH (Pmode, eqv);
+             insn = gen_rtx_PLUS (Pmode, tp, insn);
+             tp = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, tp, insn));
+           }
+         return gen_rtx_LO_SUM (Pmode, tp, eqv);
+       }
 
-  if (mode != GET_MODE (op) && mode != VOIDmode)
-    return 0;
+      if (local_symbolic_operand (x, Pmode))
+       {
+         if (small_symbolic_operand (x, Pmode))
+           return x;
+         else
+           {
+             if (!no_new_pseudos)
+               scratch = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, scratch,
+                                     gen_rtx_HIGH (Pmode, x)));
+             return gen_rtx_LO_SUM (Pmode, scratch, x);
+           }
+       }
+    }
 
-  return (code == EQ || code == NE
-         || code == LE || code == LT
-         || code == GE || code == GT);
-}
+  return NULL;
 
-/* Return 1 if OP is a valid Alpha floating point comparison operator.
-   Here we know which comparisons are valid in which insn.  */
+ split_addend:
+  {
+    HOST_WIDE_INT low, high;
 
-int
-alpha_fp_comparison_operator (rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
+    low = ((addend & 0xffff) ^ 0x8000) - 0x8000;
+    addend -= low;
+    high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000;
+    addend -= high;
 
-  if (mode != GET_MODE (op) && mode != VOIDmode)
-    return 0;
+    if (addend)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
+    if (high)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
 
-  return (code == EQ || code == LE || code == LT || code == UNORDERED);
+    return plus_constant (x, low);
+  }
 }
 
-/* Return 1 if this is a divide or modulus operator.  */
+/* Primarily this is required for TLS symbols, but given that our move
+   patterns *ought* to be able to handle any symbol at any time, we
+   should never be spilling symbolic operands to the constant pool, ever.  */
 
-int
-divmod_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+static bool
+alpha_cannot_force_const_mem (rtx x)
 {
-  enum rtx_code code = GET_CODE (op);
-
-  return (code == DIV || code == MOD || code == UDIV || code == UMOD);
+  enum rtx_code code = GET_CODE (x);
+  return code == SYMBOL_REF || code == LABEL_REF || code == CONST;
 }
 
-/* Return 1 if this is a float->int conversion operator.  */
+/* We do not allow indirect calls to be optimized into sibling calls, nor
+   can we allow a call to a function with a different GP to be optimized
+   into a sibcall.  */
 
-int
-fix_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+static bool
+alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (op);
+  /* Can't do indirect tail calls, since we don't know if the target
+     uses the same GP.  */
+  if (!decl)
+    return false;
 
-  return (code == FIX || code == UNSIGNED_FIX);
+  /* Otherwise, we can make a tail call if the target function shares
+     the same GP.  */
+  return decl_has_samegp (decl);
 }
 
-/* Return 1 if this memory address is a known aligned register plus
-   a constant.  It must be a valid address.  This means that we can do
-   this as an aligned reference plus some offset.
-
-   Take into account what reload will do.  */
-
 int
-aligned_memory_operand (rtx op, enum machine_mode mode)
+some_small_symbolic_operand_int (rtx *px, void *data ATTRIBUTE_UNUSED)
 {
-  rtx base;
-
-  if (reload_in_progress)
-    {
-      rtx tmp = op;
-      if (GET_CODE (tmp) == SUBREG)
-       tmp = SUBREG_REG (tmp);
-      if (GET_CODE (tmp) == REG
-         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
-       {
-         op = reg_equiv_memory_loc[REGNO (tmp)];
-         if (op == 0)
-           return 0;
-       }
-    }
-
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (MEM_ALIGN (op) >= 32)
-    return 1;
-  op = XEXP (op, 0);
+  rtx x = *px;
 
-  /* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
-     sorts of constructs.  Dig for the real base register.  */
-  if (reload_in_progress
-      && GET_CODE (op) == PLUS
-      && GET_CODE (XEXP (op, 0)) == PLUS)
-    base = XEXP (XEXP (op, 0), 0);
-  else
-    {
-      if (! memory_address_p (mode, op))
-       return 0;
-      base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
-    }
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
 
-  return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) >= 32);
+  return small_symbolic_operand (x, Pmode) != 0;
 }
 
-/* Similar, but return 1 if OP is a MEM which is not alignable.  */
-
-int
-unaligned_memory_operand (rtx op, enum machine_mode mode)
+static int
+split_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
 {
-  rtx base;
-
-  if (reload_in_progress)
-    {
-      rtx tmp = op;
-      if (GET_CODE (tmp) == SUBREG)
-       tmp = SUBREG_REG (tmp);
-      if (GET_CODE (tmp) == REG
-         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
-       {
-         op = reg_equiv_memory_loc[REGNO (tmp)];
-         if (op == 0)
-           return 0;
-       }
-    }
+  rtx x = *px;
 
-  if (GET_CODE (op) != MEM)
-    return 0;
-  if (MEM_ALIGN (op) >= 32)
-    return 0;
-  op = XEXP (op, 0);
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
 
-  /* LEGITIMIZE_RELOAD_ADDRESS creates (plus (plus reg const_hi) const_lo)
-     sorts of constructs.  Dig for the real base register.  */
-  if (reload_in_progress
-      && GET_CODE (op) == PLUS
-      && GET_CODE (XEXP (op, 0)) == PLUS)
-    base = XEXP (XEXP (op, 0), 0);
-  else
+  if (small_symbolic_operand (x, Pmode))
     {
-      if (! memory_address_p (mode, op))
-       return 0;
-      base = (GET_CODE (op) == PLUS ? XEXP (op, 0) : op);
+      x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
+      *px = x;
+      return -1;
     }
 
-  return (GET_CODE (base) == REG && REGNO_POINTER_ALIGN (REGNO (base)) < 32);
-}
-
-/* Return 1 if OP is either a register or an unaligned memory location.  */
-
-int
-reg_or_unaligned_mem_operand (rtx op, enum machine_mode mode)
-{
-  return register_operand (op, mode) || unaligned_memory_operand (op, mode);
+  return 0;
 }
 
-/* Return 1 if OP is any memory location.  During reload a pseudo matches.  */
-
-int
-any_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+rtx
+split_small_symbolic_operand (rtx x)
 {
-  return (GET_CODE (op) == MEM
-         || (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
-         || (reload_in_progress && GET_CODE (op) == REG
-             && REGNO (op) >= FIRST_PSEUDO_REGISTER)
-         || (reload_in_progress && GET_CODE (op) == SUBREG
-             && GET_CODE (SUBREG_REG (op)) == REG
-             && REGNO (SUBREG_REG (op)) >= FIRST_PSEUDO_REGISTER));
+  x = copy_insn (x);
+  for_each_rtx (&x, split_small_symbolic_operand_1, NULL);
+  return x;
 }
 
-/* Returns 1 if OP is not an eliminable register.
-
-   This exists to cure a pathological abort in the s8addq (et al) patterns,
+/* Indicate that INSN cannot be duplicated.  This is true for any insn
+   that we've marked with gpdisp relocs, since those have to stay in
+   1-1 correspondence with one another.
 
-       long foo () { long t; bar(); return (long) &t * 26107; }
+   Technically we could copy them if we could set up a mapping from one
+   sequence number to another, across the set of insns to be duplicated.
+   This seems overly complicated and error-prone since interblock motion
+   from sched-ebb could move one of the pair of insns to a different block.
 
-   which run afoul of a hack in reload to cure a (presumably) similar
-   problem with lea-type instructions on other targets.  But there is
-   one of us and many of them, so work around the problem by selectively
-   preventing combine from making the optimization.  */
+   Also cannot allow jsr insns to be duplicated.  If they throw exceptions,
+   then they'll be in a different block from their ldgp.  Which could lead
+   the bb reorder code to think that it would be ok to copy just the block
+   containing the call and branch to the block containing the ldgp.  */
 
-int
-reg_not_elim_operand (rtx op, enum machine_mode mode)
+static bool
+alpha_cannot_copy_insn_p (rtx insn)
 {
-  rtx inner = op;
-  if (GET_CODE (op) == SUBREG)
-    inner = SUBREG_REG (op);
-  if (inner == frame_pointer_rtx || inner == arg_pointer_rtx)
-    return 0;
-
-  return register_operand (op, mode);
+  if (!reload_completed || !TARGET_EXPLICIT_RELOCS)
+    return false;
+  if (recog_memoized (insn) >= 0)
+    return get_attr_cannot_copy (insn);
+  else
+    return false;
 }
 
-/* Return 1 is OP is a memory location that is not a reference (using
-   an AND) to an unaligned location.  Take into account what reload
-   will do.  */
 
-int
-normal_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+/* Try a machine-dependent way of reloading an illegitimate address
+   operand.  If we find one, push the reload and return the new rtx.  */
+
+rtx
+alpha_legitimize_reload_address (rtx x,
+                                enum machine_mode mode ATTRIBUTE_UNUSED,
+                                int opnum, int type,
+                                int ind_levels ATTRIBUTE_UNUSED)
 {
-  if (reload_in_progress)
+  /* We must recognize output that we have already generated ourselves.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
     {
-      rtx tmp = op;
-      if (GET_CODE (tmp) == SUBREG)
-       tmp = SUBREG_REG (tmp);
-      if (GET_CODE (tmp) == REG
-         && REGNO (tmp) >= FIRST_PSEUDO_REGISTER)
-       {
-         op = reg_equiv_memory_loc[REGNO (tmp)];
-
-         /* This may not have been assigned an equivalent address if it will
-            be eliminated.  In that case, it doesn't matter what we do.  */
-         if (op == 0)
-           return 1;
-       }
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, type);
+      return x;
     }
 
-  return GET_CODE (op) == MEM && GET_CODE (XEXP (op, 0)) != AND;
-}
+  /* We wish to handle large displacements off a base register by
+     splitting the addend across an ldah and the mem insn.  This
+     cuts number of extra insns needed from 3 to 1.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
+      && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0)))
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
+      HOST_WIDE_INT high
+       = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
 
-/* Accept a register, but not a subreg of any kind.  This allows us to
-   avoid pathological cases in reload wrt data movement common in 
-   int->fp conversion.  */
+      /* Check for 32-bit overflow.  */
+      if (high + low != val)
+       return NULL_RTX;
 
-int
-reg_no_subreg_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) != REG)
-    return 0;
-  return register_operand (op, mode);
-}
+      /* Reload the high part into a base reg; leave the low part
+        in the mem directly.  */
+      x = gen_rtx_PLUS (GET_MODE (x),
+                       gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
+                                     GEN_INT (high)),
+                       GEN_INT (low));
 
-/* Recognize an addition operation that includes a constant.  Used to
-   convince reload to canonize (plus (plus reg c1) c2) during register
-   elimination.  */
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, type);
+      return x;
+    }
 
-int
-addition_operation (rtx op, enum machine_mode mode)
-{
-  if (GET_MODE (op) != mode && mode != VOIDmode)
-    return 0;
-  if (GET_CODE (op) == PLUS
-      && register_operand (XEXP (op, 0), mode)
-      && GET_CODE (XEXP (op, 1)) == CONST_INT
-      && CONST_OK_FOR_LETTER_P (INTVAL (XEXP (op, 1)), 'K'))
-    return 1;
-  return 0;
+  return NULL_RTX;
 }
+\f
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
 
-/* Implements CONST_OK_FOR_LETTER_P.  Return true if the value matches
-   the range defined for C in [I-P].  */
-
-bool
-alpha_const_ok_for_letter_p (HOST_WIDE_INT value, int c)
+static bool
+alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
-  switch (c)
-    {
-    case 'I':
-      /* An unsigned 8 bit constant.  */
-      return (unsigned HOST_WIDE_INT) value < 0x100;
-    case 'J':
-      /* The constant zero.  */
-      return value == 0;
-    case 'K':
-      /* A signed 16 bit constant.  */
-      return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000;
-    case 'L':
-      /* A shifted signed 16 bit constant appropriate for LDAH.  */
-      return ((value & 0xffff) == 0
-              && ((value) >> 31 == -1 || value >> 31 == 0));
-    case 'M':
-      /* A constant that can be AND'ed with using a ZAP insn.  */
-      return zap_mask (value);
-    case 'N':
-      /* A complemented unsigned 8 bit constant.  */
-      return (unsigned HOST_WIDE_INT) (~ value) < 0x100;
-    case 'O':
-      /* A negated unsigned 8 bit constant.  */
-      return (unsigned HOST_WIDE_INT) (- value) < 0x100;
-    case 'P':
-      /* The constant 1, 2 or 3.  */
-      return value == 1 || value == 2 || value == 3;
-
-    default:
-      return false;
-    }
-}
+  enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
+  const struct alpha_rtx_cost_data *cost_data;
 
-/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
-   matches for C in [GH].  */
+  if (optimize_size)
+    cost_data = &alpha_rtx_cost_size;
+  else
+    cost_data = &alpha_rtx_cost_data[alpha_tune];
 
-bool
-alpha_const_double_ok_for_letter_p (rtx value, int c)
-{
-  switch (c)
+  switch (code)
     {
-    case 'G':
-      /* The floating point zero constant.  */
-      return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT
-             && value == CONST0_RTX (GET_MODE (value)));
-
-    case 'H':
-      /* A valid operand of a ZAP insn.  */
-      return (GET_MODE (value) == VOIDmode
-             && zap_mask (CONST_DOUBLE_LOW (value))
-             && zap_mask (CONST_DOUBLE_HIGH (value)));
+    case CONST_INT:
+      /* If this is an 8-bit constant, return zero since it can be used
+        nearly anywhere with no cost.  If it is a valid operand for an
+        ADD or AND, likewise return 0 if we know it will be used in that
+        context.  Otherwise, return 2 since it might be used there later.
+        All other constants take at least two insns.  */
+      if (INTVAL (x) >= 0 && INTVAL (x) < 256)
+       {
+         *total = 0;
+         return true;
+       }
+      /* FALLTHRU */
 
-    default:
-      return false;
-    }
-}
-
-/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
-   matches for C.  */
+    case CONST_DOUBLE:
+      if (x == CONST0_RTX (mode))
+       *total = 0;
+      else if ((outer_code == PLUS && add_operand (x, VOIDmode))
+              || (outer_code == AND && and_operand (x, VOIDmode)))
+       *total = 0;
+      else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
+       *total = 2;
+      else
+       *total = COSTS_N_INSNS (2);
+      return true;
 
-bool
-alpha_extra_constraint (rtx value, int c)
-{
-  switch (c)
-    {
-    case 'Q':
-      return normal_memory_operand (value, VOIDmode);
-    case 'R':
-      return direct_call_operand (value, Pmode);
-    case 'S':
-      return (GET_CODE (value) == CONST_INT
-             && (unsigned HOST_WIDE_INT) INTVAL (value) < 64);
-    case 'T':
-      return GET_CODE (value) == HIGH;
-    case 'U':
-      return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode);
-    case 'W':
-      return (GET_CODE (value) == CONST_VECTOR
-             && value == CONST0_RTX (GET_MODE (value)));
-    default:
-      return false;
-    }
-}
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode))
+       *total = COSTS_N_INSNS (outer_code != MEM);
+      else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode))
+       *total = COSTS_N_INSNS (1 + (outer_code != MEM));
+      else if (tls_symbolic_operand_type (x))
+       /* Estimate of cost for call_pal rduniq.  */
+       /* ??? How many insns do we emit here?  More than one...  */
+       *total = COSTS_N_INSNS (15);
+      else
+       /* Otherwise we do a load from the GOT.  */
+       *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
+      return true;
 
-/* Return 1 if this function can directly return via $26.  */
+    case HIGH:
+      /* This is effectively an add_operand.  */
+      *total = 2;
+      return true;
 
-int
-direct_return (void)
-{
-  return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK
-         && reload_completed
-         && alpha_sa_size () == 0
-         && get_frame_size () == 0
-         && current_function_outgoing_args_size == 0
-         && current_function_pretend_args_size == 0);
-}
+    case PLUS:
+    case MINUS:
+      if (float_mode_p)
+       *total = cost_data->fp_add;
+      else if (GET_CODE (XEXP (x, 0)) == MULT
+              && const48_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
+       {
+         *total = (rtx_cost (XEXP (XEXP (x, 0), 0), outer_code)
+                   + rtx_cost (XEXP (x, 1), outer_code) + COSTS_N_INSNS (1));
+         return true;
+       }
+      return false;
 
-/* Return the ADDR_VEC associated with a tablejump insn.  */
+    case MULT:
+      if (float_mode_p)
+       *total = cost_data->fp_mult;
+      else if (mode == DImode)
+       *total = cost_data->int_mult_di;
+      else
+       *total = cost_data->int_mult_si;
+      return false;
 
-rtx
-alpha_tablejump_addr_vec (rtx insn)
-{
-  rtx tmp;
+    case ASHIFT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) <= 3)
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
 
-  tmp = JUMP_LABEL (insn);
-  if (!tmp)
-    return NULL_RTX;
-  tmp = NEXT_INSN (tmp);
-  if (!tmp)
-    return NULL_RTX;
-  if (GET_CODE (tmp) == JUMP_INSN
-      && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)
-    return PATTERN (tmp);
-  return NULL_RTX;
-}
+    case ASHIFTRT:
+    case LSHIFTRT:
+      *total = cost_data->int_shift;
+      return false;
 
-/* Return the label of the predicted edge, or CONST0_RTX if we don't know.  */
+    case IF_THEN_ELSE:
+      if (float_mode_p)
+        *total = cost_data->fp_add;
+      else
+        *total = cost_data->int_cmov;
+      return false;
 
-rtx
-alpha_tablejump_best_label (rtx insn)
-{
-  rtx jump_table = alpha_tablejump_addr_vec (insn);
-  rtx best_label = NULL_RTX;
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      if (!float_mode_p)
+       *total = cost_data->int_div;
+      else if (mode == SFmode)
+        *total = cost_data->fp_div_sf;
+      else
+        *total = cost_data->fp_div_df;
+      return false;
 
-  /* ??? Once the CFG doesn't keep getting completely rebuilt, look
-     there for edge frequency counts from profile data.  */
+    case MEM:
+      *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
+      return true;
 
-  if (jump_table)
-    {
-      int n_labels = XVECLEN (jump_table, 1);
-      int best_count = -1;
-      int i, j;
+    case NEG:
+      if (! float_mode_p)
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
 
-      for (i = 0; i < n_labels; i++)
+    case ABS:
+      if (! float_mode_p)
        {
-         int count = 1;
+         *total = COSTS_N_INSNS (1) + cost_data->int_cmov;
+         return false;
+       }
+      /* FALLTHRU */
 
-         for (j = i + 1; j < n_labels; j++)
-           if (XEXP (XVECEXP (jump_table, 1, i), 0)
-               == XEXP (XVECEXP (jump_table, 1, j), 0))
-             count++;
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+      *total = cost_data->fp_add;
+      return false;
 
-         if (count > best_count)
-           best_count = count, best_label = XVECEXP (jump_table, 1, i);
-       }
+    default:
+      return false;
     }
-
-  return best_label ? best_label : const0_rtx;
 }
+\f
+/* REF is an alignable memory location.  Place an aligned SImode
+   reference into *PALIGNED_MEM and the number of bits to shift into
+   *PBITNUM.  SCRATCH is a free register for use in reloading out
+   of range stack slots.  */
 
-/* Return the TLS model to use for SYMBOL.  */
-
-static enum tls_model
-tls_symbolic_operand_type (rtx symbol)
+void
+get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum)
 {
-  enum tls_model model;
+  rtx base;
+  HOST_WIDE_INT offset = 0;
 
-  if (GET_CODE (symbol) != SYMBOL_REF)
-    return 0;
-  model = SYMBOL_REF_TLS_MODEL (symbol);
+  gcc_assert (GET_CODE (ref) == MEM);
 
-  /* Local-exec with a 64-bit size is the same code as initial-exec.  */
-  if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64)
-    model = TLS_MODEL_INITIAL_EXEC;
+  if (reload_in_progress
+      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+    {
+      base = find_replacement (&XEXP (ref, 0));
 
-  return model;
-}
-\f
-/* Return true if the function DECL will share the same GP as any
-   function in the current unit of translation.  */
+      gcc_assert (memory_address_p (GET_MODE (ref), base));
+    }
+  else
+    base = XEXP (ref, 0);
 
-static bool
-decl_has_samegp (tree decl)
-{
-  /* Functions that are not local can be overridden, and thus may
-     not share the same gp.  */
-  if (!(*targetm.binds_local_p) (decl))
-    return false;
+  if (GET_CODE (base) == PLUS)
+    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  /* If -msmall-data is in effect, assume that there is only one GP
-     for the module, and so any local symbol has this property.  We
-     need explicit relocations to be able to enforce this for symbols
-     not defined in this unit of translation, however.  */
-  if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
-    return true;
+  *paligned_mem
+    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
 
-  /* Functions that are not external are defined in this UoT.  */
-  /* ??? Irritatingly, static functions not yet emitted are still
-     marked "external".  Apply this to non-static functions only.  */
-  return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl);
+  if (WORDS_BIG_ENDIAN)
+    *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
+                             + (offset & 3) * 8));
+  else
+    *pbitnum = GEN_INT ((offset & 3) * 8);
 }
 
-/* Return true if EXP should be placed in the small data section.  */
+/* Similar, but just get the address.  Handle the two reload cases.
+   Add EXTRA_OFFSET to the address we return.  */
 
-static bool
-alpha_in_small_data_p (tree exp)
+rtx
+get_unaligned_address (rtx ref, int extra_offset)
 {
-  /* We want to merge strings, so we never consider them small data.  */
-  if (TREE_CODE (exp) == STRING_CST)
-    return false;
+  rtx base;
+  HOST_WIDE_INT offset = 0;
 
-  /* Functions are never in the small data area.  Duh.  */
-  if (TREE_CODE (exp) == FUNCTION_DECL)
-    return false;
+  gcc_assert (GET_CODE (ref) == MEM);
 
-  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
+  if (reload_in_progress
+      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     {
-      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
-      if (strcmp (section, ".sdata") == 0
-         || strcmp (section, ".sbss") == 0)
-       return true;
+      base = find_replacement (&XEXP (ref, 0));
+
+      gcc_assert (memory_address_p (GET_MODE (ref), base));
     }
   else
-    {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
+    base = XEXP (ref, 0);
 
-      /* If this is an incomplete type with size 0, then we can't put it
-        in sdata because it might be too big when completed.  */
-      if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
-       return true;
-    }
+  if (GET_CODE (base) == PLUS)
+    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  return false;
+  return plus_constant (base, offset + extra_offset);
 }
 
-#if TARGET_ABI_OPEN_VMS
-static bool
-alpha_linkage_symbol_p (const char *symname)
+/* On the Alpha, all (non-symbolic) constants except zero go into
+   a floating-point register via memory.  Note that we cannot
+   return anything that is not a subset of CLASS, and that some
+   symbolic constants cannot be dropped to memory.  */
+
+enum reg_class
+alpha_preferred_reload_class(rtx x, enum reg_class class)
 {
-  int symlen = strlen (symname);
+  /* Zero is present in any register class.  */
+  if (x == CONST0_RTX (GET_MODE (x)))
+    return class;
 
-  if (symlen > 4)
-    return strcmp (&symname [symlen - 4], "..lk") == 0;
+  /* These sorts of constants we can easily drop to memory.  */
+  if (GET_CODE (x) == CONST_INT
+      || GET_CODE (x) == CONST_DOUBLE
+      || GET_CODE (x) == CONST_VECTOR)
+    {
+      if (class == FLOAT_REGS)
+       return NO_REGS;
+      if (class == ALL_REGS)
+       return GENERAL_REGS;
+      return class;
+    }
 
-  return false;
+  /* All other kinds of constants should not (and in the case of HIGH
+     cannot) be dropped to memory -- instead we use a GENERAL_REGS
+     secondary reload.  */
+  if (CONSTANT_P (x))
+    return (class == ALL_REGS ? GENERAL_REGS : class);
+
+  return class;
 }
 
-#define LINKAGE_SYMBOL_REF_P(X) \
-  ((GET_CODE (X) == SYMBOL_REF   \
-    && alpha_linkage_symbol_p (XSTR (X, 0))) \
-   || (GET_CODE (X) == CONST                 \
-       && GET_CODE (XEXP (X, 0)) == PLUS     \
-       && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \
-       && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0))))
-#endif
+/* Loading and storing HImode or QImode values to and from memory
+   usually requires a scratch register.  The exceptions are loading
+   QImode and HImode from an aligned address to a general register
+   unless byte instructions are permitted.
 
-/* legitimate_address_p recognizes an RTL expression that is a valid
-   memory address for an instruction.  The MODE argument is the
-   machine mode for the MEM expression that wants to use this address.
+   We also cannot load an unaligned address or a paradoxical SUBREG
+   into an FP register.
 
-   For Alpha, we have either a constant address or the sum of a
-   register and a constant address, or just a register.  For DImode,
-   any of those forms can be surrounded with an AND that clear the
-   low-order three bits; this is an "unaligned" access.  */
+   We also cannot do integral arithmetic into FP regs, as might result
+   from register elimination into a DImode fp register.  */
 
-bool
-alpha_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
+enum reg_class
+secondary_reload_class (enum reg_class class, enum machine_mode mode,
+                       rtx x, int in)
 {
-  /* If this is an ldq_u type address, discard the outer AND.  */
-  if (mode == DImode
-      && GET_CODE (x) == AND
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && INTVAL (XEXP (x, 1)) == -8)
-    x = XEXP (x, 0);
-
-  /* Discard non-paradoxical subregs.  */
-  if (GET_CODE (x) == SUBREG
-      && (GET_MODE_SIZE (GET_MODE (x))
-         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-    x = SUBREG_REG (x);
-
-  /* Unadorned general registers are valid.  */
-  if (REG_P (x)
-      && (strict
-         ? STRICT_REG_OK_FOR_BASE_P (x)
-         : NONSTRICT_REG_OK_FOR_BASE_P (x)))
-    return true;
-
-  /* Constant addresses (i.e. +/- 32k) are valid.  */
-  if (CONSTANT_ADDRESS_P (x))
-    return true;
-
-#if TARGET_ABI_OPEN_VMS
-  if (LINKAGE_SYMBOL_REF_P (x))
-    return true;
-#endif
+  if ((mode == QImode || mode == HImode) && ! TARGET_BWX)
+    {
+      if (GET_CODE (x) == MEM
+         || (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
+         || (GET_CODE (x) == SUBREG
+             && (GET_CODE (SUBREG_REG (x)) == MEM
+                 || (GET_CODE (SUBREG_REG (x)) == REG
+                     && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER))))
+       {
+         if (!in || !aligned_memory_operand(x, mode))
+           return GENERAL_REGS;
+       }
+    }
 
-  /* Register plus a small constant offset is valid.  */
-  if (GET_CODE (x) == PLUS)
+  if (class == FLOAT_REGS)
     {
-      rtx ofs = XEXP (x, 1);
-      x = XEXP (x, 0);
+      if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND)
+       return GENERAL_REGS;
 
-      /* Discard non-paradoxical subregs.  */
       if (GET_CODE (x) == SUBREG
-          && (GET_MODE_SIZE (GET_MODE (x))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-       x = SUBREG_REG (x);
+         && (GET_MODE_SIZE (GET_MODE (x))
+             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+       return GENERAL_REGS;
 
-      if (REG_P (x))
-       {
-         if (! strict
-             && NONSTRICT_REG_OK_FP_BASE_P (x)
-             && GET_CODE (ofs) == CONST_INT)
-           return true;
-         if ((strict
-              ? STRICT_REG_OK_FOR_BASE_P (x)
-              : NONSTRICT_REG_OK_FOR_BASE_P (x))
-             && CONSTANT_ADDRESS_P (ofs))
-           return true;
-       }
+      if (in && INTEGRAL_MODE_P (mode)
+         && ! (memory_operand (x, mode) || x == const0_rtx))
+       return GENERAL_REGS;
     }
 
-  /* If we're managing explicit relocations, LO_SUM is valid, as
-     are small data symbols.  */
-  else if (TARGET_EXPLICIT_RELOCS)
-    {
-      if (small_symbolic_operand (x, Pmode))
-       return true;
+  return NO_REGS;
+}
+\f
+/* Subfunction of the following function.  Update the flags of any MEM
+   found in part of X.  */
 
-      if (GET_CODE (x) == LO_SUM)
-       {
-         rtx ofs = XEXP (x, 1);
-         x = XEXP (x, 0);
+static int
+alpha_set_memflags_1 (rtx *xp, void *data)
+{
+  rtx x = *xp, orig = (rtx) data;
 
-         /* Discard non-paradoxical subregs.  */
-         if (GET_CODE (x) == SUBREG
-             && (GET_MODE_SIZE (GET_MODE (x))
-                 < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-           x = SUBREG_REG (x);
+  if (GET_CODE (x) != MEM)
+    return 0;
 
-         /* Must have a valid base register.  */
-         if (! (REG_P (x)
-                && (strict
-                    ? STRICT_REG_OK_FOR_BASE_P (x)
-                    : NONSTRICT_REG_OK_FOR_BASE_P (x))))
-           return false;
+  MEM_VOLATILE_P (x) = MEM_VOLATILE_P (orig);
+  MEM_IN_STRUCT_P (x) = MEM_IN_STRUCT_P (orig);
+  MEM_SCALAR_P (x) = MEM_SCALAR_P (orig);
+  MEM_NOTRAP_P (x) = MEM_NOTRAP_P (orig);
+  MEM_READONLY_P (x) = MEM_READONLY_P (orig);
 
-         /* The symbol must be local.  */
-         if (local_symbolic_operand (ofs, Pmode)
-             || dtp32_symbolic_operand (ofs, Pmode)
-             || tp32_symbolic_operand (ofs, Pmode))
-           return true;
-       }
-    }
+  /* Sadly, we cannot use alias sets because the extra aliasing
+     produced by the AND interferes.  Given that two-byte quantities
+     are the only thing we would be able to differentiate anyway,
+     there does not seem to be any point in convoluting the early
+     out of the alias check.  */
 
-  return false;
+  return -1;
 }
 
-/* Build the SYMBOL_REF for __tls_get_addr.  */
-
-static GTY(()) rtx tls_get_addr_libfunc;
+/* Given INSN, which is an INSN list or the PATTERN of a single insn
+   generated to perform a memory operation, look for any MEMs in either
+   a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and
+   volatile flags from REF into each of the MEMs found.  If REF is not
+   a MEM, don't do anything.  */
 
-static rtx
-get_tls_get_addr (void)
+void
+alpha_set_memflags (rtx insn, rtx ref)
 {
-  if (!tls_get_addr_libfunc)
-    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
-  return tls_get_addr_libfunc;
+  rtx *base_ptr;
+
+  if (GET_CODE (ref) != MEM)
+    return;
+
+  /* This is only called from alpha.md, after having had something
+     generated from one of the insn patterns.  So if everything is
+     zero, the pattern is already up-to-date.  */
+  if (!MEM_VOLATILE_P (ref)
+      && !MEM_IN_STRUCT_P (ref)
+      && !MEM_SCALAR_P (ref)
+      && !MEM_NOTRAP_P (ref)
+      && !MEM_READONLY_P (ref))
+    return;
+
+  if (INSN_P (insn))
+    base_ptr = &PATTERN (insn);
+  else
+    base_ptr = &insn;
+  for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
 }
+\f
+static rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT,
+                                int, bool);
 
-/* Try machine-dependent ways of modifying an illegitimate address
-   to be legitimate.  If we find one, return the new, valid address.  */
+/* Internal routine for alpha_emit_set_const to check for N or below insns.
+   If NO_OUTPUT is true, then we only check to see if N insns are possible,
+   and return pc_rtx if successful.  */
 
-rtx
-alpha_legitimize_address (rtx x, rtx scratch,
-                         enum machine_mode mode ATTRIBUTE_UNUSED)
+static rtx
+alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
+                       HOST_WIDE_INT c, int n, bool no_output)
 {
-  HOST_WIDE_INT addend;
+  HOST_WIDE_INT new;
+  int i, bits;
+  /* Use a pseudo if highly optimizing and still generating RTL.  */
+  rtx subtarget
+    = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target);
+  rtx temp, insn;
 
-  /* If the address is (plus reg const_int) and the CONST_INT is not a
-     valid offset, compute the high part of the constant and add it to
-     the register.  Then our address is (plus temp low-part-const).  */
-  if (GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 0)) == REG
-      && GET_CODE (XEXP (x, 1)) == CONST_INT
-      && ! CONSTANT_ADDRESS_P (XEXP (x, 1)))
-    {
-      addend = INTVAL (XEXP (x, 1));
-      x = XEXP (x, 0);
-      goto split_addend;
-    }
+  /* 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.  */
 
-  /* If the address is (const (plus FOO const_int)), find the low-order
-     part of the CONST_INT.  Then load FOO plus any high-order part of the
-     CONST_INT into a register.  Our address is (plus reg low-part-const).
-     This is done to reduce the number of GOT entries.  */
-  if (!no_new_pseudos
-      && GET_CODE (x) == CONST
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+  if (HOST_BITS_PER_WIDE_INT != 64
+      || c >> 31 == -1 || c >> 31 == 0)
     {
-      addend = INTVAL (XEXP (XEXP (x, 0), 1));
-      x = force_reg (Pmode, XEXP (XEXP (x, 0), 0));
-      goto split_addend;
-    }
+      HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000;
+      HOST_WIDE_INT tmp1 = c - low;
+      HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000;
+      HOST_WIDE_INT extra = 0;
 
-  /* If we have a (plus reg const), emit the load as in (2), then add
-     the two registers, and finally generate (plus reg low-part-const) as
-     our address.  */
-  if (!no_new_pseudos
-      && GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 0)) == REG
-      && GET_CODE (XEXP (x, 1)) == CONST
-      && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT)
-    {
-      addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1));
-      x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0),
-                              XEXP (XEXP (XEXP (x, 1), 0), 0),
-                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
-      goto split_addend;
-    }
-
-  /* If this is a local symbol, split the address into HIGH/LO_SUM parts.  */
-  if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode))
-    {
-      rtx r0, r16, eqv, tga, tp, insn, dest, seq;
+      /* If HIGH will be interpreted as negative but the constant is
+        positive, we must adjust it to do two ldha insns.  */
 
-      switch (tls_symbolic_operand_type (x))
+      if ((high & 0x8000) != 0 && c >= 0)
        {
-       case TLS_MODEL_GLOBAL_DYNAMIC:
-         start_sequence ();
-
-         r0 = gen_rtx_REG (Pmode, 0);
-         r16 = gen_rtx_REG (Pmode, 16);
-         tga = get_tls_get_addr ();
-         dest = gen_reg_rtx (Pmode);
-         seq = GEN_INT (alpha_next_sequence_number++);
-         
-         emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
-         insn = gen_call_value_osf_tlsgd (r0, tga, seq);
-         insn = emit_call_insn (insn);
-         CONST_OR_PURE_CALL_P (insn) = 1;
-         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
-
-          insn = get_insns ();
-         end_sequence ();
-
-         emit_libcall_block (insn, dest, r0, x);
-         return dest;
-
-       case TLS_MODEL_LOCAL_DYNAMIC:
-         start_sequence ();
-
-         r0 = gen_rtx_REG (Pmode, 0);
-         r16 = gen_rtx_REG (Pmode, 16);
-         tga = get_tls_get_addr ();
-         scratch = gen_reg_rtx (Pmode);
-         seq = GEN_INT (alpha_next_sequence_number++);
-
-         emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
-         insn = gen_call_value_osf_tlsldm (r0, tga, seq);
-         insn = emit_call_insn (insn);
-         CONST_OR_PURE_CALL_P (insn) = 1;
-         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
-
-          insn = get_insns ();
-         end_sequence ();
-
-         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
-                               UNSPEC_TLSLDM_CALL);
-         emit_libcall_block (insn, scratch, r0, eqv);
+         extra = 0x4000;
+         tmp1 -= 0x40000000;
+         high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000);
+       }
 
-         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL);
-         eqv = gen_rtx_CONST (Pmode, eqv);
+      if (c == low || (low == 0 && extra == 0))
+       {
+         /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode)
+            but that meant that we can't handle INT_MIN on 32-bit machines
+            (like NT/Alpha), because we recurse indefinitely through
+            emit_move_insn to gen_movdi.  So instead, since we know exactly
+            what we want, create it explicitly.  */
 
-         if (alpha_tls_size == 64)
+         if (no_output)
+           return pc_rtx;
+         if (target == NULL)
+           target = gen_reg_rtx (mode);
+         emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
+         return target;
+       }
+      else if (n >= 2 + (extra != 0))
+       {
+         if (no_output)
+           return pc_rtx;
+         if (no_new_pseudos)
            {
-             dest = gen_reg_rtx (Pmode);
-             emit_insn (gen_rtx_SET (VOIDmode, dest, eqv));
-             emit_insn (gen_adddi3 (dest, dest, scratch));
-             return dest;
+             emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16)));
+             temp = target;
            }
-         if (alpha_tls_size == 32)
+         else
+           temp = copy_to_suggested_reg (GEN_INT (high << 16),
+                                         subtarget, mode);
+
+         /* As of 2002-02-23, addsi3 is only available when not optimizing.
+            This means that if we go through expand_binop, we'll try to
+            generate extensions, etc, which will require new pseudos, which
+            will fail during some split phases.  The SImode add patterns
+            still exist, but are not named.  So build the insns by hand.  */
+
+         if (extra != 0)
            {
-             insn = gen_rtx_HIGH (Pmode, eqv);
-             insn = gen_rtx_PLUS (Pmode, scratch, insn);
-             scratch = gen_reg_rtx (Pmode);
-             emit_insn (gen_rtx_SET (VOIDmode, scratch, insn));
+             if (! subtarget)
+               subtarget = gen_reg_rtx (mode);
+             insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16));
+             insn = gen_rtx_SET (VOIDmode, subtarget, insn);
+             emit_insn (insn);
+             temp = subtarget;
            }
-         return gen_rtx_LO_SUM (Pmode, scratch, eqv);
 
-       case TLS_MODEL_INITIAL_EXEC:
-         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
-         eqv = gen_rtx_CONST (Pmode, eqv);
-         tp = gen_reg_rtx (Pmode);
-         scratch = gen_reg_rtx (Pmode);
-         dest = gen_reg_rtx (Pmode);
+         if (target == NULL)
+           target = gen_reg_rtx (mode);
+         insn = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+         insn = gen_rtx_SET (VOIDmode, target, insn);
+         emit_insn (insn);
+         return target;
+       }
+    }
 
-         emit_insn (gen_load_tp (tp));
-         emit_insn (gen_rtx_SET (VOIDmode, scratch, eqv));
-         emit_insn (gen_adddi3 (dest, tp, scratch));
-         return dest;
+  /* 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.  */
 
-       case TLS_MODEL_LOCAL_EXEC:
-         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
-         eqv = gen_rtx_CONST (Pmode, eqv);
-         tp = gen_reg_rtx (Pmode);
+  if (n == 1 || (mode == SImode && no_new_pseudos))
+    return 0;
 
-         emit_insn (gen_load_tp (tp));
-         if (alpha_tls_size == 32)
+  /* 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, see if minus some low bits, we've an easy load of
+        high bits.  */
+
+      new = ((c & 0xffff) ^ 0x8000) - 0x8000;
+      if (new != 0)
+       {
+          temp = alpha_emit_set_const (subtarget, mode, c - new, i, no_output);
+         if (temp)
            {
-             insn = gen_rtx_HIGH (Pmode, eqv);
-             insn = gen_rtx_PLUS (Pmode, tp, insn);
-             tp = gen_reg_rtx (Pmode);
-             emit_insn (gen_rtx_SET (VOIDmode, tp, insn));
+             if (no_output)
+               return temp;
+             return expand_binop (mode, add_optab, temp, GEN_INT (new),
+                                  target, 0, OPTAB_WIDEN);
            }
-         return gen_rtx_LO_SUM (Pmode, tp, eqv);
        }
 
-      if (local_symbolic_operand (x, Pmode))
+      /* Next try complementing.  */
+      temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output);
+      if (temp)
        {
-         if (small_symbolic_operand (x, Pmode))
-           return x;
-         else
-           {
-             if (!no_new_pseudos)
-               scratch = gen_reg_rtx (Pmode);
-             emit_insn (gen_rtx_SET (VOIDmode, scratch,
-                                     gen_rtx_HIGH (Pmode, x)));
-             return gen_rtx_LO_SUM (Pmode, scratch, x);
-           }
+         if (no_output)
+           return temp;
+         return expand_unop (mode, one_cmpl_optab, temp, target, 0);
        }
-    }
 
-  return NULL;
+      /* 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
+        the constant.  To try to increase the chance of having the same
+        constant in more than one insn, start at the highest number of
+        bits to shift, but try all possibilities in case a ZAPNOT will
+        be useful.  */
 
- split_addend:
-  {
-    HOST_WIDE_INT low, high;
+      bits = exact_log2 (c & -c);
+      if (bits > 0)
+       for (; bits > 0; bits--)
+         {
+           new = c >> bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp && c < 0)
+             {
+               new = (unsigned HOST_WIDE_INT)c >> bits;
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, ashl_optab, temp, GEN_INT (bits),
+                                    target, 0, OPTAB_WIDEN);
+             }
+         }
 
-    low = ((addend & 0xffff) ^ 0x8000) - 0x8000;
-    addend -= low;
-    high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000;
-    addend -= high;
+      /* Now try high-order zero bits.  Here we try the shifted-in bits as
+        all zero and all ones.  Be careful to avoid shifting outside the
+        mode and to avoid shifting outside the host wide int size.  */
+      /* On narrow hosts, don't shift a 1 into the high bit, since we'll
+        confuse the recursive call and set all of the high 32 bits.  */
 
-    if (addend)
-      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
-                              (no_new_pseudos ? scratch : NULL_RTX),
-                              1, OPTAB_LIB_WIDEN);
-    if (high)
-      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high),
-                              (no_new_pseudos ? scratch : NULL_RTX),
-                              1, OPTAB_LIB_WIDEN);
+      bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+             - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64));
+      if (bits > 0)
+       for (; bits > 0; bits--)
+         {
+           new = c << bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp)
+             {
+               new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, lshr_optab, temp, GEN_INT (bits),
+                                    target, 1, OPTAB_WIDEN);
+             }
+         }
 
-    return plus_constant (x, low);
-  }
-}
+      /* Now try high-order 1 bits.  We get that with a sign-extension.
+        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.  */
 
-/* We do not allow indirect calls to be optimized into sibling calls, nor
-   can we allow a call to a function with a different GP to be optimized
-   into a sibcall.  */
+      bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+             - floor_log2 (~ c) - 2);
+      if (bits > 0)
+       for (; bits > 0; bits--)
+         {
+           new = c << bits;
+           temp = alpha_emit_set_const (subtarget, mode, new, i, no_output);
+           if (!temp)
+             {
+               new = (c << bits) | (((HOST_WIDE_INT) 1 << bits) - 1);
+               temp = alpha_emit_set_const (subtarget, mode, new,
+                                            i, no_output);
+             }
+           if (temp)
+             {
+               if (no_output)
+                 return temp;
+               return expand_binop (mode, ashr_optab, temp, GEN_INT (bits),
+                                    target, 0, OPTAB_WIDEN);
+             }
+         }
+    }
 
-static bool
-alpha_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
-{
-  /* Can't do indirect tail calls, since we don't know if the target
-     uses the same GP.  */
-  if (!decl)
-    return false;
+#if HOST_BITS_PER_WIDE_INT == 64
+  /* Finally, 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.  */
 
-  /* Otherwise, we can make a tail call if the target function shares
-     the same GP.  */
-  return decl_has_samegp (decl);
-}
+  new = c;
+  for (i = 0; i < 64; i += 8)
+    if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0)
+      new |= (HOST_WIDE_INT) 0xff << i;
 
-/* For TARGET_EXPLICIT_RELOCS, we don't obfuscate a SYMBOL_REF to a
-   small symbolic operand until after reload.  At which point we need
-   to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref))
-   so that sched2 has the proper dependency information.  */
+  /* We are only called for SImode and DImode.  If this is SImode, ensure that
+     we are sign extended to a full word.  */
 
-static int
-some_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
-{
-  rtx x = *px;
+  if (mode == SImode)
+    new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
 
-  /* Don't re-split.  */
-  if (GET_CODE (x) == LO_SUM)
-    return -1;
+  if (new != c)
+    {
+      temp = alpha_emit_set_const (subtarget, mode, new, n - 1, no_output);
+      if (temp)
+       {
+         if (no_output)
+           return temp;
+         return expand_binop (mode, and_optab, temp, GEN_INT (c | ~ new),
+                              target, 0, OPTAB_WIDEN);
+       }
+    }
+#endif
 
-  return small_symbolic_operand (x, Pmode) != 0;
+  return 0;
 }
 
-int
-some_small_symbolic_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return for_each_rtx (&x, some_small_symbolic_operand_1, NULL);
-}
+/* Try to output insns to set TARGET equal to the constant C if it can be
+   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.  */
 
-static int
-split_small_symbolic_operand_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
+static rtx
+alpha_emit_set_const (rtx target, enum machine_mode mode,
+                     HOST_WIDE_INT c, int n, bool no_output)
 {
-  rtx x = *px;
+  enum machine_mode orig_mode = mode;
+  rtx orig_target = target;
+  rtx result = 0;
+  int i;
 
-  /* Don't re-split.  */
-  if (GET_CODE (x) == LO_SUM)
-    return -1;
+  /* If we can't make any pseudos, TARGET is an SImode hard register, we
+     can't load this constant in one insn, do this in DImode.  */
+  if (no_new_pseudos && mode == SImode
+      && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER)
+    {
+      result = alpha_emit_set_const_1 (target, mode, c, 1, no_output);
+      if (result)
+       return result;
 
-  if (small_symbolic_operand (x, Pmode))
+      target = no_output ? NULL : gen_lowpart (DImode, target);
+      mode = DImode;
+    }
+  else if (mode == V8QImode || mode == V4HImode || mode == V2SImode)
     {
-      x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
-      *px = x;
-      return -1;
+      target = no_output ? NULL : gen_lowpart (DImode, target);
+      mode = DImode;
     }
 
-  return 0;
-}
-
-rtx
-split_small_symbolic_operand (rtx x)
-{
-  x = copy_insn (x);
-  for_each_rtx (&x, split_small_symbolic_operand_1, NULL);
-  return x;
-}
+  /* Try 1 insn, then 2, then up to N.  */
+  for (i = 1; i <= n; i++)
+    {
+      result = alpha_emit_set_const_1 (target, mode, c, i, no_output);
+      if (result)
+       {
+         rtx insn, set;
 
-/* Indicate that INSN cannot be duplicated.  This is true for any insn
-   that we've marked with gpdisp relocs, since those have to stay in
-   1-1 correspondence with one another.
+         if (no_output)
+           return result;
 
-   Technically we could copy them if we could set up a mapping from one
-   sequence number to another, across the set of insns to be duplicated.
-   This seems overly complicated and error-prone since interblock motion
-   from sched-ebb could move one of the pair of insns to a different block.
+         insn = get_last_insn ();
+         set = single_set (insn);
+         if (! CONSTANT_P (SET_SRC (set)))
+           set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
+         break;
+       }
+    }
 
-   Also cannot allow jsr insns to be duplicated.  If they throw exceptions,
-   then they'll be in a different block from their ldgp.  Which could lead
-   the bb reorder code to think that it would be ok to copy just the block
-   containing the call and branch to the block containing the ldgp.  */
+  /* Allow for the case where we changed the mode of TARGET.  */
+  if (result)
+    {
+      if (result == target)
+       result = orig_target;
+      else if (mode != orig_mode)
+       result = gen_lowpart (orig_mode, result);
+    }
 
-static bool
-alpha_cannot_copy_insn_p (rtx insn)
-{
-  if (!reload_completed || !TARGET_EXPLICIT_RELOCS)
-    return false;
-  if (recog_memoized (insn) >= 0)
-    return get_attr_cannot_copy (insn);
-  else
-    return false;
+  return result;
 }
 
-  
-/* Try a machine-dependent way of reloading an illegitimate address
-   operand.  If we find one, push the reload and return the new rtx.  */
-   
-rtx
-alpha_legitimize_reload_address (rtx x,
-                                enum machine_mode mode ATTRIBUTE_UNUSED,
-                                int opnum, int type,
-                                int ind_levels ATTRIBUTE_UNUSED)
+/* 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.  */
+
+static rtx
+alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
 {
-  /* We must recognize output that we have already generated ourselves.  */
-  if (GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 0)) == PLUS
-      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
-      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
-      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+  HOST_WIDE_INT d1, d2, d3, d4;
+
+  /* Decompose the entire word */
+#if HOST_BITS_PER_WIDE_INT >= 64
+  gcc_assert (c2 == -(c1 < 0));
+  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d1;
+  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  c1 = (c1 - d2) >> 32;
+  d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d3;
+  d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  gcc_assert (c1 == d4);
+#else
+  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
+  c1 -= d1;
+  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  gcc_assert (c1 == d2);
+  c2 += (d2 < 0);
+  d3 = ((c2 & 0xffff) ^ 0x8000) - 0x8000;
+  c2 -= d3;
+  d4 = ((c2 & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  gcc_assert (c2 == d4);
+#endif
+
+  /* Construct the high word */
+  if (d4)
     {
-      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                  opnum, type);
-      return x;
+      emit_move_insn (target, GEN_INT (d4));
+      if (d3)
+       emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3)));
     }
+  else
+    emit_move_insn (target, GEN_INT (d3));
 
-  /* We wish to handle large displacements off a base register by
-     splitting the addend across an ldah and the mem insn.  This
-     cuts number of extra insns needed from 3 to 1.  */
-  if (GET_CODE (x) == PLUS
-      && GET_CODE (XEXP (x, 0)) == REG
-      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
-      && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0)))
-      && GET_CODE (XEXP (x, 1)) == CONST_INT)
-    {
-      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
-      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
-      HOST_WIDE_INT high
-       = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  /* Shift it into place */
+  emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32)));
 
-      /* Check for 32-bit overflow.  */
-      if (high + low != val)
-       return NULL_RTX;
+  /* Add in the low bits.  */
+  if (d2)
+    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2)));
+  if (d1)
+    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1)));
 
-      /* Reload the high part into a base reg; leave the low part
-        in the mem directly.  */
-      x = gen_rtx_PLUS (GET_MODE (x),
-                       gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
-                                     GEN_INT (high)),
-                       GEN_INT (low));
+  return target;
+}
 
-      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
-                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
-                  opnum, type);
-      return x;
+/* Given an integral CONST_INT, CONST_DOUBLE, or CONST_VECTOR, return 
+   the low 64 bits.  */
+
+static void
+alpha_extract_integer (rtx x, HOST_WIDE_INT *p0, HOST_WIDE_INT *p1)
+{
+  HOST_WIDE_INT i0, i1;
+
+  if (GET_CODE (x) == CONST_VECTOR)
+    x = simplify_subreg (DImode, x, GET_MODE (x), 0);
+
+
+  if (GET_CODE (x) == CONST_INT)
+    {
+      i0 = INTVAL (x);
+      i1 = -(i0 < 0);
+    }
+  else if (HOST_BITS_PER_WIDE_INT >= 64)
+    {
+      i0 = CONST_DOUBLE_LOW (x);
+      i1 = -(i0 < 0);
+    }
+  else
+    {
+      i0 = CONST_DOUBLE_LOW (x);
+      i1 = CONST_DOUBLE_HIGH (x);
     }
 
-  return NULL_RTX;
+  *p0 = i0;
+  *p1 = i1;
 }
-\f
-/* Compute a (partial) cost for rtx X.  Return true if the complete
-   cost has been computed, and false if subexpressions should be
-   scanned.  In either case, *TOTAL contains the cost result.  */
 
-static bool
-alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
+/* Implement LEGITIMATE_CONSTANT_P.  This is all constants for which we
+   are willing to load the value into a register via a move pattern.
+   Normally this is all symbolic constants, integral constants that
+   take three or fewer instructions, and floating-point zero.  */
+
+bool
+alpha_legitimate_constant_p (rtx x)
 {
   enum machine_mode mode = GET_MODE (x);
-  bool float_mode_p = FLOAT_MODE_P (mode);
-  const struct alpha_rtx_cost_data *cost_data;
+  HOST_WIDE_INT i0, i1;
 
-  if (optimize_size)
-    cost_data = &alpha_rtx_cost_size;
-  else
-    cost_data = &alpha_rtx_cost_data[alpha_cpu];
-
-  switch (code)
+  switch (GET_CODE (x))
     {
-    case CONST_INT:
-      /* If this is an 8-bit constant, return zero since it can be used
-        nearly anywhere with no cost.  If it is a valid operand for an
-        ADD or AND, likewise return 0 if we know it will be used in that
-        context.  Otherwise, return 2 since it might be used there later.
-        All other constants take at least two insns.  */
-      if (INTVAL (x) >= 0 && INTVAL (x) < 256)
-       {
-         *total = 0;
-         return true;
-       }
-      /* FALLTHRU */
+    case CONST:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case HIGH:
+      return true;
 
     case CONST_DOUBLE:
       if (x == CONST0_RTX (mode))
-       *total = 0;
-      else if ((outer_code == PLUS && add_operand (x, VOIDmode))
-              || (outer_code == AND && and_operand (x, VOIDmode)))
-       *total = 0;
-      else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
-       *total = 2;
-      else
-       *total = COSTS_N_INSNS (2);
+       return true;
+      if (FLOAT_MODE_P (mode))
+       return false;
+      goto do_integer;
+
+    case CONST_VECTOR:
+      if (x == CONST0_RTX (mode))
+       return true;
+      if (GET_MODE_CLASS (mode) != MODE_VECTOR_INT)
+       return false;
+      if (GET_MODE_SIZE (mode) != 8)
+       return false;
+      goto do_integer;
+
+    case CONST_INT:
+    do_integer:
+      if (TARGET_BUILD_CONSTANTS)
+       return true;
+      alpha_extract_integer (x, &i0, &i1);
+      if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == (-i0 < 0))
+        return alpha_emit_set_const_1 (x, mode, i0, 3, true) != NULL;
+      return false;
+
+    default:
+      return false;
+    }
+}
+
+/* Operand 1 is known to be a constant, and should require more than one
+   instruction to load.  Emit that multi-part load.  */
+
+bool
+alpha_split_const_mov (enum machine_mode mode, rtx *operands)
+{
+  HOST_WIDE_INT i0, i1;
+  rtx temp = NULL_RTX;
+
+  alpha_extract_integer (operands[1], &i0, &i1);
+
+  if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
+    temp = alpha_emit_set_const (operands[0], mode, i0, 3, false);
+
+  if (!temp && TARGET_BUILD_CONSTANTS)
+    temp = alpha_emit_set_long_const (operands[0], i0, i1);
+
+  if (temp)
+    {
+      if (!rtx_equal_p (operands[0], temp))
+       emit_move_insn (operands[0], temp);
       return true;
-      
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode))
-       *total = COSTS_N_INSNS (outer_code != MEM);
-      else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode))
-       *total = COSTS_N_INSNS (1 + (outer_code != MEM));
-      else if (tls_symbolic_operand_type (x))
-       /* Estimate of cost for call_pal rduniq.  */
-       /* ??? How many insns do we emit here?  More than one...  */
-       *total = COSTS_N_INSNS (15);
-      else
-       /* Otherwise we do a load from the GOT.  */
-       *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
-      return true;
-    
-    case PLUS:
-    case MINUS:
-      if (float_mode_p)
-       *total = cost_data->fp_add;
-      else if (GET_CODE (XEXP (x, 0)) == MULT
-              && const48_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
-       {
-         *total = (rtx_cost (XEXP (XEXP (x, 0), 0), outer_code)
-                   + rtx_cost (XEXP (x, 1), outer_code) + COSTS_N_INSNS (1));
-         return true;
-       }
-      return false;
-
-    case MULT:
-      if (float_mode_p)
-       *total = cost_data->fp_mult;
-      else if (mode == DImode)
-       *total = cost_data->int_mult_di;
-      else
-       *total = cost_data->int_mult_si;
-      return false;
-
-    case ASHIFT:
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT
-         && INTVAL (XEXP (x, 1)) <= 3)
-       {
-         *total = COSTS_N_INSNS (1);
-         return false;
-       }
-      /* FALLTHRU */
-
-    case ASHIFTRT:
-    case LSHIFTRT:
-      *total = cost_data->int_shift;
-      return false;
+    }
 
-    case IF_THEN_ELSE:
-      if (float_mode_p)
-        *total = cost_data->fp_add;
-      else
-        *total = cost_data->int_cmov;
-      return false;
+  return false;
+}
 
-    case DIV:
-    case UDIV:
-    case MOD:
-    case UMOD:
-      if (!float_mode_p)
-       *total = cost_data->int_div;
-      else if (mode == SFmode)
-        *total = cost_data->fp_div_sf;
-      else
-        *total = cost_data->fp_div_df;
-      return false;
+/* Expand a move instruction; return true if all work is done.
+   We don't handle non-bwx subword loads here.  */
 
-    case MEM:
-      *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
-      return true;
+bool
+alpha_expand_mov (enum machine_mode mode, rtx *operands)
+{
+  /* If the output is not a register, the input must be.  */
+  if (GET_CODE (operands[0]) == MEM
+      && ! reg_or_0_operand (operands[1], mode))
+    operands[1] = force_reg (mode, operands[1]);
 
-    case NEG:
-      if (! float_mode_p)
-       {
-         *total = COSTS_N_INSNS (1);
-         return false;
-       }
-      /* FALLTHRU */
+  /* Allow legitimize_address to perform some simplifications.  */
+  if (mode == Pmode && symbolic_operand (operands[1], mode))
+    {
+      rtx tmp;
 
-    case ABS:
-      if (! float_mode_p)
+      tmp = alpha_legitimize_address (operands[1], operands[0], mode);
+      if (tmp)
        {
-         *total = COSTS_N_INSNS (1) + cost_data->int_cmov;
+         if (tmp == operands[0])
+           return true;
+         operands[1] = tmp;
          return false;
        }
-      /* FALLTHRU */
-
-    case FLOAT:
-    case UNSIGNED_FLOAT:
-    case FIX:
-    case UNSIGNED_FIX:
-    case FLOAT_EXTEND:
-    case FLOAT_TRUNCATE:
-      *total = cost_data->fp_add;
-      return false;
-
-    default:
-      return false;
     }
-}
-\f
-/* REF is an alignable memory location.  Place an aligned SImode
-   reference into *PALIGNED_MEM and the number of bits to shift into
-   *PBITNUM.  SCRATCH is a free register for use in reloading out
-   of range stack slots.  */
 
-void
-get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum)
-{
-  rtx base;
-  HOST_WIDE_INT offset = 0;
-
-  if (GET_CODE (ref) != MEM)
-    abort ();
+  /* Early out for non-constants and valid constants.  */
+  if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode))
+    return false;
 
-  if (reload_in_progress
-      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+  /* Split large integers.  */
+  if (GET_CODE (operands[1]) == CONST_INT
+      || GET_CODE (operands[1]) == CONST_DOUBLE
+      || GET_CODE (operands[1]) == CONST_VECTOR)
     {
-      base = find_replacement (&XEXP (ref, 0));
-
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
+      if (alpha_split_const_mov (mode, operands))
+       return true;
     }
-  else
+
+  /* Otherwise we've nothing left but to drop the thing to memory.  */
+  operands[1] = force_const_mem (mode, operands[1]);
+  if (reload_in_progress)
     {
-      base = XEXP (ref, 0);
+      emit_move_insn (operands[0], XEXP (operands[1], 0));
+      operands[1] = copy_rtx (operands[1]);
+      XEXP (operands[1], 0) = operands[0];
     }
-
-  if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
-
-  *paligned_mem
-    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
-
-  if (WORDS_BIG_ENDIAN)
-    *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
-                             + (offset & 3) * 8));
   else
-    *pbitnum = GEN_INT ((offset & 3) * 8);
+    operands[1] = validize_mem (operands[1]);
+  return false;
 }
 
-/* Similar, but just get the address.  Handle the two reload cases.  
-   Add EXTRA_OFFSET to the address we return.  */
+/* Expand a non-bwx QImode or HImode move instruction;
+   return true if all work is done.  */
 
-rtx
-get_unaligned_address (rtx ref, int extra_offset)
+bool
+alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
 {
-  rtx base;
-  HOST_WIDE_INT offset = 0;
-
-  if (GET_CODE (ref) != MEM)
-    abort ();
+  /* If the output is not a register, the input must be.  */
+  if (GET_CODE (operands[0]) == MEM)
+    operands[1] = force_reg (mode, operands[1]);
 
-  if (reload_in_progress
-      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
-    {
-      base = find_replacement (&XEXP (ref, 0));
+  /* Handle four memory cases, unaligned and aligned for either the input
+     or the output.  The only case where we can be called during reload is
+     for aligned loads; all other cases require temporaries.  */
 
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
-    }
-  else
+  if (GET_CODE (operands[1]) == MEM
+      || (GET_CODE (operands[1]) == SUBREG
+         && GET_CODE (SUBREG_REG (operands[1])) == MEM)
+      || (reload_in_progress && GET_CODE (operands[1]) == REG
+         && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
+      || (reload_in_progress && GET_CODE (operands[1]) == SUBREG
+         && GET_CODE (SUBREG_REG (operands[1])) == REG
+         && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER))
     {
-      base = XEXP (ref, 0);
-    }
+      if (aligned_memory_operand (operands[1], mode))
+       {
+         if (reload_in_progress)
+           {
+             emit_insn ((mode == QImode
+                         ? gen_reload_inqi_help
+                         : gen_reload_inhi_help)
+                        (operands[0], operands[1],
+                         gen_rtx_REG (SImode, REGNO (operands[0]))));
+           }
+         else
+           {
+             rtx aligned_mem, bitnum;
+             rtx scratch = gen_reg_rtx (SImode);
+             rtx subtarget;
+             bool copyout;
 
-  if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+             get_aligned_mem (operands[1], &aligned_mem, &bitnum);
 
-  return plus_constant (base, offset + extra_offset);
-}
+             subtarget = operands[0];
+             if (GET_CODE (subtarget) == REG)
+               subtarget = gen_lowpart (DImode, subtarget), copyout = false;
+             else
+               subtarget = gen_reg_rtx (DImode), copyout = true;
 
-/* On the Alpha, all (non-symbolic) constants except zero go into
-   a floating-point register via memory.  Note that we cannot 
-   return anything that is not a subset of CLASS, and that some
-   symbolic constants cannot be dropped to memory.  */
+             emit_insn ((mode == QImode
+                         ? gen_aligned_loadqi
+                         : gen_aligned_loadhi)
+                        (subtarget, aligned_mem, bitnum, scratch));
 
-enum reg_class
-alpha_preferred_reload_class(rtx x, enum reg_class class)
-{
-  /* Zero is present in any register class.  */
-  if (x == CONST0_RTX (GET_MODE (x)))
-    return class;
+             if (copyout)
+               emit_move_insn (operands[0], gen_lowpart (mode, subtarget));
+           }
+       }
+      else
+       {
+         /* Don't pass these as parameters since that makes the generated
+            code depend on parameter evaluation order which will cause
+            bootstrap failures.  */
 
-  /* These sorts of constants we can easily drop to memory.  */
-  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
-    {
-      if (class == FLOAT_REGS)
-       return NO_REGS;
-      if (class == ALL_REGS)
-       return GENERAL_REGS;
-      return class;
-    }
+         rtx temp1, temp2, seq, subtarget;
+         bool copyout;
 
-  /* All other kinds of constants should not (and in the case of HIGH
-     cannot) be dropped to memory -- instead we use a GENERAL_REGS
-     secondary reload.  */
-  if (CONSTANT_P (x))
-    return (class == ALL_REGS ? GENERAL_REGS : class);
+         temp1 = gen_reg_rtx (DImode);
+         temp2 = gen_reg_rtx (DImode);
 
-  return class;
-}
-
-/* Loading and storing HImode or QImode values to and from memory
-   usually requires a scratch register.  The exceptions are loading
-   QImode and HImode from an aligned address to a general register
-   unless byte instructions are permitted. 
-
-   We also cannot load an unaligned address or a paradoxical SUBREG
-   into an FP register. 
+         subtarget = operands[0];
+         if (GET_CODE (subtarget) == REG)
+           subtarget = gen_lowpart (DImode, subtarget), copyout = false;
+         else
+           subtarget = gen_reg_rtx (DImode), copyout = true;
 
-   We also cannot do integral arithmetic into FP regs, as might result
-   from register elimination into a DImode fp register.  */
+         seq = ((mode == QImode
+                 ? gen_unaligned_loadqi
+                 : gen_unaligned_loadhi)
+                (subtarget, get_unaligned_address (operands[1], 0),
+                 temp1, temp2));
+         alpha_set_memflags (seq, operands[1]);
+         emit_insn (seq);
 
-enum reg_class
-secondary_reload_class (enum reg_class class, enum machine_mode mode,
-                       rtx x, int in)
-{
-  if ((mode == QImode || mode == HImode) && ! TARGET_BWX)
-    {
-      if (GET_CODE (x) == MEM
-         || (GET_CODE (x) == REG && REGNO (x) >= FIRST_PSEUDO_REGISTER)
-         || (GET_CODE (x) == SUBREG
-             && (GET_CODE (SUBREG_REG (x)) == MEM
-                 || (GET_CODE (SUBREG_REG (x)) == REG
-                     && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER))))
-       {
-         if (!in || !aligned_memory_operand(x, mode))
-           return GENERAL_REGS;
+         if (copyout)
+           emit_move_insn (operands[0], gen_lowpart (mode, subtarget));
        }
+      return true;
     }
 
-  if (class == FLOAT_REGS)
+  if (GET_CODE (operands[0]) == MEM
+      || (GET_CODE (operands[0]) == SUBREG
+         && GET_CODE (SUBREG_REG (operands[0])) == MEM)
+      || (reload_in_progress && GET_CODE (operands[0]) == REG
+         && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
+      || (reload_in_progress && GET_CODE (operands[0]) == SUBREG
+         && GET_CODE (SUBREG_REG (operands[0])) == REG
+         && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
     {
-      if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND)
-       return GENERAL_REGS;
+      if (aligned_memory_operand (operands[0], mode))
+       {
+         rtx aligned_mem, bitnum;
+         rtx temp1 = gen_reg_rtx (SImode);
+         rtx temp2 = gen_reg_rtx (SImode);
 
-      if (GET_CODE (x) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (x))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-       return GENERAL_REGS;
+         get_aligned_mem (operands[0], &aligned_mem, &bitnum);
 
-      if (in && INTEGRAL_MODE_P (mode)
-         && ! (memory_operand (x, mode) || x == const0_rtx))
-       return GENERAL_REGS;
+         emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
+                                       temp1, temp2));
+       }
+      else
+       {
+         rtx temp1 = gen_reg_rtx (DImode);
+         rtx temp2 = gen_reg_rtx (DImode);
+         rtx temp3 = gen_reg_rtx (DImode);
+         rtx seq = ((mode == QImode
+                     ? gen_unaligned_storeqi
+                     : gen_unaligned_storehi)
+                    (get_unaligned_address (operands[0], 0),
+                     operands[1], temp1, temp2, temp3));
+
+         alpha_set_memflags (seq, operands[0]);
+         emit_insn (seq);
+       }
+      return true;
     }
 
-  return NO_REGS;
+  return false;
 }
-\f
-/* Subfunction of the following function.  Update the flags of any MEM
-   found in part of X.  */
 
-static void
-alpha_set_memflags_1 (rtx x, int in_struct_p, int volatile_p, int unchanging_p)
+/* Implement the movmisalign patterns.  One of the operands is a memory
+   that is not naturally aligned.  Emit instructions to load it.  */
+
+void
+alpha_expand_movmisalign (enum machine_mode mode, rtx *operands)
 {
-  int i;
+  /* Honor misaligned loads, for those we promised to do so.  */
+  if (MEM_P (operands[1]))
+    {
+      rtx tmp;
 
-  switch (GET_CODE (x))
+      if (register_operand (operands[0], mode))
+       tmp = operands[0];
+      else
+       tmp = gen_reg_rtx (mode);
+
+      alpha_expand_unaligned_load (tmp, operands[1], 8, 0, 0);
+      if (tmp != operands[0])
+       emit_move_insn (operands[0], tmp);
+    }
+  else if (MEM_P (operands[0]))
     {
-    case SEQUENCE:
-      abort ();
+      if (!reg_or_0_operand (operands[1], mode))
+       operands[1] = force_reg (mode, operands[1]);
+      alpha_expand_unaligned_store (operands[0], operands[1], 8, 0);
+    }
+  else
+    gcc_unreachable ();
+}
 
-    case PARALLEL:
-      for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
-       alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p,
-                             unchanging_p);
-      break;
+/* Generate an unsigned DImode to FP conversion.  This is the same code
+   optabs would emit if we didn't have TFmode patterns.
 
-    case INSN:
-      alpha_set_memflags_1 (PATTERN (x), in_struct_p, volatile_p,
-                           unchanging_p);
-      break;
+   For SFmode, this is the only construction I've found that can pass
+   gcc.c-torture/execute/ieee/rbug.c.  No scenario that uses DFmode
+   intermediates will work, because you'll get intermediate rounding
+   that ruins the end result.  Some of this could be fixed by turning
+   on round-to-positive-infinity, but that requires diddling the fpsr,
+   which kills performance.  I tried turning this around and converting
+   to a negative number, so that I could turn on /m, but either I did
+   it wrong or there's something else cause I wound up with the exact
+   same single-bit error.  There is a branch-less form of this same code:
 
-    case SET:
-      alpha_set_memflags_1 (SET_DEST (x), in_struct_p, volatile_p,
-                           unchanging_p);
-      alpha_set_memflags_1 (SET_SRC (x), in_struct_p, volatile_p,
-                           unchanging_p);
-      break;
+       srl     $16,1,$1
+       and     $16,1,$2
+       cmplt   $16,0,$3
+       or      $1,$2,$2
+       cmovge  $16,$16,$2
+       itoft   $3,$f10
+       itoft   $2,$f11
+       cvtqs   $f11,$f11
+       adds    $f11,$f11,$f0
+       fcmoveq $f10,$f11,$f0
 
-    case MEM:
-      MEM_IN_STRUCT_P (x) = in_struct_p;
-      MEM_VOLATILE_P (x) = volatile_p;
-      RTX_UNCHANGING_P (x) = unchanging_p;
-      /* Sadly, we cannot use alias sets because the extra aliasing
-        produced by the AND interferes.  Given that two-byte quantities
-        are the only thing we would be able to differentiate anyway,
-        there does not seem to be any point in convoluting the early
-        out of the alias check.  */
-      break;
+   I'm not using it because it's the same number of instructions as
+   this branch-full form, and it has more serialized long latency
+   instructions on the critical path.
 
-    default:
-      break;
-    }
-}
+   For DFmode, we can avoid rounding errors by breaking up the word
+   into two pieces, converting them separately, and adding them back:
 
-/* Given INSN, which is an INSN list or the PATTERN of a single insn
-   generated to perform a memory operation, look for any MEMs in either
-   a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and
-   volatile flags from REF into each of the MEMs found.  If REF is not
-   a MEM, don't do anything.  */
+   LC0: .long 0,0x5f800000
+
+       itoft   $16,$f11
+       lda     $2,LC0
+       cmplt   $16,0,$1
+       cpyse   $f11,$f31,$f10
+       cpyse   $f31,$f11,$f11
+       s4addq  $1,$2,$1
+       lds     $f12,0($1)
+       cvtqt   $f10,$f10
+       cvtqt   $f11,$f11
+       addt    $f12,$f10,$f0
+       addt    $f0,$f11,$f0
+
+   This doesn't seem to be a clear-cut win over the optabs form.
+   It probably all depends on the distribution of numbers being
+   converted -- in the optabs form, all but high-bit-set has a
+   much lower minimum execution time.  */
 
 void
-alpha_set_memflags (rtx insn, rtx ref)
+alpha_emit_floatuns (rtx operands[2])
 {
-  int in_struct_p, volatile_p, unchanging_p;
+  rtx neglab, donelab, i0, i1, f0, in, out;
+  enum machine_mode mode;
 
-  if (GET_CODE (ref) != MEM)
-    return;
+  out = operands[0];
+  in = force_reg (DImode, operands[1]);
+  mode = GET_MODE (out);
+  neglab = gen_label_rtx ();
+  donelab = gen_label_rtx ();
+  i0 = gen_reg_rtx (DImode);
+  i1 = gen_reg_rtx (DImode);
+  f0 = gen_reg_rtx (mode);
 
-  in_struct_p = MEM_IN_STRUCT_P (ref);
-  volatile_p = MEM_VOLATILE_P (ref);
-  unchanging_p = RTX_UNCHANGING_P (ref);
+  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
 
-  /* This is only called from alpha.md, after having had something 
-     generated from one of the insn patterns.  So if everything is
-     zero, the pattern is already up-to-date.  */
-  if (! in_struct_p && ! volatile_p && ! unchanging_p)
-    return;
+  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
+  emit_jump_insn (gen_jump (donelab));
+  emit_barrier ();
+
+  emit_label (neglab);
+
+  emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
+  emit_insn (gen_anddi3 (i1, in, const1_rtx));
+  emit_insn (gen_iordi3 (i0, i0, i1));
+  emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
+  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
 
-  alpha_set_memflags_1 (insn, in_struct_p, volatile_p, unchanging_p);
+  emit_label (donelab);
 }
-\f
-/* Internal routine for alpha_emit_set_const to check for N or below insns.  */
 
-static rtx
-alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
-                       HOST_WIDE_INT c, int n)
+/* Generate the comparison for a conditional branch.  */
+
+rtx
+alpha_emit_conditional_branch (enum rtx_code code)
 {
-  HOST_WIDE_INT new;
-  int i, bits;
-  /* Use a pseudo if highly optimizing and still generating RTL.  */
-  rtx subtarget
-    = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target);
-  rtx temp, insn;
+  enum rtx_code cmp_code, branch_code;
+  enum machine_mode cmp_mode, branch_mode = VOIDmode;
+  rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
+  rtx tem;
 
-  /* 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.  */
+  if (alpha_compare.fp_p && GET_MODE (op0) == TFmode)
+    {
+      op0 = alpha_emit_xfloating_compare (&code, op0, op1);
+      op1 = const0_rtx;
+      alpha_compare.fp_p = 0;
+    }
 
-  if (HOST_BITS_PER_WIDE_INT != 64
-      || c >> 31 == -1 || c >> 31 == 0)
+  /* The general case: fold the comparison code to the types of compares
+     that we have, choosing the branch as necessary.  */
+  switch (code)
     {
-      HOST_WIDE_INT low = ((c & 0xffff) ^ 0x8000) - 0x8000;
-      HOST_WIDE_INT tmp1 = c - low;
-      HOST_WIDE_INT high = (((tmp1 >> 16) & 0xffff) ^ 0x8000) - 0x8000;
-      HOST_WIDE_INT extra = 0;
+    case EQ:  case LE:  case LT:  case LEU:  case LTU:
+    case UNORDERED:
+      /* We have these compares: */
+      cmp_code = code, branch_code = NE;
+      break;
 
-      /* If HIGH will be interpreted as negative but the constant is
-        positive, we must adjust it to do two ldha insns.  */
+    case NE:
+    case ORDERED:
+      /* These must be reversed.  */
+      cmp_code = reverse_condition (code), branch_code = EQ;
+      break;
 
-      if ((high & 0x8000) != 0 && c >= 0)
+    case GE:  case GT: case GEU:  case GTU:
+      /* For FP, we swap them, for INT, we reverse them.  */
+      if (alpha_compare.fp_p)
        {
-         extra = 0x4000;
-         tmp1 -= 0x40000000;
-         high = ((tmp1 >> 16) & 0xffff) - 2 * ((tmp1 >> 16) & 0x8000);
+         cmp_code = swap_condition (code);
+         branch_code = NE;
+         tem = op0, op0 = op1, op1 = tem;
        }
-
-      if (c == low || (low == 0 && extra == 0))
+      else
        {
-         /* We used to use copy_to_suggested_reg (GEN_INT (c), target, mode)
-            but that meant that we can't handle INT_MIN on 32-bit machines
-            (like NT/Alpha), because we recurse indefinitely through 
-            emit_move_insn to gen_movdi.  So instead, since we know exactly
-            what we want, create it explicitly.  */
-
-         if (target == NULL)
-           target = gen_reg_rtx (mode);
-         emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
-         return target;
+         cmp_code = reverse_condition (code);
+         branch_code = EQ;
        }
-      else if (n >= 2 + (extra != 0))
-       {
-         if (no_new_pseudos)
-           {
-             emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16)));
-             temp = target;
-           }
-         else
-           temp = copy_to_suggested_reg (GEN_INT (high << 16),
-                                         subtarget, mode);
+      break;
 
-         /* As of 2002-02-23, addsi3 is only available when not optimizing.
-            This means that if we go through expand_binop, we'll try to
-            generate extensions, etc, which will require new pseudos, which
-            will fail during some split phases.  The SImode add patterns
-            still exist, but are not named.  So build the insns by hand.  */
+    default:
+      gcc_unreachable ();
+    }
 
-         if (extra != 0)
+  if (alpha_compare.fp_p)
+    {
+      cmp_mode = DFmode;
+      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.  */
+         if (op1 == CONST0_RTX (DFmode))
+           cmp_code = UNKNOWN, branch_code = code;
+         else if (op0 == CONST0_RTX (DFmode))
            {
-             if (! subtarget)
-               subtarget = gen_reg_rtx (mode);
-             insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16));
-             insn = gen_rtx_SET (VOIDmode, subtarget, insn);
-             emit_insn (insn);
-             temp = subtarget;
+             /* Undo the swap we probably did just above.  */
+             tem = op0, op0 = op1, op1 = tem;
+             branch_code = swap_condition (cmp_code);
+             cmp_code = UNKNOWN;
            }
-
-         if (target == NULL)
-           target = gen_reg_rtx (mode);
-         insn = gen_rtx_PLUS (mode, temp, GEN_INT (low));
-         insn = gen_rtx_SET (VOIDmode, target, insn);
-         emit_insn (insn);
-         return target;
+       }
+      else
+       {
+         /* ??? We mark the branch mode to be CCmode to prevent the
+            compare and branch from being combined, since the compare
+            insn follows IEEE rules that the branch does not.  */
+         branch_mode = CCmode;
        }
     }
+  else
+    {
+      cmp_mode = DImode;
 
-  /* 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 || (mode == SImode && no_new_pseudos))
-    return 0;
+      /* The following optimizations are only for signed compares.  */
+      if (code != LEU && code != LTU && code != GEU && code != GTU)
+       {
+         /* Whee.  Compare and branch against 0 directly.  */
+         if (op1 == const0_rtx)
+           cmp_code = UNKNOWN, branch_code = code;
 
-  /* 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.  */
+         /* If the constants doesn't fit into an immediate, but can
+            be generated by lda/ldah, we adjust the argument and
+            compare against zero, so we can use beq/bne directly.  */
+         /* ??? Don't do this when comparing against symbols, otherwise
+            we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will
+            be declared false out of hand (at least for non-weak).  */
+         else if (GET_CODE (op1) == CONST_INT
+                  && (code == EQ || code == NE)
+                  && !(symbolic_operand (op0, VOIDmode)
+                       || (GET_CODE (op0) == REG && REG_POINTER (op0))))
+           {
+             HOST_WIDE_INT v = INTVAL (op1), n = -v;
 
-  for (i = 1; i < n; i++)
-    {
-      /* First, see if minus some low bits, we've an easy load of
-        high bits.  */
+             if (! CONST_OK_FOR_LETTER_P (v, 'I')
+                 && (CONST_OK_FOR_LETTER_P (n, 'K')
+                     || CONST_OK_FOR_LETTER_P (n, 'L')))
+               {
+                 cmp_code = PLUS, branch_code = code;
+                 op1 = GEN_INT (n);
+               }
+           }
+       }
 
-      new = ((c & 0xffff) ^ 0x8000) - 0x8000;
-      if (new != 0
-          && (temp = alpha_emit_set_const (subtarget, mode, c - new, i)) != 0)
-       return expand_binop (mode, add_optab, temp, GEN_INT (new),
-                            target, 0, OPTAB_WIDEN);
+      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);
+    }
 
-      /* Next try complementing.  */
-      if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
-       return expand_unop (mode, one_cmpl_optab, temp, target, 0);
+  /* Emit an initial compare instruction, if necessary.  */
+  tem = op0;
+  if (cmp_code != UNKNOWN)
+    {
+      tem = gen_reg_rtx (cmp_mode);
+      emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1));
+    }
 
-      /* 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
-        the constant.  To try to increase the chance of having the same
-        constant in more than one insn, start at the highest number of
-        bits to shift, but try all possibilities in case a ZAPNOT will
-        be useful.  */
+  /* Zero the operands.  */
+  memset (&alpha_compare, 0, sizeof (alpha_compare));
 
-      if ((bits = exact_log2 (c & - c)) > 0)
-       for (; bits > 0; bits--)
-         if ((temp = (alpha_emit_set_const
-                      (subtarget, mode, 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);
+  /* Return the branch comparison.  */
+  return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
+}
 
-      /* Now try high-order zero bits.  Here we try the shifted-in bits as
-        all zero and all ones.  Be careful to avoid shifting outside the
-        mode and to avoid shifting outside the host wide int size.  */
-      /* On narrow hosts, don't shift a 1 into the high bit, since we'll
-        confuse the recursive call and set all of the high 32 bits.  */
+/* Certain simplifications can be done to make invalid setcc operations
+   valid.  Return the final comparison, or NULL if we can't work.  */
 
-      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0)
-       for (; bits > 0; bits--)
-         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);
+rtx
+alpha_emit_setcc (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;
 
-      /* Now try high-order 1 bits.  We get that with a sign-extension.
-        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.  */
+  /* Zero the operands.  */
+  memset (&alpha_compare, 0, sizeof (alpha_compare));
 
-      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (~ c) - 2)) > 0)
-       for (; bits > 0; bits--)
-         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);
+  if (fp_p && GET_MODE (op0) == TFmode)
+    {
+      op0 = alpha_emit_xfloating_compare (&code, op0, op1);
+      op1 = const0_rtx;
+      fp_p = 0;
     }
 
-#if HOST_BITS_PER_WIDE_INT == 64
-  /* Finally, 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.  */
-
-  new = c;
-  for (i = 0; i < 64; i += 8)
-    if ((new & ((HOST_WIDE_INT) 0xff << i)) == 0)
-      new |= (HOST_WIDE_INT) 0xff << i;
+  if (fp_p && !TARGET_FIX)
+    return NULL_RTX;
 
-  /* We are only called for SImode and DImode.  If this is SImode, ensure that
-     we are sign extended to a full word.  */
+  /* The general case: fold the comparison code to the types of compares
+     that we have, choosing the branch as necessary.  */
 
-  if (mode == SImode)
-    new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  cmp_code = UNKNOWN;
+  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;
 
-  if (new != c && new != -1
-      && (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
+    case NE:
+      if (!fp_p && op1 == const0_rtx)
+       break;
+      /* FALLTHRU */
 
-  return 0;
-}
+    case ORDERED:
+      cmp_code = reverse_condition (code);
+      code = EQ;
+      break;
 
-/* Try to output insns to set TARGET equal to the constant C if it can be
-   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.  */
+    case GE:  case GT: case GEU:  case GTU:
+      /* These 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;
 
-rtx
-alpha_emit_set_const (rtx target, enum machine_mode mode,
-                     HOST_WIDE_INT c, int n)
-{
-  rtx result = 0;
-  rtx orig_target = target;
-  int i;
+    default:
+      gcc_unreachable ();
+    }
 
-  /* If we can't make any pseudos, TARGET is an SImode hard register, we
-     can't load this constant in one insn, do this in DImode.  */
-  if (no_new_pseudos && mode == SImode
-      && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER
-      && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0)
+  if (!fp_p)
     {
-      target = gen_lowpart (DImode, target);
-      mode = DImode;
+      if (!register_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
     }
 
-  /* Try 1 insn, then 2, then up to N.  */
-  for (i = 1; i <= n; i++)
+  /* Emit an initial compare instruction, if necessary.  */
+  if (cmp_code != UNKNOWN)
     {
-      result = alpha_emit_set_const_1 (target, mode, c, i);
-      if (result)
-       {
-         rtx insn = get_last_insn ();
-         rtx set = single_set (insn);
-         if (! CONSTANT_P (SET_SRC (set)))
-           set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
-         break;
-       }
-    }
+      enum machine_mode mode = fp_p ? DFmode : DImode;
 
-  /* Allow for the case where we changed the mode of TARGET.  */
-  if (result == target)
-    result = orig_target;
+      tmp = gen_reg_rtx (mode);
+      emit_insn (gen_rtx_SET (VOIDmode, tmp,
+                             gen_rtx_fmt_ee (cmp_code, mode, op0, op1)));
 
-  return result;
+      op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp;
+      op1 = const0_rtx;
+    }
+
+  /* Return the setcc comparison.  */
+  return gen_rtx_fmt_ee (code, DImode, op0, op1);
 }
 
-/* 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.  */
+
+/* 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 nonzero we must emit
+   an insn to perform the compare (it can't be done within
+   the conditional move).  */
 
 rtx
-alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
+alpha_emit_conditional_move (rtx cmp, enum machine_mode mode)
 {
-  HOST_WIDE_INT d1, d2, d3, d4;
-
-  /* Decompose the entire word */
-#if HOST_BITS_PER_WIDE_INT >= 64
-  if (c2 != -(c1 < 0))
-    abort ();
-  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
-  c1 -= d1;
-  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  c1 = (c1 - d2) >> 32;
-  d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
-  c1 -= d3;
-  d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c1 != d4)
-    abort ();
-#else
-  d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
-  c1 -= d1;
-  d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c1 != d2)
-    abort ();
-  c2 += (d2 < 0);
-  d3 = ((c2 & 0xffff) ^ 0x8000) - 0x8000;
-  c2 -= d3;
-  d4 = ((c2 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c2 != d4)
-    abort ();
-#endif
+  enum rtx_code code = GET_CODE (cmp);
+  enum rtx_code cmov_code = NE;
+  rtx op0 = alpha_compare.op0;
+  rtx op1 = alpha_compare.op1;
+  int fp_p = alpha_compare.fp_p;
+  enum machine_mode 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_unsafe_math_optimizations;
+  rtx tem;
 
-  /* Construct the high word */
-  if (d4)
-    {
-      emit_move_insn (target, GEN_INT (d4));
-      if (d3)
-       emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d3)));
-    }
-  else
-    emit_move_insn (target, GEN_INT (d3));
+  /* Zero the operands.  */
+  memset (&alpha_compare, 0, sizeof (alpha_compare));
 
-  /* Shift it into place */
-  emit_move_insn (target, gen_rtx_ASHIFT (DImode, target, GEN_INT (32)));
+  if (fp_p != FLOAT_MODE_P (mode))
+    {
+      enum rtx_code cmp_code;
 
-  /* Add in the low bits.  */
-  if (d2)
-    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d2)));
-  if (d1)
-    emit_move_insn (target, gen_rtx_PLUS (DImode, target, GEN_INT (d1)));
+      if (! TARGET_FIX)
+       return 0;
 
-  return target;
-}
+      /* If we have fp<->int register move instructions, do a cmov by
+        performing the comparison in fp registers, and move the
+        zero/nonzero value to integer registers, where we can then
+        use a normal cmov, or vice-versa.  */
 
-/* Expand a move instruction; return true if all work is done.
-   We don't handle non-bwx subword loads here.  */
+      switch (code)
+       {
+       case EQ: case LE: case LT: case LEU: case LTU:
+         /* We have these compares.  */
+         cmp_code = code, code = NE;
+         break;
 
-bool
-alpha_expand_mov (enum machine_mode mode, rtx *operands)
-{
-  /* If the output is not a register, the input must be.  */
-  if (GET_CODE (operands[0]) == MEM
-      && ! reg_or_0_operand (operands[1], mode))
-    operands[1] = force_reg (mode, operands[1]);
+       case NE:
+         /* This must be reversed.  */
+         cmp_code = EQ, code = EQ;
+         break;
 
-  /* Allow legitimize_address to perform some simplifications.  */
-  if (mode == Pmode && symbolic_operand (operands[1], mode))
-    {
-      rtx tmp;
+       case GE: case GT: case GEU: case GTU:
+         /* These normally need swapping, but for integer zero we have
+            special patterns that recognize swapped operands.  */
+         if (!fp_p && op1 == const0_rtx)
+           cmp_code = code, code = NE;
+         else
+           {
+             cmp_code = swap_condition (code);
+             code = NE;
+             tem = op0, op0 = op1, op1 = tem;
+           }
+         break;
 
-      tmp = alpha_legitimize_address (operands[1], operands[0], mode);
-      if (tmp)
-       {
-         if (tmp == operands[0])
-           return true;
-         operands[1] = tmp;
-         return false;
+       default:
+         gcc_unreachable ();
        }
+
+      tem = gen_reg_rtx (cmp_op_mode);
+      emit_insn (gen_rtx_SET (VOIDmode, tem,
+                             gen_rtx_fmt_ee (cmp_code, cmp_op_mode,
+                                             op0, op1)));
+
+      cmp_mode = cmp_op_mode = fp_p ? DImode : DFmode;
+      op0 = gen_lowpart (cmp_op_mode, tem);
+      op1 = CONST0_RTX (cmp_op_mode);
+      fp_p = !fp_p;
+      local_fast_math = 1;
     }
 
-  /* Early out for non-constants and valid constants.  */
-  if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode))
-    return false;
+  /* We may be able to use a conditional move directly.
+     This avoids emitting spurious compares.  */
+  if (signed_comparison_operator (cmp, VOIDmode)
+      && (!fp_p || local_fast_math)
+      && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
+    return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
 
-  /* Split large integers.  */
-  if (GET_CODE (operands[1]) == CONST_INT
-      || GET_CODE (operands[1]) == CONST_DOUBLE)
-    {
-      HOST_WIDE_INT i0, i1;
-      rtx temp = NULL_RTX;
+  /* We can't put the comparison inside the 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.  */
 
-      if (GET_CODE (operands[1]) == CONST_INT)
-       {
-         i0 = INTVAL (operands[1]);
-         i1 = -(i0 < 0);
-       }
-      else if (HOST_BITS_PER_WIDE_INT >= 64)
-       {
-         i0 = CONST_DOUBLE_LOW (operands[1]);
-         i1 = -(i0 < 0);
-       }
-      else
-       {
-         i0 = CONST_DOUBLE_LOW (operands[1]);
-         i1 = CONST_DOUBLE_HIGH (operands[1]);
-       }
+  if (no_new_pseudos)
+    return NULL_RTX;
 
-      if (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
-       temp = alpha_emit_set_const (operands[0], mode, i0, 3);
+  switch (code)
+    {
+    case EQ:  case LE:  case LT:  case LEU:  case LTU:
+      /* We have these compares: */
+      break;
 
-      if (!temp && TARGET_BUILD_CONSTANTS)
-       temp = alpha_emit_set_long_const (operands[0], i0, i1);
+    case NE:
+      /* This must be reversed.  */
+      code = reverse_condition (code);
+      cmov_code = EQ;
+      break;
 
-      if (temp)
+    case GE:  case GT:  case GEU:  case GTU:
+      /* These must be swapped.  */
+      if (op1 != CONST0_RTX (cmp_mode))
        {
-         if (rtx_equal_p (operands[0], temp))
-           return true;
-         operands[1] = temp;
-         return false;
+         code = swap_condition (code);
+         tem = op0, op0 = op1, op1 = tem;
        }
+      break;
+
+    default:
+      gcc_unreachable ();
     }
 
-  /* Otherwise we've nothing left but to drop the thing to memory.  */
-  operands[1] = force_const_mem (mode, operands[1]);
-  if (reload_in_progress)
+  if (!fp_p)
     {
-      emit_move_insn (operands[0], XEXP (operands[1], 0));
-      operands[1] = copy_rtx (operands[1]);
-      XEXP (operands[1], 0) = operands[0];
+      if (!reg_or_0_operand (op0, DImode))
+       op0 = force_reg (DImode, op0);
+      if (!reg_or_8bit_operand (op1, DImode))
+       op1 = force_reg (DImode, op1);
     }
-  else
-    operands[1] = validize_mem (operands[1]);
-  return false;
+
+  /* ??? 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.  */
+  if (fp_p && !local_fast_math)
+    cmov_mode = CCmode;
+
+  tem = gen_reg_rtx (cmp_op_mode);
+  emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_op_mode, op0, op1));
+  return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode));
 }
 
-/* Expand a non-bwx QImode or HImode move instruction;
-   return true if all work is done.  */
+/* Simplify a conditional move of two constants into a setcc with
+   arithmetic.  This is done with a splitter since combine would
+   just undo the work if done during code generation.  It also catches
+   cases we wouldn't have before cse.  */
 
-bool
-alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
+int
+alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond,
+                             rtx t_rtx, rtx f_rtx)
 {
-  /* If the output is not a register, the input must be.  */
-  if (GET_CODE (operands[0]) == MEM)
-    operands[1] = force_reg (mode, operands[1]);
+  HOST_WIDE_INT t, f, diff;
+  enum machine_mode mode;
+  rtx target, subtarget, tmp;
 
-  /* Handle four memory cases, unaligned and aligned for either the input
-     or the output.  The only case where we can be called during reload is
-     for aligned loads; all other cases require temporaries.  */
+  mode = GET_MODE (dest);
+  t = INTVAL (t_rtx);
+  f = INTVAL (f_rtx);
+  diff = t - f;
 
-  if (GET_CODE (operands[1]) == MEM
-      || (GET_CODE (operands[1]) == SUBREG
-         && GET_CODE (SUBREG_REG (operands[1])) == MEM)
-      || (reload_in_progress && GET_CODE (operands[1]) == REG
-         && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER)
-      || (reload_in_progress && GET_CODE (operands[1]) == SUBREG
-         && GET_CODE (SUBREG_REG (operands[1])) == REG
-         && REGNO (SUBREG_REG (operands[1])) >= FIRST_PSEUDO_REGISTER))
+  if (((code == NE || code == EQ) && diff < 0)
+      || (code == GE || code == GT))
     {
-      if (aligned_memory_operand (operands[1], mode))
-       {
-         if (reload_in_progress)
-           {
-             emit_insn ((mode == QImode
-                         ? gen_reload_inqi_help
-                         : gen_reload_inhi_help)
-                        (operands[0], operands[1],
-                         gen_rtx_REG (SImode, REGNO (operands[0]))));
-           }
-         else
-           {
-             rtx aligned_mem, bitnum;
-             rtx scratch = gen_reg_rtx (SImode);
-             rtx subtarget;
-             bool copyout;
-
-             get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+      code = reverse_condition (code);
+      diff = t, t = f, f = diff;
+      diff = t - f;
+    }
 
-             subtarget = operands[0];
-             if (GET_CODE (subtarget) == REG)
-               subtarget = gen_lowpart (DImode, subtarget), copyout = false;
-             else
-               subtarget = gen_reg_rtx (DImode), copyout = true;
+  subtarget = target = dest;
+  if (mode != DImode)
+    {
+      target = gen_lowpart (DImode, dest);
+      if (! no_new_pseudos)
+        subtarget = gen_reg_rtx (DImode);
+      else
+       subtarget = target;
+    }
+  /* Below, we must be careful to use copy_rtx on target and subtarget
+     in intermediate insns, as they may be a subreg rtx, which may not
+     be shared.  */
 
-             emit_insn ((mode == QImode
-                         ? gen_aligned_loadqi
-                         : gen_aligned_loadhi)
-                        (subtarget, aligned_mem, bitnum, scratch));
-
-             if (copyout)
-               emit_move_insn (operands[0], gen_lowpart (mode, subtarget));
-           }
-       }
-      else
-       {
-         /* Don't pass these as parameters since that makes the generated
-            code depend on parameter evaluation order which will cause
-            bootstrap failures.  */
-
-         rtx temp1, temp2, seq, subtarget;
-         bool copyout;
-
-         temp1 = gen_reg_rtx (DImode);
-         temp2 = gen_reg_rtx (DImode);
-
-         subtarget = operands[0];
-         if (GET_CODE (subtarget) == REG)
-           subtarget = gen_lowpart (DImode, subtarget), copyout = false;
-         else
-           subtarget = gen_reg_rtx (DImode), copyout = true;
-
-         seq = ((mode == QImode
-                 ? gen_unaligned_loadqi
-                 : gen_unaligned_loadhi)
-                (subtarget, get_unaligned_address (operands[1], 0),
-                 temp1, temp2));
-         alpha_set_memflags (seq, operands[1]);
-         emit_insn (seq);
+  if (f == 0 && exact_log2 (diff) > 0
+      /* On EV6, we've got enough shifters to make non-arithmetic shifts
+        viable over a longer latency cmove.  On EV5, the E0 slot is a
+        scarce resource, and on EV4 shift has the same latency as a cmove.  */
+      && (diff <= 8 || alpha_tune == PROCESSOR_EV6))
+    {
+      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-         if (copyout)
-           emit_move_insn (operands[0], gen_lowpart (mode, subtarget));
-       }
-      return true;
+      tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget),
+                           GEN_INT (exact_log2 (t)));
+      emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
     }
+  else if (f == 0 && t == -1)
+    {
+      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-  if (GET_CODE (operands[0]) == MEM
-      || (GET_CODE (operands[0]) == SUBREG
-         && GET_CODE (SUBREG_REG (operands[0])) == MEM)
-      || (reload_in_progress && GET_CODE (operands[0]) == REG
-         && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER)
-      || (reload_in_progress && GET_CODE (operands[0]) == SUBREG
-         && GET_CODE (SUBREG_REG (operands[0])) == REG
-         && REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
+      emit_insn (gen_negdi2 (target, copy_rtx (subtarget)));
+    }
+  else if (diff == 1 || diff == 4 || diff == 8)
     {
-      if (aligned_memory_operand (operands[0], mode))
-       {
-         rtx aligned_mem, bitnum;
-         rtx temp1 = gen_reg_rtx (SImode);
-         rtx temp2 = gen_reg_rtx (SImode);
+      rtx add_op;
 
-         get_aligned_mem (operands[0], &aligned_mem, &bitnum);
+      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-         emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
-                                       temp1, temp2));
-       }
+      if (diff == 1)
+       emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f)));
       else
        {
-         rtx temp1 = gen_reg_rtx (DImode);
-         rtx temp2 = gen_reg_rtx (DImode);
-         rtx temp3 = gen_reg_rtx (DImode);
-         rtx seq = ((mode == QImode
-                     ? gen_unaligned_storeqi
-                     : gen_unaligned_storehi)
-                    (get_unaligned_address (operands[0], 0),
-                     operands[1], temp1, temp2, temp3));
-
-         alpha_set_memflags (seq, operands[0]);
-         emit_insn (seq);
+         add_op = GEN_INT (f);
+         if (sext_add_operand (add_op, mode))
+           {
+             tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget),
+                                 GEN_INT (diff));
+             tmp = gen_rtx_PLUS (DImode, tmp, add_op);
+             emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
+           }
+         else
+           return 0;
        }
-      return true;
     }
+  else
+    return 0;
 
-  return false;
+  return 1;
 }
+\f
+/* Look up the function X_floating library function name for the
+   given operation.  */
 
-/* Generate an unsigned DImode to FP conversion.  This is the same code
-   optabs would emit if we didn't have TFmode patterns.
-
-   For SFmode, this is the only construction I've found that can pass
-   gcc.c-torture/execute/ieee/rbug.c.  No scenario that uses DFmode
-   intermediates will work, because you'll get intermediate rounding
-   that ruins the end result.  Some of this could be fixed by turning
-   on round-to-positive-infinity, but that requires diddling the fpsr,
-   which kills performance.  I tried turning this around and converting
-   to a negative number, so that I could turn on /m, but either I did
-   it wrong or there's something else cause I wound up with the exact
-   same single-bit error.  There is a branch-less form of this same code:
+struct xfloating_op GTY(())
+{
+  const enum rtx_code code;
+  const char *const GTY((skip)) osf_func;
+  const char *const GTY((skip)) vms_func;
+  rtx libcall;
+};
 
-       srl     $16,1,$1
-       and     $16,1,$2
-       cmplt   $16,0,$3
-       or      $1,$2,$2
-       cmovge  $16,$16,$2
-       itoft   $3,$f10
-       itoft   $2,$f11
-       cvtqs   $f11,$f11
-       adds    $f11,$f11,$f0
-       fcmoveq $f10,$f11,$f0
+static GTY(()) struct xfloating_op xfloating_ops[] =
+{
+  { PLUS,              "_OtsAddX", "OTS$ADD_X", 0 },
+  { MINUS,             "_OtsSubX", "OTS$SUB_X", 0 },
+  { MULT,              "_OtsMulX", "OTS$MUL_X", 0 },
+  { DIV,               "_OtsDivX", "OTS$DIV_X", 0 },
+  { EQ,                        "_OtsEqlX", "OTS$EQL_X", 0 },
+  { NE,                        "_OtsNeqX", "OTS$NEQ_X", 0 },
+  { LT,                        "_OtsLssX", "OTS$LSS_X", 0 },
+  { LE,                        "_OtsLeqX", "OTS$LEQ_X", 0 },
+  { GT,                        "_OtsGtrX", "OTS$GTR_X", 0 },
+  { GE,                        "_OtsGeqX", "OTS$GEQ_X", 0 },
+  { FIX,               "_OtsCvtXQ", "OTS$CVTXQ", 0 },
+  { FLOAT,             "_OtsCvtQX", "OTS$CVTQX", 0 },
+  { UNSIGNED_FLOAT,    "_OtsCvtQUX", "OTS$CVTQUX", 0 },
+  { FLOAT_EXTEND,      "_OtsConvertFloatTX", "OTS$CVT_FLOAT_T_X", 0 },
+  { FLOAT_TRUNCATE,    "_OtsConvertFloatXT", "OTS$CVT_FLOAT_X_T", 0 }
+};
 
-   I'm not using it because it's the same number of instructions as
-   this branch-full form, and it has more serialized long latency
-   instructions on the critical path.
+static GTY(()) struct xfloating_op vax_cvt_ops[] =
+{
+  { FLOAT_EXTEND,      "_OtsConvertFloatGX", "OTS$CVT_FLOAT_G_X", 0 },
+  { FLOAT_TRUNCATE,    "_OtsConvertFloatXG", "OTS$CVT_FLOAT_X_G", 0 }
+};
 
-   For DFmode, we can avoid rounding errors by breaking up the word
-   into two pieces, converting them separately, and adding them back:
+static rtx
+alpha_lookup_xfloating_lib_func (enum rtx_code code)
+{
+  struct xfloating_op *ops = xfloating_ops;
+  long n = ARRAY_SIZE (xfloating_ops);
+  long i;
 
-   LC0: .long 0,0x5f800000
+  gcc_assert (TARGET_HAS_XFLOATING_LIBS);
 
-       itoft   $16,$f11
-       lda     $2,LC0
-       cmplt   $16,0,$1
-       cpyse   $f11,$f31,$f10
-       cpyse   $f31,$f11,$f11
-       s4addq  $1,$2,$1
-       lds     $f12,0($1)
-       cvtqt   $f10,$f10
-       cvtqt   $f11,$f11
-       addt    $f12,$f10,$f0
-       addt    $f0,$f11,$f0
+  /* How irritating.  Nothing to key off for the main table.  */
+  if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE))
+    {
+      ops = vax_cvt_ops;
+      n = ARRAY_SIZE (vax_cvt_ops);
+    }
 
-   This doesn't seem to be a clear-cut win over the optabs form.
-   It probably all depends on the distribution of numbers being
-   converted -- in the optabs form, all but high-bit-set has a
-   much lower minimum execution time.  */
+  for (i = 0; i < n; ++i, ++ops)
+    if (ops->code == code)
+      {
+       rtx func = ops->libcall;
+       if (!func)
+         {
+           func = init_one_libfunc (TARGET_ABI_OPEN_VMS
+                                    ? ops->vms_func : ops->osf_func);
+           ops->libcall = func;
+         }
+        return func;
+      }
 
-void
-alpha_emit_floatuns (rtx operands[2])
-{
-  rtx neglab, donelab, i0, i1, f0, in, out;
-  enum machine_mode mode;
+  gcc_unreachable ();
+}
 
-  out = operands[0];
-  in = force_reg (DImode, operands[1]);
-  mode = GET_MODE (out);
-  neglab = gen_label_rtx ();
-  donelab = gen_label_rtx ();
-  i0 = gen_reg_rtx (DImode);
-  i1 = gen_reg_rtx (DImode);
-  f0 = gen_reg_rtx (mode);
+/* Most X_floating operations take the rounding mode as an argument.
+   Compute that here.  */
 
-  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
+static int
+alpha_compute_xfloating_mode_arg (enum rtx_code code,
+                                 enum alpha_fp_rounding_mode round)
+{
+  int mode;
 
-  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
-  emit_jump_insn (gen_jump (donelab));
-  emit_barrier ();
+  switch (round)
+    {
+    case ALPHA_FPRM_NORM:
+      mode = 2;
+      break;
+    case ALPHA_FPRM_MINF:
+      mode = 1;
+      break;
+    case ALPHA_FPRM_CHOP:
+      mode = 0;
+      break;
+    case ALPHA_FPRM_DYN:
+      mode = 4;
+      break;
+    default:
+      gcc_unreachable ();
 
-  emit_label (neglab);
+    /* XXX For reference, round to +inf is mode = 3.  */
+    }
 
-  emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
-  emit_insn (gen_anddi3 (i1, in, const1_rtx));
-  emit_insn (gen_iordi3 (i0, i0, i1));
-  emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
-  emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
+  if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N)
+    mode |= 0x10000;
 
-  emit_label (donelab);
+  return mode;
 }
 
-/* Generate the comparison for a conditional branch.  */
+/* Emit an X_floating library function call.
 
-rtx
-alpha_emit_conditional_branch (enum rtx_code code)
-{
-  enum rtx_code cmp_code, branch_code;
-  enum machine_mode cmp_mode, branch_mode = VOIDmode;
-  rtx op0 = alpha_compare.op0, op1 = alpha_compare.op1;
-  rtx tem;
+   Note that these functions do not follow normal calling conventions:
+   TFmode arguments are passed in two integer registers (as opposed to
+   indirect); TFmode return values appear in R16+R17.
 
-  if (alpha_compare.fp_p && GET_MODE (op0) == TFmode)
-    {
-      if (! TARGET_HAS_XFLOATING_LIBS)
-       abort ();
+   FUNC is the function to call.
+   TARGET is where the output belongs.
+   OPERANDS are the inputs.
+   NOPERANDS is the count of inputs.
+   EQUIV is the expression equivalent for the function.
+*/
 
-      /* X_floating library comparison functions return
-          -1  unordered
-           0  false
-           1  true
-        Convert the compare against the raw return value.  */
+static void
+alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
+                             int noperands, rtx equiv)
+{
+  rtx usage = NULL_RTX, tmp, reg;
+  int regno = 16, i;
 
-      switch (code)
+  start_sequence ();
+
+  for (i = 0; i < noperands; ++i)
+    {
+      switch (GET_MODE (operands[i]))
        {
-       case UNORDERED:
-         cmp_code = EQ;
-         code = LT;
+       case TFmode:
+         reg = gen_rtx_REG (TFmode, regno);
+         regno += 2;
          break;
-       case ORDERED:
-         cmp_code = EQ;
-         code = GE;
+
+       case DFmode:
+         reg = gen_rtx_REG (DFmode, regno + 32);
+         regno += 1;
          break;
-       case NE:
-         cmp_code = NE;
-         code = NE;
+
+       case VOIDmode:
+         gcc_assert (GET_CODE (operands[i]) == CONST_INT);
+         /* FALLTHRU */
+       case DImode:
+         reg = gen_rtx_REG (DImode, regno);
+         regno += 1;
          break;
+
        default:
-         cmp_code = code;
-         code = GT;
-         break;
+         gcc_unreachable ();
        }
 
-      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
-      op1 = const0_rtx;
-      alpha_compare.fp_p = 0;
+      emit_move_insn (reg, operands[i]);
+      usage = alloc_EXPR_LIST (0, gen_rtx_USE (VOIDmode, reg), usage);
     }
 
-  /* The general case: fold the comparison code to the types of compares
-     that we have, choosing the branch as necessary.  */
-  switch (code)
+  switch (GET_MODE (target))
     {
-    case EQ:  case LE:  case LT:  case LEU:  case LTU:
-    case UNORDERED:
-      /* We have these compares: */
-      cmp_code = code, branch_code = NE;
+    case TFmode:
+      reg = gen_rtx_REG (TFmode, 16);
       break;
-
-    case NE:
-    case ORDERED:
-      /* These must be reversed.  */
-      cmp_code = reverse_condition (code), branch_code = EQ;
+    case DFmode:
+      reg = gen_rtx_REG (DFmode, 32);
       break;
-
-    case GE:  case GT: case GEU:  case GTU:
-      /* For FP, we swap them, for INT, we reverse them.  */
-      if (alpha_compare.fp_p)
-       {
-         cmp_code = swap_condition (code);
-         branch_code = NE;
-         tem = op0, op0 = op1, op1 = tem;
-       }
-      else
-       {
-         cmp_code = reverse_condition (code);
-         branch_code = EQ;
-       }
+    case DImode:
+      reg = gen_rtx_REG (DImode, 0);
       break;
-
     default:
-      abort ();
-    }
-
-  if (alpha_compare.fp_p)
-    {
-      cmp_mode = DFmode;
-      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.  */
-         if (op1 == CONST0_RTX (DFmode))
-           cmp_code = NIL, branch_code = code;
-         else if (op0 == CONST0_RTX (DFmode))
-           {
-             /* Undo the swap we probably did just above.  */
-             tem = op0, op0 = op1, op1 = tem;
-             branch_code = swap_condition (cmp_code);
-             cmp_code = NIL;
-           }
-       }
-      else
-       {
-         /* ??? We mark the branch mode to be CCmode to prevent the
-            compare and branch from being combined, since the compare 
-            insn follows IEEE rules that the branch does not.  */
-         branch_mode = CCmode;
-       }
+      gcc_unreachable ();
     }
-  else
-    {
-      cmp_mode = DImode;
 
-      /* The following optimizations are only for signed compares.  */
-      if (code != LEU && code != LTU && code != GEU && code != GTU)
-       {
-         /* Whee.  Compare and branch against 0 directly.  */
-         if (op1 == const0_rtx)
-           cmp_code = NIL, branch_code = code;
+  tmp = gen_rtx_MEM (QImode, func);
+  tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
+                                       const0_rtx, const0_rtx));
+  CALL_INSN_FUNCTION_USAGE (tmp) = usage;
+  CONST_OR_PURE_CALL_P (tmp) = 1;
 
-         /* If the constants doesn't fit into an immediate, but can
-            be generated by lda/ldah, we adjust the argument and
-            compare against zero, so we can use beq/bne directly.  */
-         /* ??? Don't do this when comparing against symbols, otherwise
-            we'll reduce (&x == 0x1234) to (&x-0x1234 == 0), which will
-            be declared false out of hand (at least for non-weak).  */
-         else if (GET_CODE (op1) == CONST_INT
-                  && (code == EQ || code == NE)
-                  && !(symbolic_operand (op0, VOIDmode)
-                       || (GET_CODE (op0) == REG && REG_POINTER (op0))))
-           {
-             HOST_WIDE_INT v = INTVAL (op1), n = -v;
+  tmp = get_insns ();
+  end_sequence ();
 
-             if (! CONST_OK_FOR_LETTER_P (v, 'I')
-                 && (CONST_OK_FOR_LETTER_P (n, 'K')
-                     || CONST_OK_FOR_LETTER_P (n, 'L')))
-               {
-                 cmp_code = PLUS, branch_code = code;
-                 op1 = GEN_INT (n);
-               }
-           }
-       }
+  emit_libcall_block (tmp, target, reg, equiv);
+}
 
-      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 X_floating library function call for arithmetic (+,-,*,/).  */
 
-  /* Emit an initial compare instruction, if necessary.  */
-  tem = op0;
-  if (cmp_code != NIL)
-    {
-      tem = gen_reg_rtx (cmp_mode);
-      emit_move_insn (tem, gen_rtx_fmt_ee (cmp_code, cmp_mode, op0, op1));
-    }
+void
+alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[])
+{
+  rtx func;
+  int mode;
+  rtx out_operands[3];
 
-  /* Zero the operands.  */
-  memset (&alpha_compare, 0, sizeof (alpha_compare));
+  func = alpha_lookup_xfloating_lib_func (code);
+  mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
 
-  /* Return the branch comparison.  */
-  return gen_rtx_fmt_ee (branch_code, branch_mode, tem, CONST0_RTX (cmp_mode));
+  out_operands[0] = operands[1];
+  out_operands[1] = operands[2];
+  out_operands[2] = GEN_INT (mode);
+  alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3,
+                               gen_rtx_fmt_ee (code, TFmode, operands[1],
+                                               operands[2]));
 }
 
-/* Certain simplifications can be done to make invalid setcc operations
-   valid.  Return the final comparison, or NULL if we can't work.  */
+/* Emit an X_floating library function call for a comparison.  */
 
-rtx
-alpha_emit_setcc (enum rtx_code code)
+static rtx
+alpha_emit_xfloating_compare (enum rtx_code *pcode, rtx op0, rtx op1)
 {
-  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 ();
+  enum rtx_code cmp_code, res_code;
+  rtx func, out, operands[2];
 
-      /* X_floating library comparison functions return
+  /* 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;
+     Convert the compare against the raw return value.  */
 
-  /* 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)
+  cmp_code = *pcode;
+  switch (cmp_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;
+      cmp_code = EQ;
+      res_code = LT;
       break;
-
-    case NE:
-      if (!fp_p && op1 == const0_rtx)
-       break;
-      /* FALLTHRU */
-
     case ORDERED:
-      cmp_code = reverse_condition (code);
-      code = EQ;
+      cmp_code = EQ;
+      res_code = GE;
       break;
-
-    case GE:  case GT: case GEU:  case GTU:
-      /* These 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;
+    case NE:
+      res_code = NE;
+      break;
+    case EQ:
+    case LT:
+    case GT:
+    case LE:
+    case GE:
+      res_code = GT;
       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);
+      gcc_unreachable ();
     }
+  *pcode = res_code;
 
-  /* Emit an initial compare instruction, if necessary.  */
-  if (cmp_code != NIL)
-    {
-      enum machine_mode mode = fp_p ? DFmode : DImode;
+  func = alpha_lookup_xfloating_lib_func (cmp_code);
 
-      tmp = gen_reg_rtx (mode);
-      emit_insn (gen_rtx_SET (VOIDmode, tmp,
-                             gen_rtx_fmt_ee (cmp_code, mode, op0, op1)));
+  operands[0] = op0;
+  operands[1] = op1;
+  out = gen_reg_rtx (DImode);
 
-      op0 = fp_p ? gen_lowpart (DImode, tmp) : tmp;
-      op1 = const0_rtx;
-    }
+  /* ??? Strange mode for equiv because what's actually returned
+     is -1,0,1, not a proper boolean value.  */
+  alpha_emit_xfloating_libcall (func, out, operands, 2,
+                               gen_rtx_fmt_ee (cmp_code, CCmode, op0, op1));
 
-  /* Return the setcc comparison.  */
-  return gen_rtx_fmt_ee (code, DImode, op0, op1);
+  return out;
 }
 
+/* Emit an X_floating library function call for a conversion.  */
 
-/* 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 nonzero we must emit
-   an insn to perform the compare (it can't be done within
-   the conditional move).  */
-
-rtx
-alpha_emit_conditional_move (rtx cmp, enum machine_mode mode)
+void
+alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[])
 {
-  enum rtx_code code = GET_CODE (cmp);
-  enum rtx_code cmov_code = NE;
-  rtx op0 = alpha_compare.op0;
-  rtx op1 = alpha_compare.op1;
-  int fp_p = alpha_compare.fp_p;
-  enum machine_mode 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_unsafe_math_optimizations;
-  rtx tem;
-
-  /* Zero the operands.  */
-  memset (&alpha_compare, 0, sizeof (alpha_compare));
-
-  if (fp_p != FLOAT_MODE_P (mode))
-    {
-      enum rtx_code cmp_code;
-
-      if (! TARGET_FIX)
-       return 0;
-
-      /* If we have fp<->int register move instructions, do a cmov by
-        performing the comparison in fp registers, and move the
-        zero/nonzero value to integer registers, where we can then
-        use a normal cmov, or vice-versa.  */
-
-      switch (code)
-       {
-       case EQ: case LE: case LT: case LEU: case LTU:
-         /* We have these compares.  */
-         cmp_code = code, code = NE;
-         break;
-
-       case NE:
-         /* This must be reversed.  */
-         cmp_code = EQ, code = EQ;
-         break;
+  int noperands = 1, mode;
+  rtx out_operands[2];
+  rtx func;
+  enum rtx_code code = orig_code;
 
-       case GE: case GT: case GEU: case GTU:
-         /* These normally need swapping, but for integer zero we have
-            special patterns that recognize swapped operands.  */
-         if (!fp_p && op1 == const0_rtx)
-           cmp_code = code, code = NE;
-         else
-           {
-             cmp_code = swap_condition (code);
-             code = NE;
-             tem = op0, op0 = op1, op1 = tem;
-           }
-         break;
+  if (code == UNSIGNED_FIX)
+    code = FIX;
 
-       default:
-         abort ();
-       }
+  func = alpha_lookup_xfloating_lib_func (code);
 
-      tem = gen_reg_rtx (cmp_op_mode);
-      emit_insn (gen_rtx_SET (VOIDmode, tem,
-                             gen_rtx_fmt_ee (cmp_code, cmp_op_mode,
-                                             op0, op1)));
+  out_operands[0] = operands[1];
 
-      cmp_mode = cmp_op_mode = fp_p ? DImode : DFmode;
-      op0 = gen_lowpart (cmp_op_mode, tem);
-      op1 = CONST0_RTX (cmp_op_mode);
-      fp_p = !fp_p;
-      local_fast_math = 1;
+  switch (code)
+    {
+    case FIX:
+      mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP);
+      out_operands[1] = GEN_INT (mode);
+      noperands = 2;
+      break;
+    case FLOAT_TRUNCATE:
+      mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
+      out_operands[1] = GEN_INT (mode);
+      noperands = 2;
+      break;
+    default:
+      break;
     }
 
-  /* We may be able to use a conditional move directly.
-     This avoids emitting spurious compares.  */
-  if (signed_comparison_operator (cmp, VOIDmode)
-      && (!fp_p || local_fast_math)
-      && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
-    return gen_rtx_fmt_ee (code, VOIDmode, op0, op1);
-
-  /* We can't put the comparison inside the 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.  */
+  alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands,
+                               gen_rtx_fmt_e (orig_code,
+                                              GET_MODE (operands[0]),
+                                              operands[1]));
+}
 
-  if (no_new_pseudos)
-    return NULL_RTX;
+/* 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.  */
 
-  switch (code)
+void
+alpha_split_tfmode_pair (rtx operands[4])
+{
+  switch (GET_CODE (operands[1]))
     {
-    case EQ:  case LE:  case LT:  case LEU:  case LTU:
-      /* We have these compares: */
+    case REG:
+      operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
+      operands[2] = gen_rtx_REG (DImode, REGNO (operands[1]));
       break;
 
-    case NE:
-      /* This must be reversed.  */
-      code = reverse_condition (code);
-      cmov_code = EQ;
+    case MEM:
+      operands[3] = adjust_address (operands[1], DImode, 8);
+      operands[2] = adjust_address (operands[1], DImode, 0);
       break;
 
-    case GE:  case GT:  case GEU:  case GTU:
-      /* These must be swapped.  */
-      if (op1 != CONST0_RTX (cmp_mode))
-       {
-         code = swap_condition (code);
-         tem = op0, op0 = op1, op1 = tem;
-       }
+    case CONST_DOUBLE:
+      gcc_assert (operands[1] == CONST0_RTX (TFmode));
+      operands[2] = operands[3] = const0_rtx;
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
-  if (!fp_p)
+  switch (GET_CODE (operands[0]))
     {
-      if (!reg_or_0_operand (op0, DImode))
-       op0 = force_reg (DImode, op0);
-      if (!reg_or_8bit_operand (op1, DImode))
-       op1 = force_reg (DImode, op1);
-    }
+    case REG:
+      operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1);
+      operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+      break;
 
-  /* ??? 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.  */
-  if (fp_p && !local_fast_math)
-    cmov_mode = CCmode;
+    case MEM:
+      operands[1] = adjust_address (operands[0], DImode, 8);
+      operands[0] = adjust_address (operands[0], DImode, 0);
+      break;
 
-  tem = gen_reg_rtx (cmp_op_mode);
-  emit_move_insn (tem, gen_rtx_fmt_ee (code, cmp_op_mode, op0, op1));
-  return gen_rtx_fmt_ee (cmov_code, cmov_mode, tem, CONST0_RTX (cmp_op_mode));
+    default:
+      gcc_unreachable ();
+    }
 }
 
-/* Simplify a conditional move of two constants into a setcc with
-   arithmetic.  This is done with a splitter since combine would
-   just undo the work if done during code generation.  It also catches
-   cases we wouldn't have before cse.  */
+/* 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.  */
 
-int
-alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond,
-                             rtx t_rtx, rtx f_rtx)
+void
+alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx))
 {
-  HOST_WIDE_INT t, f, diff;
-  enum machine_mode mode;
-  rtx target, subtarget, tmp;
-
-  mode = GET_MODE (dest);
-  t = INTVAL (t_rtx);
-  f = INTVAL (f_rtx);
-  diff = t - f;
+  rtx high_bit = operands[2];
+  rtx scratch;
+  int move;
 
-  if (((code == NE || code == EQ) && diff < 0)
-      || (code == GE || code == GT))
-    {
-      code = reverse_condition (code);
-      diff = t, t = f, f = diff;
-      diff = t - f;
-    }
+  alpha_split_tfmode_pair (operands);
 
-  subtarget = target = dest;
-  if (mode != DImode)
+  /* Detect three flavors of operand overlap.  */
+  move = 1;
+  if (rtx_equal_p (operands[0], operands[2]))
+    move = 0;
+  else if (rtx_equal_p (operands[1], operands[2]))
     {
-      target = gen_lowpart (DImode, dest);
-      if (! no_new_pseudos)
-        subtarget = gen_reg_rtx (DImode);
+      if (rtx_equal_p (operands[0], high_bit))
+       move = 2;
       else
-       subtarget = target;
+       move = -1;
     }
-  /* Below, we must be careful to use copy_rtx on target and subtarget
-     in intermediate insns, as they may be a subreg rtx, which may not
-     be shared.  */
 
-  if (f == 0 && exact_log2 (diff) > 0
-      /* On EV6, we've got enough shifters to make non-arithmetic shifts
-        viable over a longer latency cmove.  On EV5, the E0 slot is a
-        scarce resource, and on EV4 shift has the same latency as a cmove.  */
-      && (diff <= 8 || alpha_cpu == PROCESSOR_EV6))
-    {
-      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+  if (move < 0)
+    emit_move_insn (operands[0], operands[2]);
 
-      tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget),
-                           GEN_INT (exact_log2 (t)));
-      emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
-    }
-  else if (f == 0 && t == -1)
-    {
-      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+  /* ??? 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 (gen_negdi2 (target, copy_rtx (subtarget)));
-    }
-  else if (diff == 1 || diff == 4 || diff == 8)
+  emit_insn ((*operation) (scratch, high_bit, operands[3]));
+
+  if (move > 0)
     {
-      rtx add_op;
+      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:
 
-      tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
+           unsigned:                       signed:
+   word:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
+           ldq_u  r2,X+1(r11)              ldq_u  r2,X+1(r11)
+           lda    r3,X(r11)                lda    r3,X+2(r11)
+           extwl  r1,r3,r1                 extql  r1,r3,r1
+           extwh  r2,r3,r2                 extqh  r2,r3,r2
+           or     r1.r2.r1                 or     r1,r2,r1
+                                           sra    r1,48,r1
 
-      if (diff == 1)
-       emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f)));
+   long:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
+           ldq_u  r2,X+3(r11)              ldq_u  r2,X+3(r11)
+           lda    r3,X(r11)                lda    r3,X(r11)
+           extll  r1,r3,r1                 extll  r1,r3,r1
+           extlh  r2,r3,r2                 extlh  r2,r3,r2
+           or     r1.r2.r1                 addl   r1,r2,r1
+
+   quad:   ldq_u  r1,X(r11)
+           ldq_u  r2,X+7(r11)
+           lda    r3,X(r11)
+           extql  r1,r3,r1
+           extqh  r2,r3,r2
+           or     r1.r2.r1
+*/
+
+void
+alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
+                            HOST_WIDE_INT ofs, int sign)
+{
+  rtx meml, memh, addr, extl, exth, tmp, mema;
+  enum machine_mode mode;
+
+  if (TARGET_BWX && size == 2)
+    {
+      meml = adjust_address (mem, QImode, ofs);
+      memh = adjust_address (mem, QImode, ofs+1);
+      if (BYTES_BIG_ENDIAN)
+       tmp = meml, meml = memh, memh = tmp;
+      extl = gen_reg_rtx (DImode);
+      exth = gen_reg_rtx (DImode);
+      emit_insn (gen_zero_extendqidi2 (extl, meml));
+      emit_insn (gen_zero_extendqidi2 (exth, memh));
+      exth = expand_simple_binop (DImode, ASHIFT, exth, GEN_INT (8),
+                                 NULL, 1, OPTAB_LIB_WIDEN);
+      addr = expand_simple_binop (DImode, IOR, extl, exth,
+                                 NULL, 1, OPTAB_LIB_WIDEN);
+
+      if (sign && GET_MODE (tgt) != HImode)
+       {
+         addr = gen_lowpart (HImode, addr);
+         emit_insn (gen_extend_insn (tgt, addr, GET_MODE (tgt), HImode, 0));
+       }
       else
        {
-         add_op = GEN_INT (f);
-         if (sext_add_operand (add_op, mode))
-           {
-             tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget),
-                                 GEN_INT (diff));
-             tmp = gen_rtx_PLUS (DImode, tmp, add_op);
-             emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
-           }
-         else
-           return 0;
+         if (GET_MODE (tgt) != DImode)
+           addr = gen_lowpart (GET_MODE (tgt), addr);
+         emit_move_insn (tgt, addr);
        }
+      return;
     }
-  else
-    return 0;
 
-  return 1;
-}
-\f
-/* Look up the function X_floating library function name for the
-   given operation.  */
+  meml = gen_reg_rtx (DImode);
+  memh = gen_reg_rtx (DImode);
+  addr = gen_reg_rtx (DImode);
+  extl = gen_reg_rtx (DImode);
+  exth = gen_reg_rtx (DImode);
 
-struct xfloating_op GTY(())
-{
-  const enum rtx_code code;
-  const char *const GTY((skip)) osf_func;
-  const char *const GTY((skip)) vms_func;
-  rtx libcall;
-};
+  mema = XEXP (mem, 0);
+  if (GET_CODE (mema) == LO_SUM)
+    mema = force_reg (Pmode, mema);
 
-static GTY(()) struct xfloating_op xfloating_ops[] = 
-{
-  { PLUS,              "_OtsAddX", "OTS$ADD_X", 0 },
-  { MINUS,             "_OtsSubX", "OTS$SUB_X", 0 },
-  { MULT,              "_OtsMulX", "OTS$MUL_X", 0 },
-  { DIV,               "_OtsDivX", "OTS$DIV_X", 0 },
-  { EQ,                        "_OtsEqlX", "OTS$EQL_X", 0 },
-  { NE,                        "_OtsNeqX", "OTS$NEQ_X", 0 },
-  { LT,                        "_OtsLssX", "OTS$LSS_X", 0 },
-  { LE,                        "_OtsLeqX", "OTS$LEQ_X", 0 },
-  { GT,                        "_OtsGtrX", "OTS$GTR_X", 0 },
-  { GE,                        "_OtsGeqX", "OTS$GEQ_X", 0 },
-  { FIX,               "_OtsCvtXQ", "OTS$CVTXQ", 0 },
-  { FLOAT,             "_OtsCvtQX", "OTS$CVTQX", 0 },
-  { UNSIGNED_FLOAT,    "_OtsCvtQUX", "OTS$CVTQUX", 0 },
-  { FLOAT_EXTEND,      "_OtsConvertFloatTX", "OTS$CVT_FLOAT_T_X", 0 },
-  { FLOAT_TRUNCATE,    "_OtsConvertFloatXT", "OTS$CVT_FLOAT_X_T", 0 }
-};
+  /* 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.  */
 
-static GTY(()) struct xfloating_op vax_cvt_ops[] =
-{
-  { FLOAT_EXTEND,      "_OtsConvertFloatGX", "OTS$CVT_FLOAT_G_X", 0 },
-  { FLOAT_TRUNCATE,    "_OtsConvertFloatXG", "OTS$CVT_FLOAT_X_G", 0 }
-};
+  tmp = change_address (mem, DImode,
+                       gen_rtx_AND (DImode,
+                                    plus_constant (mema, ofs),
+                                    GEN_INT (-8)));
+  set_mem_alias_set (tmp, 0);
+  emit_move_insn (meml, tmp);
 
-static rtx
-alpha_lookup_xfloating_lib_func (enum rtx_code code)
-{
-  struct xfloating_op *ops = xfloating_ops;
-  long n = ARRAY_SIZE (xfloating_ops);
-  long i;
+  tmp = change_address (mem, DImode,
+                       gen_rtx_AND (DImode,
+                                    plus_constant (mema, ofs + size - 1),
+                                    GEN_INT (-8)));
+  set_mem_alias_set (tmp, 0);
+  emit_move_insn (memh, tmp);
 
-  /* How irritating.  Nothing to key off for the main table.  */
-  if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE))
+  if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4))
     {
-      ops = vax_cvt_ops;
-      n = ARRAY_SIZE (vax_cvt_ops);
+      emit_move_insn (addr, plus_constant (mema, -1));
+
+      emit_insn (gen_extqh_be (extl, meml, addr));
+      emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr));
+
+      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8),
+                          addr, 1, OPTAB_WIDEN);
     }
+  else if (sign && size == 2)
+    {
+      emit_move_insn (addr, plus_constant (mema, ofs+2));
 
-  for (i = 0; i < n; ++i, ++ops)
-    if (ops->code == code)
-      {
-       rtx func = ops->libcall;
-       if (!func)
-         {
-           func = init_one_libfunc (TARGET_ABI_OPEN_VMS
-                                    ? ops->vms_func : ops->osf_func);
-           ops->libcall = func;
-         }
-        return func;
-      }
+      emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr));
+      emit_insn (gen_extqh_le (exth, memh, addr));
 
-  abort();
-}
+      /* We must use tgt here for the target.  Alpha-vms port fails if we use
+        addr for the target, because addr is marked as a pointer and combine
+        knows that pointers are always sign-extended 32 bit values.  */
+      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48),
+                          addr, 1, OPTAB_WIDEN);
+    }
+  else
+    {
+      if (WORDS_BIG_ENDIAN)
+       {
+         emit_move_insn (addr, plus_constant (mema, ofs+size-1));
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_extwh_be (extl, meml, addr));
+             mode = HImode;
+             break;
 
-/* Most X_floating operations take the rounding mode as an argument.
-   Compute that here.  */
+           case 4:
+             emit_insn (gen_extlh_be (extl, meml, addr));
+             mode = SImode;
+             break;
 
-static int
-alpha_compute_xfloating_mode_arg (enum rtx_code code,
-                                 enum alpha_fp_rounding_mode round)
-{
-  int mode;
+           case 8:
+             emit_insn (gen_extqh_be (extl, meml, addr));
+             mode = DImode;
+             break;
 
-  switch (round)
-    {
-    case ALPHA_FPRM_NORM:
-      mode = 2;
-      break;
-    case ALPHA_FPRM_MINF:
-      mode = 1;
-      break;
-    case ALPHA_FPRM_CHOP:
-      mode = 0;
-      break;
-    case ALPHA_FPRM_DYN:
-      mode = 4;
-      break;
-    default:
-      abort ();
+           default:
+             gcc_unreachable ();
+           }
+         emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr));
+       }
+      else
+       {
+         emit_move_insn (addr, plus_constant (mema, ofs));
+         emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr));
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_extwh_le (exth, memh, addr));
+             mode = HImode;
+             break;
 
-    /* XXX For reference, round to +inf is mode = 3.  */
-    }
+           case 4:
+             emit_insn (gen_extlh_le (exth, memh, addr));
+             mode = SImode;
+             break;
 
-  if (code == FLOAT_TRUNCATE && alpha_fptm == ALPHA_FPTM_N)
-    mode |= 0x10000;
+           case 8:
+             emit_insn (gen_extqh_le (exth, memh, addr));
+             mode = DImode;
+             break;
 
-  return mode;
-}
+           default:
+             gcc_unreachable ();
+           }
+       }
 
-/* Emit an X_floating library function call.
+      addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl),
+                          gen_lowpart (mode, exth), gen_lowpart (mode, tgt),
+                          sign, OPTAB_WIDEN);
+    }
 
-   Note that these functions do not follow normal calling conventions:
-   TFmode arguments are passed in two integer registers (as opposed to
-   indirect); TFmode return values appear in R16+R17. 
+  if (addr != tgt)
+    emit_move_insn (tgt, gen_lowpart (GET_MODE (tgt), addr));
+}
 
-   FUNC is the function to call.
-   TARGET is where the output belongs.
-   OPERANDS are the inputs.
-   NOPERANDS is the count of inputs.
-   EQUIV is the expression equivalent for the function.
-*/
+/* Similarly, use ins and msk instructions to perform unaligned stores.  */
 
-static void
-alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
-                             int noperands, rtx equiv)
+void
+alpha_expand_unaligned_store (rtx dst, rtx src,
+                             HOST_WIDE_INT size, HOST_WIDE_INT ofs)
 {
-  rtx usage = NULL_RTX, tmp, reg;
-  int regno = 16, i;
-
-  start_sequence ();
+  rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
 
-  for (i = 0; i < noperands; ++i)
+  if (TARGET_BWX && size == 2)
     {
-      switch (GET_MODE (operands[i]))
+      if (src != const0_rtx)
        {
-       case TFmode:
-         reg = gen_rtx_REG (TFmode, regno);
-         regno += 2;
-         break;
+         dstl = gen_lowpart (QImode, src);
+         dsth = expand_simple_binop (DImode, LSHIFTRT, src, GEN_INT (8),
+                                     NULL, 1, OPTAB_LIB_WIDEN);
+         dsth = gen_lowpart (QImode, dsth);
+       }
+      else
+       dstl = dsth = const0_rtx;
 
-       case DFmode:
-         reg = gen_rtx_REG (DFmode, regno + 32);
-         regno += 1;
-         break;
+      meml = adjust_address (dst, QImode, ofs);
+      memh = adjust_address (dst, QImode, ofs+1);
+      if (BYTES_BIG_ENDIAN)
+       addr = meml, meml = memh, memh = addr;
 
-       case VOIDmode:
-         if (GET_CODE (operands[i]) != CONST_INT)
-           abort ();
-         /* FALLTHRU */
-       case DImode:
-         reg = gen_rtx_REG (DImode, regno);
-         regno += 1;
-         break;
-
-       default:
-         abort ();
-       }
-
-      emit_move_insn (reg, operands[i]);
-      usage = alloc_EXPR_LIST (0, gen_rtx_USE (VOIDmode, reg), usage);
-    }
-
-  switch (GET_MODE (target))
-    {
-    case TFmode:
-      reg = gen_rtx_REG (TFmode, 16);
-      break;
-    case DFmode:
-      reg = gen_rtx_REG (DFmode, 32);
-      break;
-    case DImode:
-      reg = gen_rtx_REG (DImode, 0);
-      break;
-    default:
-      abort ();
+      emit_move_insn (meml, dstl);
+      emit_move_insn (memh, dsth);
+      return;
     }
 
-  tmp = gen_rtx_MEM (QImode, func);
-  tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
-                                       const0_rtx, const0_rtx));
-  CALL_INSN_FUNCTION_USAGE (tmp) = usage;
-  CONST_OR_PURE_CALL_P (tmp) = 1;
-
-  tmp = get_insns ();
-  end_sequence ();
-
-  emit_libcall_block (tmp, target, reg, equiv);
-}
-
-/* Emit an X_floating library function call for arithmetic (+,-,*,/).  */
-
-void
-alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[])
-{
-  rtx func;
-  int mode;
-  rtx out_operands[3];
-
-  func = alpha_lookup_xfloating_lib_func (code);
-  mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
-
-  out_operands[0] = operands[1];
-  out_operands[1] = operands[2];
-  out_operands[2] = GEN_INT (mode);
-  alpha_emit_xfloating_libcall (func, operands[0], out_operands, 3,  
-                               gen_rtx_fmt_ee (code, TFmode, operands[1],
-                                               operands[2]));
-}
+  dstl = gen_reg_rtx (DImode);
+  dsth = gen_reg_rtx (DImode);
+  insl = gen_reg_rtx (DImode);
+  insh = gen_reg_rtx (DImode);
 
-/* Emit an X_floating library function call for a comparison.  */
+  dsta = XEXP (dst, 0);
+  if (GET_CODE (dsta) == LO_SUM)
+    dsta = force_reg (Pmode, dsta);
 
-static rtx
-alpha_emit_xfloating_compare (enum rtx_code code, rtx op0, rtx op1)
-{
-  rtx func;
-  rtx out, operands[2];
+  /* 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.  */
 
-  func = alpha_lookup_xfloating_lib_func (code);
+  meml = change_address (dst, DImode,
+                        gen_rtx_AND (DImode,
+                                     plus_constant (dsta, ofs),
+                                     GEN_INT (-8)));
+  set_mem_alias_set (meml, 0);
 
-  operands[0] = op0;
-  operands[1] = op1;
-  out = gen_reg_rtx (DImode);
+  memh = change_address (dst, DImode,
+                        gen_rtx_AND (DImode,
+                                     plus_constant (dsta, ofs + size - 1),
+                                     GEN_INT (-8)));
+  set_mem_alias_set (memh, 0);
 
-  /* ??? Strange mode for equiv because what's actually returned
-     is -1,0,1, not a proper boolean value.  */
-  alpha_emit_xfloating_libcall (func, out, operands, 2,
-                               gen_rtx_fmt_ee (code, CCmode, op0, op1));
+  emit_move_insn (dsth, memh);
+  emit_move_insn (dstl, meml);
+  if (WORDS_BIG_ENDIAN)
+    {
+      addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1));
 
-  return out;
-}
+      if (src != const0_rtx)
+       {
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr));
+             break;
+           case 4:
+             emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr));
+             break;
+           case 8:
+             emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr));
+             break;
+           }
+         emit_insn (gen_insxh (insl, gen_lowpart (DImode, src),
+                               GEN_INT (size*8), addr));
+       }
 
-/* Emit an X_floating library function call for a conversion.  */
+      switch ((int) size)
+       {
+       case 2:
+         emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr));
+         break;
+       case 4:
+         {
+           rtx msk = immed_double_const (0xffffffff, 0, DImode);
+           emit_insn (gen_mskxl_be (dsth, dsth, msk, addr));
+           break;
+         }
+       case 8:
+         emit_insn (gen_mskxl_be (dsth, dsth, constm1_rtx, addr));
+         break;
+       }
 
-void
-alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[])
-{
-  int noperands = 1, mode;
-  rtx out_operands[2];
-  rtx func;
-  enum rtx_code code = orig_code;
+      emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr));
+    }
+  else
+    {
+      addr = copy_addr_to_reg (plus_constant (dsta, ofs));
 
-  if (code == UNSIGNED_FIX)
-    code = FIX;
+      if (src != CONST0_RTX (GET_MODE (src)))
+       {
+         emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
+                               GEN_INT (size*8), addr));
 
-  func = alpha_lookup_xfloating_lib_func (code);
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr));
+             break;
+           case 4:
+             emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr));
+             break;
+           case 8:
+             emit_insn (gen_insql_le (insl, src, addr));
+             break;
+           }
+       }
 
-  out_operands[0] = operands[1];
+      emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
 
-  switch (code)
-    {
-    case FIX:
-      mode = alpha_compute_xfloating_mode_arg (code, ALPHA_FPRM_CHOP);
-      out_operands[1] = GEN_INT (mode);
-      noperands = 2;
-      break;
-    case FLOAT_TRUNCATE:
-      mode = alpha_compute_xfloating_mode_arg (code, alpha_fprm);
-      out_operands[1] = GEN_INT (mode);
-      noperands = 2;
-      break;
-    default:
-      break;
+      switch ((int) size)
+       {
+       case 2:
+         emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr));
+         break;
+       case 4:
+         {
+           rtx msk = immed_double_const (0xffffffff, 0, DImode);
+           emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
+           break;
+         }
+       case 8:
+         emit_insn (gen_mskxl_le (dstl, dstl, constm1_rtx, addr));
+         break;
+       }
     }
 
-  alpha_emit_xfloating_libcall (func, operands[0], out_operands, noperands,
-                               gen_rtx_fmt_e (orig_code,
-                                              GET_MODE (operands[0]),
-                                              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 (rtx operands[4])
-{
-  if (GET_CODE (operands[1]) == REG)
-    {
-      operands[3] = gen_rtx_REG (DImode, REGNO (operands[1]) + 1);
-      operands[2] = gen_rtx_REG (DImode, REGNO (operands[1]));
-    }
-  else if (GET_CODE (operands[1]) == MEM)
+  if (src != CONST0_RTX (GET_MODE (src)))
     {
-      operands[3] = adjust_address (operands[1], DImode, 8);
-      operands[2] = adjust_address (operands[1], DImode, 0);
+      dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
+      dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
     }
-  else if (operands[1] == CONST0_RTX (TFmode))
-    operands[2] = operands[3] = const0_rtx;
-  else
-    abort ();
 
-  if (GET_CODE (operands[0]) == REG)
+  if (WORDS_BIG_ENDIAN)
     {
-      operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1);
-      operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
+      emit_move_insn (meml, dstl);
+      emit_move_insn (memh, dsth);
     }
-  else if (GET_CODE (operands[0]) == MEM)
+  else
     {
-      operands[1] = adjust_address (operands[0], DImode, 8);
-      operands[0] = adjust_address (operands[0], DImode, 0);
+      /* Must store high before low for degenerate case of aligned.  */
+      emit_move_insn (memh, dsth);
+      emit_move_insn (meml, dstl);
     }
-  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.  */
+/* The block move code tries to maximize speed by separating loads and
+   stores at the expense of register pressure: we load all of the data
+   before we store it back out.  There are two secondary effects worth
+   mentioning, that this speeds copying to/from aligned and unaligned
+   buffers, and that it makes the code significantly easier to write.  */
 
-void
-alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx))
+#define MAX_MOVE_WORDS 8
+
+/* Load an integral number of consecutive unaligned quadwords.  */
+
+static void
+alpha_expand_unaligned_load_words (rtx *out_regs, rtx smem,
+                                  HOST_WIDE_INT words, HOST_WIDE_INT ofs)
 {
-  rtx high_bit = operands[2];
-  rtx scratch;
-  int move;
+  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, tmp, smema;
+  HOST_WIDE_INT i;
 
-  alpha_split_tfmode_pair (operands);
+  smema = XEXP (smem, 0);
+  if (GET_CODE (smema) == LO_SUM)
+    smema = force_reg (Pmode, smema);
 
-  /* Detect three flavors of operand overlap.  */
-  move = 1;
-  if (rtx_equal_p (operands[0], operands[2]))
-    move = 0;
-  else if (rtx_equal_p (operands[1], operands[2]))
+  /* Generate all the tmp registers we need.  */
+  for (i = 0; i < words; ++i)
     {
-      if (rtx_equal_p (operands[0], high_bit))
-       move = 2;
-      else
-       move = -1;
+      data_regs[i] = out_regs[i];
+      ext_tmps[i] = gen_reg_rtx (DImode);
     }
+  data_regs[words] = gen_reg_rtx (DImode);
 
-  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 (ofs != 0)
+    smem = adjust_address (smem, GET_MODE (smem), ofs);
 
-  if (move > 0)
+  /* Load up all of the source data.  */
+  for (i = 0; i < words; ++i)
     {
-      emit_move_insn (operands[0], operands[2]);
-      if (move > 1)
-       emit_move_insn (operands[1], scratch);
+      tmp = change_address (smem, DImode,
+                           gen_rtx_AND (DImode,
+                                        plus_constant (smema, 8*i),
+                                        im8));
+      set_mem_alias_set (tmp, 0);
+      emit_move_insn (data_regs[i], tmp);
     }
-}
-\f
-/* Use ext[wlq][lh] as the Architecture Handbook describes for extracting
-   unaligned data:
-
-           unsigned:                       signed:
-   word:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
-           ldq_u  r2,X+1(r11)              ldq_u  r2,X+1(r11)
-           lda    r3,X(r11)                lda    r3,X+2(r11)
-           extwl  r1,r3,r1                 extql  r1,r3,r1
-           extwh  r2,r3,r2                 extqh  r2,r3,r2
-           or     r1.r2.r1                 or     r1,r2,r1
-                                           sra    r1,48,r1
-
-   long:   ldq_u  r1,X(r11)                ldq_u  r1,X(r11)
-           ldq_u  r2,X+3(r11)              ldq_u  r2,X+3(r11)
-           lda    r3,X(r11)                lda    r3,X(r11)
-           extll  r1,r3,r1                 extll  r1,r3,r1
-           extlh  r2,r3,r2                 extlh  r2,r3,r2
-           or     r1.r2.r1                 addl   r1,r2,r1
-
-   quad:   ldq_u  r1,X(r11)
-           ldq_u  r2,X+7(r11)
-           lda    r3,X(r11)
-           extql  r1,r3,r1
-           extqh  r2,r3,r2
-           or     r1.r2.r1
-*/
-
-void
-alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
-                            HOST_WIDE_INT ofs, int sign)
-{
-  rtx meml, memh, addr, extl, exth, tmp, mema;
-  enum machine_mode mode;
-
-  meml = gen_reg_rtx (DImode);
-  memh = gen_reg_rtx (DImode);
-  addr = gen_reg_rtx (DImode);
-  extl = gen_reg_rtx (DImode);
-  exth = gen_reg_rtx (DImode);
-
-  mema = XEXP (mem, 0);
-  if (GET_CODE (mema) == LO_SUM)
-    mema = force_reg (Pmode, mema);
-
-  /* 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 (mema, ofs),
-                                    GEN_INT (-8)));
-  set_mem_alias_set (tmp, 0);
-  emit_move_insn (meml, tmp);
 
-  tmp = change_address (mem, DImode,
-                       gen_rtx_AND (DImode, 
-                                    plus_constant (mema, ofs + size - 1),
-                                    GEN_INT (-8)));
+  tmp = change_address (smem, DImode,
+                       gen_rtx_AND (DImode,
+                                    plus_constant (smema, 8*words - 1),
+                                    im8));
   set_mem_alias_set (tmp, 0);
-  emit_move_insn (memh, tmp);
-
-  if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4))
-    {
-      emit_move_insn (addr, plus_constant (mema, -1));
-
-      emit_insn (gen_extqh_be (extl, meml, addr));
-      emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr));
-
-      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
-      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8),
-                          addr, 1, OPTAB_WIDEN);
-    }
-  else if (sign && size == 2)
-    {
-      emit_move_insn (addr, plus_constant (mema, ofs+2));
+  emit_move_insn (data_regs[words], tmp);
 
-      emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr));
-      emit_insn (gen_extqh_le (exth, memh, addr));
+  /* Extract the half-word fragments.  Unfortunately DEC decided to make
+     extxh with offset zero a noop instead of zeroing the register, so
+     we must take care of that edge condition ourselves with cmov.  */
 
-      /* We must use tgt here for the target.  Alpha-vms port fails if we use
-        addr for the target, because addr is marked as a pointer and combine
-        knows that pointers are always sign-extended 32 bit values.  */
-      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
-      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (48), 
-                          addr, 1, OPTAB_WIDEN);
-    }
-  else
+  sreg = copy_addr_to_reg (smema);
+  areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL,
+                      1, OPTAB_WIDEN);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (sreg, plus_constant (sreg, 7));
+  for (i = 0; i < words; ++i)
     {
       if (WORDS_BIG_ENDIAN)
        {
-         emit_move_insn (addr, plus_constant (mema, ofs+size-1));
-         switch ((int) size)
-           {
-           case 2:
-             emit_insn (gen_extwh_be (extl, meml, addr));
-             mode = HImode;
-             break;
-
-           case 4:
-             emit_insn (gen_extlh_be (extl, meml, addr));
-             mode = SImode;
-             break;
-
-           case 8:
-             emit_insn (gen_extqh_be (extl, meml, addr));
-             mode = DImode;
-             break;
-
-           default:
-             abort ();
-           }
-         emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr));
+         emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg));
+         emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg));
        }
       else
        {
-         emit_move_insn (addr, plus_constant (mema, ofs));
-         emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr));
-         switch ((int) size)
-           {
-           case 2:
-             emit_insn (gen_extwh_le (exth, memh, addr));
-             mode = HImode;
-             break;
-
-           case 4:
-             emit_insn (gen_extlh_le (exth, memh, addr));
-             mode = SImode;
-             break;
-
-           case 8:
-             emit_insn (gen_extqh_le (exth, memh, addr));
-             mode = DImode;
-             break;
-
-           default:
-             abort();
-           }
+         emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg));
+         emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg));
        }
-
-      addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl),
-                          gen_lowpart (mode, exth), gen_lowpart (mode, tgt),
-                          sign, OPTAB_WIDEN);
+      emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i],
+                             gen_rtx_IF_THEN_ELSE (DImode,
+                                                   gen_rtx_EQ (DImode, areg,
+                                                               const0_rtx),
+                                                   const0_rtx, ext_tmps[i])));
     }
 
-  if (addr != tgt)
-    emit_move_insn (tgt, gen_lowpart(GET_MODE (tgt), addr));
+  /* Merge the half-words into whole words.  */
+  for (i = 0; i < words; ++i)
+    {
+      out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i],
+                                 ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN);
+    }
 }
 
-/* Similarly, use ins and msk instructions to perform unaligned stores.  */
+/* Store an integral number of consecutive unaligned quadwords.  DATA_REGS
+   may be NULL to store zeros.  */
 
-void
-alpha_expand_unaligned_store (rtx dst, rtx src,
-                             HOST_WIDE_INT size, HOST_WIDE_INT ofs)
+static void
+alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem,
+                                   HOST_WIDE_INT words, HOST_WIDE_INT ofs)
 {
-  rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
-  
-  dstl = gen_reg_rtx (DImode);
-  dsth = gen_reg_rtx (DImode);
-  insl = gen_reg_rtx (DImode);
-  insh = gen_reg_rtx (DImode);
+  rtx const im8 = GEN_INT (-8);
+  rtx const i64 = GEN_INT (64);
+  rtx ins_tmps[MAX_MOVE_WORDS];
+  rtx st_tmp_1, st_tmp_2, dreg;
+  rtx st_addr_1, st_addr_2, dmema;
+  HOST_WIDE_INT i;
 
-  dsta = XEXP (dst, 0);
-  if (GET_CODE (dsta) == LO_SUM)
-    dsta = force_reg (Pmode, dsta);
+  dmema = XEXP (dmem, 0);
+  if (GET_CODE (dmema) == LO_SUM)
+    dmema = force_reg (Pmode, dmema);
 
-  /* 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.  */
+  /* Generate all the tmp registers we need.  */
+  if (data_regs != NULL)
+    for (i = 0; i < words; ++i)
+      ins_tmps[i] = gen_reg_rtx(DImode);
+  st_tmp_1 = gen_reg_rtx(DImode);
+  st_tmp_2 = gen_reg_rtx(DImode);
 
-  meml = change_address (dst, DImode,
-                        gen_rtx_AND (DImode, 
-                                     plus_constant (dsta, ofs),
-                                     GEN_INT (-8)));
-  set_mem_alias_set (meml, 0);
+  if (ofs != 0)
+    dmem = adjust_address (dmem, GET_MODE (dmem), ofs);
 
-  memh = change_address (dst, DImode,
-                        gen_rtx_AND (DImode, 
-                                     plus_constant (dsta, ofs + size - 1),
-                                     GEN_INT (-8)));
-  set_mem_alias_set (memh, 0);
+  st_addr_2 = change_address (dmem, DImode,
+                             gen_rtx_AND (DImode,
+                                          plus_constant (dmema, words*8 - 1),
+                                      im8));
+  set_mem_alias_set (st_addr_2, 0);
 
-  emit_move_insn (dsth, memh);
-  emit_move_insn (dstl, meml);
+  st_addr_1 = change_address (dmem, DImode,
+                             gen_rtx_AND (DImode, dmema, im8));
+  set_mem_alias_set (st_addr_1, 0);
+
+  /* Load up the destination end bits.  */
+  emit_move_insn (st_tmp_2, st_addr_2);
+  emit_move_insn (st_tmp_1, st_addr_1);
+
+  /* Shift the input data into place.  */
+  dreg = copy_addr_to_reg (dmema);
   if (WORDS_BIG_ENDIAN)
+    emit_move_insn (dreg, plus_constant (dreg, 7));
+  if (data_regs != NULL)
     {
-      addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1));
-
-      if (src != const0_rtx)
+      for (i = words-1; i >= 0; --i)
        {
-         switch ((int) size)
-           {
-           case 2:
-             emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr));
-             break;
-           case 4:
-             emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr));
-             break;
-           case 8:
-             emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr));
-             break;
-           }
-         emit_insn (gen_insxh (insl, gen_lowpart (DImode, src),
-                               GEN_INT (size*8), addr));
-       }
-
-      switch ((int) size)
-       {
-       case 2:
-         emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr));
-         break;
-       case 4:
-         {
-           rtx msk = immed_double_const (0xffffffff, 0, DImode);
-           emit_insn (gen_mskxl_be (dsth, dsth, msk, addr));
-           break;
-         }
-       case 8:
-         emit_insn (gen_mskxl_be (dsth, dsth, constm1_rtx, addr));
-         break;
-       }
-
-      emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr));
-    }
-  else
-    {
-      addr = copy_addr_to_reg (plus_constant (dsta, ofs));
-
-      if (src != const0_rtx)
-       {
-         emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
-                               GEN_INT (size*8), addr));
-
-         switch ((int) size)
-           {
-           case 2:
-             emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr));
-             break;
-           case 4:
-             emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr));
-             break;
-           case 8:
-             emit_insn (gen_insql_le (insl, src, addr));
-             break;
-           }
-       }
-
-      emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
-
-      switch ((int) size)
-       {
-       case 2:
-         emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr));
-         break;
-       case 4:
-         {
-           rtx msk = immed_double_const (0xffffffff, 0, DImode);
-           emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
-           break;
-         }
-       case 8:
-         emit_insn (gen_mskxl_le (dstl, dstl, constm1_rtx, addr));
-         break;
-       }
-    }
-
-  if (src != const0_rtx)
-    {
-      dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
-      dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
-    }
-  if (WORDS_BIG_ENDIAN)
-    {
-      emit_move_insn (meml, dstl);
-      emit_move_insn (memh, dsth);
-    }
-  else
-    {
-      /* Must store high before low for degenerate case of aligned.  */
-      emit_move_insn (memh, dsth);
-      emit_move_insn (meml, dstl);
-    }
-}
-
-/* The block move code tries to maximize speed by separating loads and
-   stores at the expense of register pressure: we load all of the data
-   before we store it back out.  There are two secondary effects worth
-   mentioning, that this speeds copying to/from aligned and unaligned
-   buffers, and that it makes the code significantly easier to write.  */
-
-#define MAX_MOVE_WORDS 8
-
-/* Load an integral number of consecutive unaligned quadwords.  */
-
-static void
-alpha_expand_unaligned_load_words (rtx *out_regs, rtx smem,
-                                  HOST_WIDE_INT words, HOST_WIDE_INT 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, tmp, smema;
-  HOST_WIDE_INT i;
-
-  smema = XEXP (smem, 0);
-  if (GET_CODE (smema) == LO_SUM)
-    smema = force_reg (Pmode, smema);
-
-  /* Generate all the tmp registers we need.  */
-  for (i = 0; i < words; ++i)
-    {
-      data_regs[i] = out_regs[i];
-      ext_tmps[i] = gen_reg_rtx (DImode);
-    }
-  data_regs[words] = gen_reg_rtx (DImode);
-
-  if (ofs != 0)
-    smem = adjust_address (smem, GET_MODE (smem), ofs);
-  
-  /* Load up all of the source data.  */
-  for (i = 0; i < words; ++i)
-    {
-      tmp = change_address (smem, DImode,
-                           gen_rtx_AND (DImode,
-                                        plus_constant (smema, 8*i),
-                                        im8));
-      set_mem_alias_set (tmp, 0);
-      emit_move_insn (data_regs[i], tmp);
-    }
-
-  tmp = change_address (smem, DImode,
-                       gen_rtx_AND (DImode,
-                                    plus_constant (smema, 8*words - 1),
-                                    im8));
-  set_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 
-     we must take care of that edge condition ourselves with cmov.  */
-
-  sreg = copy_addr_to_reg (smema);
-  areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, 
-                      1, OPTAB_WIDEN);
-  if (WORDS_BIG_ENDIAN)
-    emit_move_insn (sreg, plus_constant (sreg, 7));
-  for (i = 0; i < words; ++i)
-    {
-      if (WORDS_BIG_ENDIAN)
-       {
-         emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg));
-         emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg));
-       }
-      else
-       {
-         emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg));
-         emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg));
-       }
-      emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i],
-                             gen_rtx_IF_THEN_ELSE (DImode,
-                                                   gen_rtx_EQ (DImode, areg,
-                                                               const0_rtx),
-                                                   const0_rtx, ext_tmps[i])));
-    }
-
-  /* Merge the half-words into whole words.  */
-  for (i = 0; i < words; ++i)
-    {
-      out_regs[i] = expand_binop (DImode, ior_optab, data_regs[i],
-                                 ext_tmps[i], data_regs[i], 1, OPTAB_WIDEN);
-    }
-}
-
-/* Store an integral number of consecutive unaligned quadwords.  DATA_REGS
-   may be NULL to store zeros.  */
-
-static void
-alpha_expand_unaligned_store_words (rtx *data_regs, rtx dmem,
-                                   HOST_WIDE_INT words, HOST_WIDE_INT ofs)
-{
-  rtx const im8 = GEN_INT (-8);
-  rtx const i64 = GEN_INT (64);
-  rtx ins_tmps[MAX_MOVE_WORDS];
-  rtx st_tmp_1, st_tmp_2, dreg;
-  rtx st_addr_1, st_addr_2, dmema;
-  HOST_WIDE_INT i;
-
-  dmema = XEXP (dmem, 0);
-  if (GET_CODE (dmema) == LO_SUM)
-    dmema = force_reg (Pmode, dmema);
-
-  /* Generate all the tmp registers we need.  */
-  if (data_regs != NULL)
-    for (i = 0; i < words; ++i)
-      ins_tmps[i] = gen_reg_rtx(DImode);
-  st_tmp_1 = gen_reg_rtx(DImode);
-  st_tmp_2 = gen_reg_rtx(DImode);
-  
-  if (ofs != 0)
-    dmem = adjust_address (dmem, GET_MODE (dmem), ofs);
-
-  st_addr_2 = change_address (dmem, DImode,
-                             gen_rtx_AND (DImode,
-                                          plus_constant (dmema, words*8 - 1),
-                                      im8));
-  set_mem_alias_set (st_addr_2, 0);
-
-  st_addr_1 = change_address (dmem, DImode,
-                             gen_rtx_AND (DImode, dmema, im8));
-  set_mem_alias_set (st_addr_1, 0);
-
-  /* Load up the destination end bits.  */
-  emit_move_insn (st_tmp_2, st_addr_2);
-  emit_move_insn (st_tmp_1, st_addr_1);
-
-  /* Shift the input data into place.  */
-  dreg = copy_addr_to_reg (dmema);
-  if (WORDS_BIG_ENDIAN)
-    emit_move_insn (dreg, plus_constant (dreg, 7));
-  if (data_regs != NULL)
-    {
-      for (i = words-1; i >= 0; --i)
-       {
-         if (WORDS_BIG_ENDIAN)
+         if (WORDS_BIG_ENDIAN)
            {
              emit_insn (gen_insql_be (ins_tmps[i], data_regs[i], dreg));
              emit_insn (gen_insxh (data_regs[i], data_regs[i], i64, dreg));
@@ -4415,7 +3875,7 @@ alpha_expand_block_move (rtx operands[])
   rtx data_regs[2 * MAX_MOVE_WORDS + 16];
   rtx tmp;
   unsigned int i, words, ofs, nregs = 0;
-  
+
   if (orig_bytes <= 0)
     return 1;
   else if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
@@ -4443,7 +3903,7 @@ alpha_expand_block_move (rtx operands[])
            src_align = 16;
        }
     }
-       
+
   tmp = XEXP (orig_dst, 0);
   if (GET_CODE (tmp) == REG)
     dst_align = MAX (dst_align, REGNO_POINTER_ALIGN (REGNO (tmp)));
@@ -4549,8 +4009,7 @@ alpha_expand_block_move (rtx operands[])
       ofs += 1;
     }
 
-  if (nregs > ARRAY_SIZE (data_regs))
-    abort ();
+  gcc_assert (nregs <= ARRAY_SIZE (data_regs));
 
   /* Now save it back out again.  */
 
@@ -4607,7 +4066,7 @@ alpha_expand_block_move (rtx operands[])
       else
         alpha_expand_unaligned_store_words (data_regs + i, orig_dst,
                                            words, ofs);
-     
+
       i += words;
       ofs += words * 8;
     }
@@ -4637,16 +4096,15 @@ alpha_expand_block_move (rtx operands[])
        ofs += 2;
       }
 
-  while (i < nregs && GET_MODE (data_regs[i]) == QImode)
+  /* The remainder must be byte copies.  */
+  while (i < nregs)
     {
+      gcc_assert (GET_MODE (data_regs[i]) == QImode);
       emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]);
       i++;
       ofs += 1;
     }
 
-  if (i != nregs)
-    abort ();
-
   return 1;
 }
 
@@ -4662,7 +4120,7 @@ alpha_expand_block_clear (rtx operands[])
   rtx orig_dst = operands[0];
   rtx tmp;
   int i, words, ofs = 0;
-  
+
   if (orig_bytes <= 0)
     return 1;
   if (orig_bytes > MAX_MOVE_WORDS * UNITS_PER_WORD)
@@ -4944,10 +4402,12 @@ alpha_expand_zap_mask (HOST_WIDE_INT value)
 
       result = gen_int_mode (mask, DImode);
     }
-  else if (HOST_BITS_PER_WIDE_INT == 32)
+  else
     {
       HOST_WIDE_INT mask_lo = 0, mask_hi = 0;
 
+      gcc_assert (HOST_BITS_PER_WIDE_INT == 32);
+      
       for (i = 7; i >= 4; --i)
        {
          mask_hi <<= 8;
@@ -4964,8 +4424,6 @@ alpha_expand_zap_mask (HOST_WIDE_INT value)
 
       result = immed_double_const (mask_lo, mask_hi, DImode);
     }
-  else
-    abort ();
 
   return result;
 }
@@ -4989,27 +4447,85 @@ alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
 
   emit_insn ((*gen) (op0, op1, op2));
 }
-\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.  */
 
-static int
-alpha_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
+/* Expand an an atomic fetch-and-operate pattern.  CODE is the binary operation
+   to perform.  MEM is the memory on which to operate.  VAL is the second 
+   operand of the binary operator.  BEFORE and AFTER are optional locations to
+   return the value of MEM either before of after the operation.  SCRATCH is
+   a scratch register.  */
+
+void
+alpha_split_atomic_op (enum rtx_code code, rtx mem, rtx val,
+                      rtx before, rtx after, rtx scratch)
 {
-  enum attr_type insn_type, dep_insn_type;
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label, cond, x;
+  rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
 
-  /* If the dependence is an anti-dependence, there is no cost.  For an
-     output dependence, there is sometimes a cost, but it doesn't seem
-     worth handling those few cases.  */
-  if (REG_NOTE_KIND (link) != 0)
-    return cost;
+  emit_insn (gen_memory_barrier ());
 
-  /* If we can't recognize the insns, we can't really do anything.  */
-  if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
-    return cost;
+  label = gen_label_rtx ();
+  emit_label (label);
+  label = gen_rtx_LABEL_REF (DImode, label);
 
-  insn_type = get_attr_type (insn);
-  dep_insn_type = get_attr_type (dep_insn);
+  if (before == NULL)
+    before = scratch;
+
+  if (mode == SImode)
+    emit_insn (gen_load_locked_si (before, mem));
+  else if (mode == DImode)
+    emit_insn (gen_load_locked_di (before, mem));
+  else
+    gcc_unreachable ();
+
+  if (code == NOT)
+    {
+      x = gen_rtx_NOT (mode, before);
+      x = gen_rtx_AND (mode, x, val);
+    }
+  else
+    x = gen_rtx_fmt_ee (code, mode, before, val);
+
+  if (after)
+    emit_insn (gen_rtx_SET (VOIDmode, after, copy_rtx (x)));
+  emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+
+  cond = gen_rtx_REG (DImode, REGNO (scratch));
+  if (mode == SImode)
+    emit_insn (gen_store_conditional_si (cond, mem, scratch));
+  else if (mode == DImode)
+    emit_insn (gen_store_conditional_di (cond, mem, scratch));
+  else
+    gcc_unreachable ();
+
+  x = gen_rtx_EQ (DImode, cond, const0_rtx);
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, x, label, pc_rtx);
+  x = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, x));
+  REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_BR_PROB, very_unlikely, NULL_RTX);
+
+  emit_insn (gen_memory_barrier ());
+}
+\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.  */
+
+static int
+alpha_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
+{
+  enum attr_type insn_type, dep_insn_type;
+
+  /* If the dependence is an anti-dependence, there is no cost.  For an
+     output dependence, there is sometimes a cost, but it doesn't seem
+     worth handling those few cases.  */
+  if (REG_NOTE_KIND (link) != 0)
+    return cost;
+
+  /* If we can't recognize the insns, we can't really do anything.  */
+  if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
+    return cost;
+
+  insn_type = get_attr_type (insn);
+  dep_insn_type = get_attr_type (dep_insn);
 
   /* Bring in the user-defined memory latency.  */
   if (dep_insn_type == TYPE_ILD
@@ -5027,7 +4543,7 @@ alpha_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
 static int
 alpha_issue_rate (void)
 {
-  return (alpha_cpu == PROCESSOR_EV4 ? 2 : 4);
+  return (alpha_tune == PROCESSOR_EV4 ? 2 : 4);
 }
 
 /* How many alternative schedules to try.  This should be as wide as the
@@ -5041,7 +4557,7 @@ alpha_issue_rate (void)
 static int
 alpha_multipass_dfa_lookahead (void)
 {
-  return (alpha_cpu == PROCESSOR_EV6 ? 4 : 2);
+  return (alpha_tune == PROCESSOR_EV6 ? 4 : 2);
 }
 \f
 /* Machine-specific function data.  */
@@ -5069,7 +4585,7 @@ struct machine_function GTY(())
 static struct machine_function *
 alpha_init_machine_status (void)
 {
-  return ((struct machine_function *) 
+  return ((struct machine_function *)
                ggc_alloc_cleared (sizeof (struct machine_function)));
 }
 
@@ -5161,8 +4677,9 @@ get_trap_mode_suffix (void)
        case ALPHA_FPTM_SU:
        case ALPHA_FPTM_SUI:
          return "sv";
+       default:
+         gcc_unreachable ();
        }
-      break;
 
     case TRAP_SUFFIX_V_SV_SVI:
       switch (alpha_fptm)
@@ -5175,6 +4692,8 @@ get_trap_mode_suffix (void)
          return "sv";
        case ALPHA_FPTM_SUI:
          return "svi";
+       default:
+         gcc_unreachable ();
        }
       break;
 
@@ -5189,10 +4708,15 @@ get_trap_mode_suffix (void)
          return "su";
        case ALPHA_FPTM_SUI:
          return "sui";
+       default:
+         gcc_unreachable ();
        }
       break;
+      
+    default:
+      gcc_unreachable ();
     }
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Return the rounding mode suffix applicable to the current
@@ -5212,19 +4736,24 @@ get_round_mode_suffix (void)
        {
        case ALPHA_FPRM_NORM:
          return NULL;
-       case ALPHA_FPRM_MINF: 
+       case ALPHA_FPRM_MINF:
          return "m";
        case ALPHA_FPRM_CHOP:
          return "c";
        case ALPHA_FPRM_DYN:
          return "d";
+       default:
+         gcc_unreachable ();
        }
       break;
 
     case ROUND_SUFFIX_C:
       return "c";
+      
+    default:
+      gcc_unreachable ();
     }
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Locate some local-dynamic symbol still in use by this function
@@ -5258,7 +4787,7 @@ get_some_local_dynamic_name (void)
        && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
       return cfun->machine->some_ld_name;
 
-  abort ();
+  gcc_unreachable ();
 }
 
 /* Print an operand.  Recognize special options, documented below.  */
@@ -5501,7 +5030,7 @@ print_operand (FILE *file, rtx x, int code)
       if (GET_CODE (x) != CONST_INT
          || (unsigned HOST_WIDE_INT) INTVAL (x) >= (WORDS_BIG_ENDIAN
                                                     ? 56
-                                                    : 64)  
+                                                    : 64)
          || (INTVAL (x) & 7) != 0)
        output_operand_lossage ("invalid %%s value");
 
@@ -5665,48 +5194,58 @@ print_operand_address (FILE *file, rtx addr)
 
       if (offset)
        fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
-      
+
       addr = XEXP (addr, 0);
-      if (GET_CODE (addr) == REG)
-       basereg = REGNO (addr);
-      else if (GET_CODE (addr) == SUBREG
-              && GET_CODE (SUBREG_REG (addr)) == REG)
-       basereg = subreg_regno (addr);
-      else
-       abort ();
+      switch (GET_CODE (addr))
+       {
+       case REG:
+         basereg = REGNO (addr);
+         break;
+
+       case SUBREG:
+         basereg = subreg_regno (addr);
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
 
       fprintf (file, "($%d)\t\t!%s", basereg,
               (basereg == 29 ? reloc16 : reloclo));
       return;
     }
 
-  if (GET_CODE (addr) == REG)
-    basereg = REGNO (addr);
-  else if (GET_CODE (addr) == SUBREG
-          && GET_CODE (SUBREG_REG (addr)) == REG)
-    basereg = subreg_regno (addr);
-  else if (GET_CODE (addr) == CONST_INT)
-    offset = INTVAL (addr);
+  switch (GET_CODE (addr))
+    {
+    case REG:
+      basereg = REGNO (addr);
+      break;
+
+    case SUBREG:
+      basereg = subreg_regno (addr);
+      break;
+
+    case CONST_INT:
+      offset = INTVAL (addr);
+      break;
 
 #if TARGET_ABI_OPEN_VMS
-  else if (GET_CODE (addr) == SYMBOL_REF)
-    {
+    case SYMBOL_REF:
       fprintf (file, "%s", XSTR (addr, 0));
       return;
-    }
-  else if (GET_CODE (addr) == CONST
-          && GET_CODE (XEXP (addr, 0)) == PLUS
-          && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF)
-    {
+
+    case CONST:
+      gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS
+                 && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF);
       fprintf (file, "%s+" HOST_WIDE_INT_PRINT_DEC,
               XSTR (XEXP (XEXP (addr, 0), 0), 0),
               INTVAL (XEXP (XEXP (addr, 0), 1)));
       return;
-    }
+    
 #endif
-
-  else
-    abort ();
+    default:
+      gcc_unreachable ();
+    }
 
   fprintf (file, HOST_WIDE_INT_PRINT_DEC "($%d)", offset, basereg);
 }
@@ -5716,7 +5255,7 @@ print_operand_address (FILE *file, rtx addr)
    code.  CXT is an RTX for the static chain value for the function.
 
    The three offset parameters are for the individual template's
-   layout.  A JMPOFS < 0 indicates that the trampoline does not 
+   layout.  A JMPOFS < 0 indicates that the trampoline does not
    contain instructions at all.
 
    We assume here that a function will be called many more times than
@@ -5752,7 +5291,7 @@ alpha_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt,
       temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1,
                           OPTAB_WIDEN);
       temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
-                          build_int_2 (2, 0), NULL_RTX, 1);
+                          build_int_cst (NULL_TREE, 2), NULL_RTX, 1);
       temp = expand_and (SImode, gen_lowpart (SImode, temp),
                         GEN_INT (0x3fff), 0);
 
@@ -5805,8 +5344,7 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
 #ifdef ENABLE_CHECKING
       /* With alpha_split_complex_arg, we shouldn't see any raw complex
         values here.  */
-      if (COMPLEX_MODE_P (mode))
-       abort ();
+      gcc_assert (!COMPLEX_MODE_P (mode));
 #endif
 
       /* Set up defaults for FP operands passed in FP registers, and
@@ -5913,6 +5451,31 @@ function_arg (CUMULATIVE_ARGS cum, enum machine_mode mode, tree type,
   return gen_rtx_REG (mode, num_args + basereg);
 }
 
+static int
+alpha_arg_partial_bytes (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
+                        enum machine_mode mode ATTRIBUTE_UNUSED,
+                        tree type ATTRIBUTE_UNUSED,
+                        bool named ATTRIBUTE_UNUSED)
+{
+  int words = 0;
+
+#if TARGET_ABI_OPEN_VMS
+  if (cum->num_args < 6
+      && 6 < cum->num_args + ALPHA_ARG_SIZE (mode, type, named))
+    words = 6 - (CUM).num_args;
+#elif TARGET_ABI_UNICOSMK
+  /* Never any split arguments.  */
+#elif TARGET_ABI_OSF
+  if (*cum < 6 && 6 < *cum + ALPHA_ARG_SIZE (mode, type, named))
+    words = 6 - *cum;
+#else
+#error Unhandled ABI
+#endif
+
+  return words * UNITS_PER_WORD;
+}
+
+
 /* Return true if TYPE must be returned in memory, instead of in registers.  */
 
 static bool
@@ -5950,9 +5513,10 @@ alpha_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
       break;
 
     default:
-      /* ??? We get called on all sorts of random stuff from 
-        aggregate_value_p.  We can't abort, but it's not clear
-        what's safe to return.  Pretend it's a struct I guess.  */
+      /* ??? We get called on all sorts of random stuff from
+        aggregate_value_p.  We must return something, but it's not
+        clear what's safe to return.  Pretend it's a struct I
+        guess.  */
       return true;
     }
 
@@ -5976,662 +5540,1318 @@ alpha_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
    called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0.
    MODE is set instead of VALTYPE for libcalls.
 
-   On Alpha the value is found in $0 for integer functions and
-   $f0 for floating-point functions.  */
+   On Alpha the value is found in $0 for integer functions and
+   $f0 for floating-point functions.  */
+
+rtx
+function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+               enum machine_mode mode)
+{
+  unsigned int regnum, dummy;
+  enum mode_class class;
+
+  gcc_assert (!valtype || !alpha_return_in_memory (valtype, func));
+
+  if (valtype)
+    mode = TYPE_MODE (valtype);
+
+  class = GET_MODE_CLASS (mode);
+  switch (class)
+    {
+    case MODE_INT:
+      PROMOTE_MODE (mode, dummy, valtype);
+      /* FALLTHRU */
+
+    case MODE_COMPLEX_INT:
+    case MODE_VECTOR_INT:
+      regnum = 0;
+      break;
+
+    case MODE_FLOAT:
+      regnum = 32;
+      break;
+
+    case MODE_COMPLEX_FLOAT:
+      {
+       enum machine_mode cmode = GET_MODE_INNER (mode);
+
+       return gen_rtx_PARALLEL
+         (VOIDmode,
+          gen_rtvec (2,
+                     gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32),
+                                        const0_rtx),
+                     gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33),
+                                        GEN_INT (GET_MODE_SIZE (cmode)))));
+      }
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return gen_rtx_REG (mode, regnum);
+}
+
+/* TCmode complex values are passed by invisible reference.  We
+   should not split these values.  */
+
+static bool
+alpha_split_complex_arg (tree type)
+{
+  return TYPE_MODE (type) != TCmode;
+}
+
+static tree
+alpha_build_builtin_va_list (void)
+{
+  tree base, ofs, space, record, type_decl;
+
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
+    return ptr_type_node;
+
+  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
+  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
+  TREE_CHAIN (record) = type_decl;
+  TYPE_NAME (record) = type_decl;
+
+  /* C++? SET_IS_AGGR_TYPE (record, 1); */
+
+  /* Dummy field to prevent alignment warnings.  */
+  space = build_decl (FIELD_DECL, NULL_TREE, integer_type_node);
+  DECL_FIELD_CONTEXT (space) = record;
+  DECL_ARTIFICIAL (space) = 1;
+  DECL_IGNORED_P (space) = 1;
+
+  ofs = build_decl (FIELD_DECL, get_identifier ("__offset"),
+                   integer_type_node);
+  DECL_FIELD_CONTEXT (ofs) = record;
+  TREE_CHAIN (ofs) = space;
+
+  base = build_decl (FIELD_DECL, get_identifier ("__base"),
+                    ptr_type_node);
+  DECL_FIELD_CONTEXT (base) = record;
+  TREE_CHAIN (base) = ofs;
+
+  TYPE_FIELDS (record) = base;
+  layout_type (record);
+
+  va_list_gpr_counter_field = ofs;
+  return record;
+}
+
+#if TARGET_ABI_OSF
+/* Helper function for alpha_stdarg_optimize_hook.  Skip over casts
+   and constant additions.  */
+
+static tree
+va_list_skip_additions (tree lhs)
+{
+  tree rhs, stmt;
+
+  if (TREE_CODE (lhs) != SSA_NAME)
+    return lhs;
+
+  for (;;)
+    {
+      stmt = SSA_NAME_DEF_STMT (lhs);
+
+      if (TREE_CODE (stmt) == PHI_NODE)
+       return stmt;
+
+      if (TREE_CODE (stmt) != MODIFY_EXPR
+         || TREE_OPERAND (stmt, 0) != lhs)
+       return lhs;
+
+      rhs = TREE_OPERAND (stmt, 1);
+      if (TREE_CODE (rhs) == WITH_SIZE_EXPR)
+       rhs = TREE_OPERAND (rhs, 0);
+
+      if ((TREE_CODE (rhs) != NOP_EXPR
+          && TREE_CODE (rhs) != CONVERT_EXPR
+          && (TREE_CODE (rhs) != PLUS_EXPR
+              || TREE_CODE (TREE_OPERAND (rhs, 1)) != INTEGER_CST
+              || !host_integerp (TREE_OPERAND (rhs, 1), 1)))
+         || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME)
+       return rhs;
+
+      lhs = TREE_OPERAND (rhs, 0);
+    }
+}
+
+/* Check if LHS = RHS statement is
+   LHS = *(ap.__base + ap.__offset + cst)
+   or
+   LHS = *(ap.__base
+          + ((ap.__offset + cst <= 47)
+             ? ap.__offset + cst - 48 : ap.__offset + cst) + cst2).
+   If the former, indicate that GPR registers are needed,
+   if the latter, indicate that FPR registers are needed.
+   On alpha, cfun->va_list_gpr_size is used as size of the needed
+   regs and cfun->va_list_fpr_size is a bitmask, bit 0 set if
+   GPR registers are needed and bit 1 set if FPR registers are needed.
+   Return true if va_list references should not be scanned for the current
+   statement.  */
+
+static bool
+alpha_stdarg_optimize_hook (struct stdarg_info *si, tree lhs, tree rhs)
+{
+  tree base, offset, arg1, arg2;
+  int offset_arg = 1;
+
+  if (TREE_CODE (rhs) != INDIRECT_REF
+      || TREE_CODE (TREE_OPERAND (rhs, 0)) != SSA_NAME)
+    return false;
+
+  lhs = va_list_skip_additions (TREE_OPERAND (rhs, 0));
+  if (lhs == NULL_TREE
+      || TREE_CODE (lhs) != PLUS_EXPR)
+    return false;
+
+  base = TREE_OPERAND (lhs, 0);
+  if (TREE_CODE (base) == SSA_NAME)
+    base = va_list_skip_additions (base);
+
+  if (TREE_CODE (base) != COMPONENT_REF
+      || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node))
+    {
+      base = TREE_OPERAND (lhs, 0);
+      if (TREE_CODE (base) == SSA_NAME)
+       base = va_list_skip_additions (base);
+
+      if (TREE_CODE (base) != COMPONENT_REF
+         || TREE_OPERAND (base, 1) != TYPE_FIELDS (va_list_type_node))
+       return false;
+
+      offset_arg = 0;
+    }
+
+  base = get_base_address (base);
+  if (TREE_CODE (base) != VAR_DECL
+      || !bitmap_bit_p (si->va_list_vars, var_ann (base)->uid))
+    return false;
+
+  offset = TREE_OPERAND (lhs, offset_arg);
+  if (TREE_CODE (offset) == SSA_NAME)
+    offset = va_list_skip_additions (offset);
+
+  if (TREE_CODE (offset) == PHI_NODE)
+    {
+      HOST_WIDE_INT sub;
+
+      if (PHI_NUM_ARGS (offset) != 2)
+       goto escapes;
+
+      arg1 = va_list_skip_additions (PHI_ARG_DEF (offset, 0));
+      arg2 = va_list_skip_additions (PHI_ARG_DEF (offset, 1));
+      if (TREE_CODE (arg2) != MINUS_EXPR && TREE_CODE (arg2) != PLUS_EXPR)
+       {
+         tree tem = arg1;
+         arg1 = arg2;
+         arg2 = tem;
+
+         if (TREE_CODE (arg2) != MINUS_EXPR && TREE_CODE (arg2) != PLUS_EXPR)
+           goto escapes;
+       }
+      if (!host_integerp (TREE_OPERAND (arg2, 1), 0))
+       goto escapes;
+
+      sub = tree_low_cst (TREE_OPERAND (arg2, 1), 0);
+      if (TREE_CODE (arg2) == MINUS_EXPR)
+       sub = -sub;
+      if (sub < -48 || sub > -32)
+       goto escapes;
+
+      arg2 = va_list_skip_additions (TREE_OPERAND (arg2, 0));
+      if (arg1 != arg2)
+       goto escapes;
+
+      if (TREE_CODE (arg1) == SSA_NAME)
+       arg1 = va_list_skip_additions (arg1);
+
+      if (TREE_CODE (arg1) != COMPONENT_REF
+         || TREE_OPERAND (arg1, 1) != va_list_gpr_counter_field
+         || get_base_address (arg1) != base)
+       goto escapes;
+
+      /* Need floating point regs.  */
+      cfun->va_list_fpr_size |= 2;
+    }
+  else if (TREE_CODE (offset) != COMPONENT_REF
+          || TREE_OPERAND (offset, 1) != va_list_gpr_counter_field
+          || get_base_address (offset) != base)
+    goto escapes;
+  else
+    /* Need general regs.  */
+    cfun->va_list_fpr_size |= 1;
+  return false;
+
+escapes:
+  si->va_list_escapes = true;
+  return false;
+}
+#endif
+
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments.  */
+
+static void
+alpha_setup_incoming_varargs (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
+                             tree type, int *pretend_size, int no_rtl)
+{
+  CUMULATIVE_ARGS cum = *pcum;
+
+  /* Skip the current argument.  */
+  FUNCTION_ARG_ADVANCE (cum, mode, type, 1);
+
+#if TARGET_ABI_UNICOSMK
+  /* On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register
+     arguments on the stack. Unfortunately, it doesn't always store the first
+     one (i.e. the one that arrives in $16 or $f16). This is not a problem
+     with stdargs as we always have at least one named argument there.  */
+  if (cum.num_reg_words < 6)
+    {
+      if (!no_rtl)
+       {
+         emit_insn (gen_umk_mismatch_args (GEN_INT (cum.num_reg_words)));
+         emit_insn (gen_arg_home_umk ());
+       }
+      *pretend_size = 0;
+    }
+#elif TARGET_ABI_OPEN_VMS
+  /* For VMS, we allocate space for all 6 arg registers plus a count.
+
+     However, if NO registers need to be saved, don't allocate any space.
+     This is not only because we won't need the space, but because AP
+     includes the current_pretend_args_size and we don't want to mess up
+     any ap-relative addresses already made.  */
+  if (cum.num_args < 6)
+    {
+      if (!no_rtl)
+       {
+         emit_move_insn (gen_rtx_REG (DImode, 1), virtual_incoming_args_rtx);
+         emit_insn (gen_arg_home ());
+       }
+      *pretend_size = 7 * UNITS_PER_WORD;
+    }
+#else
+  /* On OSF/1 and friends, we allocate space for all 12 arg registers, but
+     only push those that are remaining.  However, if NO registers need to
+     be saved, don't allocate any space.  This is not only because we won't
+     need the space, but because AP includes the current_pretend_args_size
+     and we don't want to mess up any ap-relative addresses already made.
+
+     If we are not to use the floating-point registers, save the integer
+     registers where we would put the floating-point registers.  This is
+     not the most efficient way to implement varargs with just one register
+     class, but it isn't worth doing anything more efficient in this rare
+     case.  */
+  if (cum >= 6)
+    return;
+
+  if (!no_rtl)
+    {
+      int count, set = get_varargs_alias_set ();
+      rtx tmp;
+
+      count = cfun->va_list_gpr_size / UNITS_PER_WORD;
+      if (count > 6 - cum)
+       count = 6 - cum;
+
+      /* Detect whether integer registers or floating-point registers
+        are needed by the detected va_arg statements.  See above for
+        how these values are computed.  Note that the "escape" value
+        is VA_LIST_MAX_FPR_SIZE, which is 255, which has both of 
+        these bits set.  */
+      gcc_assert ((VA_LIST_MAX_FPR_SIZE & 3) == 3);
+
+      if (cfun->va_list_fpr_size & 1)
+       {
+         tmp = gen_rtx_MEM (BLKmode,
+                            plus_constant (virtual_incoming_args_rtx,
+                                           (cum + 6) * UNITS_PER_WORD));
+         set_mem_alias_set (tmp, set);
+         move_block_from_reg (16 + cum, tmp, count);
+       }
+
+      if (cfun->va_list_fpr_size & 2)
+       {
+         tmp = gen_rtx_MEM (BLKmode,
+                            plus_constant (virtual_incoming_args_rtx,
+                                           cum * UNITS_PER_WORD));
+         set_mem_alias_set (tmp, set);
+         move_block_from_reg (16 + cum + TARGET_FPREGS*32, tmp, count);
+       }
+     }
+  *pretend_size = 12 * UNITS_PER_WORD;
+#endif
+}
+
+void
+alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
+{
+  HOST_WIDE_INT offset;
+  tree t, offset_field, base_field;
+
+  if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK)
+    return;
+
+  if (TARGET_ABI_UNICOSMK)
+    std_expand_builtin_va_start (valist, nextarg);
+
+  /* For Unix, TARGET_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.
+
+     If no integer registers need be stored, then we must subtract 48
+     in order to account for the integer arg registers which are counted
+     in argsize above, but which are not actually stored on the stack.
+     Must further be careful here about structures straddling the last
+     integer argument register; that futzes with pretend_args_size,
+     which changes the meaning of AP.  */
+
+  if (NUM_ARGS < 6)
+    offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD;
+  else
+    offset = -6 * UNITS_PER_WORD + current_function_pretend_args_size;
+
+  if (TARGET_ABI_OPEN_VMS)
+    {
+      nextarg = plus_constant (nextarg, offset);
+      nextarg = plus_constant (nextarg, NUM_ARGS * UNITS_PER_WORD);
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+                make_tree (ptr_type_node, nextarg));
+      TREE_SIDE_EFFECTS (t) = 1;
+
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
+  else
+    {
+      base_field = TYPE_FIELDS (TREE_TYPE (valist));
+      offset_field = TREE_CHAIN (base_field);
+
+      base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+                         valist, base_field, NULL_TREE);
+      offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+                           valist, offset_field, NULL_TREE);
+
+      t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
+      t = build (PLUS_EXPR, ptr_type_node, t,
+                build_int_cst (NULL_TREE, offset));
+      t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      t = build_int_cst (NULL_TREE, NUM_ARGS * UNITS_PER_WORD);
+      t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
+}
+
+static tree
+alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
+{
+  tree type_size, ptr_type, addend, t, addr, internal_post;
+
+  /* If the type could not be passed in registers, skip the block
+     reserved for the registers.  */
+  if (targetm.calls.must_pass_in_stack (TYPE_MODE (type), type))
+    {
+      t = build_int_cst (TREE_TYPE (offset), 6*8);
+      t = build (MODIFY_EXPR, TREE_TYPE (offset), offset,
+                build (MAX_EXPR, TREE_TYPE (offset), offset, t));
+      gimplify_and_add (t, pre_p);
+    }
+
+  addend = offset;
+  ptr_type = build_pointer_type (type);
+
+  if (TREE_CODE (type) == COMPLEX_TYPE)
+    {
+      tree real_part, imag_part, real_temp;
+
+      real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base,
+                                          offset, pre_p);
+
+      /* Copy the value into a new temporary, lest the formal temporary
+        be reused out from under us.  */
+      real_temp = get_initialized_tmp_var (real_part, pre_p, NULL);
+
+      imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base,
+                                          offset, pre_p);
+
+      return build (COMPLEX_EXPR, type, real_temp, imag_part);
+    }
+  else if (TREE_CODE (type) == REAL_TYPE)
+    {
+      tree fpaddend, cond, fourtyeight;
+
+      fourtyeight = build_int_cst (TREE_TYPE (addend), 6*8);
+      fpaddend = fold (build (MINUS_EXPR, TREE_TYPE (addend),
+                             addend, fourtyeight));
+      cond = fold (build (LT_EXPR, boolean_type_node, addend, fourtyeight));
+      addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond,
+                           fpaddend, addend));
+    }
+
+  /* Build the final address and force that value into a temporary.  */
+  addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
+               fold_convert (ptr_type, addend));
+  internal_post = NULL;
+  gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue);
+  append_to_statement_list (internal_post, pre_p);
+
+  /* Update the offset field.  */
+  type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+  if (type_size == NULL || TREE_OVERFLOW (type_size))
+    t = size_zero_node;
+  else
+    {
+      t = size_binop (PLUS_EXPR, type_size, size_int (7));
+      t = size_binop (TRUNC_DIV_EXPR, t, size_int (8));
+      t = size_binop (MULT_EXPR, t, size_int (8));
+    }
+  t = fold_convert (TREE_TYPE (offset), t);
+  t = build (MODIFY_EXPR, void_type_node, offset,
+            build (PLUS_EXPR, TREE_TYPE (offset), offset, t));
+  gimplify_and_add (t, pre_p);
+
+  return build_fold_indirect_ref (addr);
+}
+
+static tree
+alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+{
+  tree offset_field, base_field, offset, base, t, r;
+  bool indirect;
+
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
+    return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
+
+  base_field = TYPE_FIELDS (va_list_type_node);
+  offset_field = TREE_CHAIN (base_field);
+  base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+                     valist, base_field, NULL_TREE);
+  offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+                       valist, offset_field, NULL_TREE);
+
+  /* Pull the fields of the structure out into temporaries.  Since we never
+     modify the base field, we can use a formal temporary.  Sign-extend the
+     offset field so that it's the proper width for pointer arithmetic.  */
+  base = get_formal_tmp_var (base_field, pre_p);
+
+  t = fold_convert (lang_hooks.types.type_for_size (64, 0), offset_field);
+  offset = get_initialized_tmp_var (t, pre_p, NULL);
+
+  indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
+  if (indirect)
+    type = build_pointer_type (type);
+
+  /* Find the value.  Note that this will be a stable indirection, or
+     a composite of stable indirections in the case of complex.  */
+  r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p);
+
+  /* Stuff the offset temporary back into its field.  */
+  t = build (MODIFY_EXPR, void_type_node, offset_field,
+            fold_convert (TREE_TYPE (offset_field), offset));
+  gimplify_and_add (t, pre_p);
+
+  if (indirect)
+    r = build_fold_indirect_ref (r);
+
+  return r;
+}
+\f
+/* Builtins.  */
+
+enum alpha_builtin
+{
+  ALPHA_BUILTIN_CMPBGE,
+  ALPHA_BUILTIN_EXTBL,
+  ALPHA_BUILTIN_EXTWL,
+  ALPHA_BUILTIN_EXTLL,
+  ALPHA_BUILTIN_EXTQL,
+  ALPHA_BUILTIN_EXTWH,
+  ALPHA_BUILTIN_EXTLH,
+  ALPHA_BUILTIN_EXTQH,
+  ALPHA_BUILTIN_INSBL,
+  ALPHA_BUILTIN_INSWL,
+  ALPHA_BUILTIN_INSLL,
+  ALPHA_BUILTIN_INSQL,
+  ALPHA_BUILTIN_INSWH,
+  ALPHA_BUILTIN_INSLH,
+  ALPHA_BUILTIN_INSQH,
+  ALPHA_BUILTIN_MSKBL,
+  ALPHA_BUILTIN_MSKWL,
+  ALPHA_BUILTIN_MSKLL,
+  ALPHA_BUILTIN_MSKQL,
+  ALPHA_BUILTIN_MSKWH,
+  ALPHA_BUILTIN_MSKLH,
+  ALPHA_BUILTIN_MSKQH,
+  ALPHA_BUILTIN_UMULH,
+  ALPHA_BUILTIN_ZAP,
+  ALPHA_BUILTIN_ZAPNOT,
+  ALPHA_BUILTIN_AMASK,
+  ALPHA_BUILTIN_IMPLVER,
+  ALPHA_BUILTIN_RPCC,
+  ALPHA_BUILTIN_THREAD_POINTER,
+  ALPHA_BUILTIN_SET_THREAD_POINTER,
+
+  /* TARGET_MAX */
+  ALPHA_BUILTIN_MINUB8,
+  ALPHA_BUILTIN_MINSB8,
+  ALPHA_BUILTIN_MINUW4,
+  ALPHA_BUILTIN_MINSW4,
+  ALPHA_BUILTIN_MAXUB8,
+  ALPHA_BUILTIN_MAXSB8,
+  ALPHA_BUILTIN_MAXUW4,
+  ALPHA_BUILTIN_MAXSW4,
+  ALPHA_BUILTIN_PERR,
+  ALPHA_BUILTIN_PKLB,
+  ALPHA_BUILTIN_PKWB,
+  ALPHA_BUILTIN_UNPKBL,
+  ALPHA_BUILTIN_UNPKBW,
+
+  /* TARGET_CIX */
+  ALPHA_BUILTIN_CTTZ,
+  ALPHA_BUILTIN_CTLZ,
+  ALPHA_BUILTIN_CTPOP,
+
+  ALPHA_BUILTIN_max
+};
+
+static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = {
+  CODE_FOR_builtin_cmpbge,
+  CODE_FOR_builtin_extbl,
+  CODE_FOR_builtin_extwl,
+  CODE_FOR_builtin_extll,
+  CODE_FOR_builtin_extql,
+  CODE_FOR_builtin_extwh,
+  CODE_FOR_builtin_extlh,
+  CODE_FOR_builtin_extqh,
+  CODE_FOR_builtin_insbl,
+  CODE_FOR_builtin_inswl,
+  CODE_FOR_builtin_insll,
+  CODE_FOR_builtin_insql,
+  CODE_FOR_builtin_inswh,
+  CODE_FOR_builtin_inslh,
+  CODE_FOR_builtin_insqh,
+  CODE_FOR_builtin_mskbl,
+  CODE_FOR_builtin_mskwl,
+  CODE_FOR_builtin_mskll,
+  CODE_FOR_builtin_mskql,
+  CODE_FOR_builtin_mskwh,
+  CODE_FOR_builtin_msklh,
+  CODE_FOR_builtin_mskqh,
+  CODE_FOR_umuldi3_highpart,
+  CODE_FOR_builtin_zap,
+  CODE_FOR_builtin_zapnot,
+  CODE_FOR_builtin_amask,
+  CODE_FOR_builtin_implver,
+  CODE_FOR_builtin_rpcc,
+  CODE_FOR_load_tp,
+  CODE_FOR_set_tp,
+
+  /* TARGET_MAX */
+  CODE_FOR_builtin_minub8,
+  CODE_FOR_builtin_minsb8,
+  CODE_FOR_builtin_minuw4,
+  CODE_FOR_builtin_minsw4,
+  CODE_FOR_builtin_maxub8,
+  CODE_FOR_builtin_maxsb8,
+  CODE_FOR_builtin_maxuw4,
+  CODE_FOR_builtin_maxsw4,
+  CODE_FOR_builtin_perr,
+  CODE_FOR_builtin_pklb,
+  CODE_FOR_builtin_pkwb,
+  CODE_FOR_builtin_unpkbl,
+  CODE_FOR_builtin_unpkbw,
+
+  /* TARGET_CIX */
+  CODE_FOR_ctzdi2,
+  CODE_FOR_clzdi2,
+  CODE_FOR_popcountdi2
+};
+
+struct alpha_builtin_def
+{
+  const char *name;
+  enum alpha_builtin code;
+  unsigned int target_mask;
+  bool is_const;
+};
+
+static struct alpha_builtin_def const zero_arg_builtins[] = {
+  { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER,  0, true },
+  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0, false }
+};
+
+static struct alpha_builtin_def const one_arg_builtins[] = {
+  { "__builtin_alpha_amask",   ALPHA_BUILTIN_AMASK,    0, true },
+  { "__builtin_alpha_pklb",    ALPHA_BUILTIN_PKLB,     MASK_MAX, true },
+  { "__builtin_alpha_pkwb",    ALPHA_BUILTIN_PKWB,     MASK_MAX, true },
+  { "__builtin_alpha_unpkbl",  ALPHA_BUILTIN_UNPKBL,   MASK_MAX, true },
+  { "__builtin_alpha_unpkbw",  ALPHA_BUILTIN_UNPKBW,   MASK_MAX, true },
+  { "__builtin_alpha_cttz",    ALPHA_BUILTIN_CTTZ,     MASK_CIX, true },
+  { "__builtin_alpha_ctlz",    ALPHA_BUILTIN_CTLZ,     MASK_CIX, true },
+  { "__builtin_alpha_ctpop",   ALPHA_BUILTIN_CTPOP,    MASK_CIX, true }
+};
+
+static struct alpha_builtin_def const two_arg_builtins[] = {
+  { "__builtin_alpha_cmpbge",  ALPHA_BUILTIN_CMPBGE,   0, true },
+  { "__builtin_alpha_extbl",   ALPHA_BUILTIN_EXTBL,    0, true },
+  { "__builtin_alpha_extwl",   ALPHA_BUILTIN_EXTWL,    0, true },
+  { "__builtin_alpha_extll",   ALPHA_BUILTIN_EXTLL,    0, true },
+  { "__builtin_alpha_extql",   ALPHA_BUILTIN_EXTQL,    0, true },
+  { "__builtin_alpha_extwh",   ALPHA_BUILTIN_EXTWH,    0, true },
+  { "__builtin_alpha_extlh",   ALPHA_BUILTIN_EXTLH,    0, true },
+  { "__builtin_alpha_extqh",   ALPHA_BUILTIN_EXTQH,    0, true },
+  { "__builtin_alpha_insbl",   ALPHA_BUILTIN_INSBL,    0, true },
+  { "__builtin_alpha_inswl",   ALPHA_BUILTIN_INSWL,    0, true },
+  { "__builtin_alpha_insll",   ALPHA_BUILTIN_INSLL,    0, true },
+  { "__builtin_alpha_insql",   ALPHA_BUILTIN_INSQL,    0, true },
+  { "__builtin_alpha_inswh",   ALPHA_BUILTIN_INSWH,    0, true },
+  { "__builtin_alpha_inslh",   ALPHA_BUILTIN_INSLH,    0, true },
+  { "__builtin_alpha_insqh",   ALPHA_BUILTIN_INSQH,    0, true },
+  { "__builtin_alpha_mskbl",   ALPHA_BUILTIN_MSKBL,    0, true },
+  { "__builtin_alpha_mskwl",   ALPHA_BUILTIN_MSKWL,    0, true },
+  { "__builtin_alpha_mskll",   ALPHA_BUILTIN_MSKLL,    0, true },
+  { "__builtin_alpha_mskql",   ALPHA_BUILTIN_MSKQL,    0, true },
+  { "__builtin_alpha_mskwh",   ALPHA_BUILTIN_MSKWH,    0, true },
+  { "__builtin_alpha_msklh",   ALPHA_BUILTIN_MSKLH,    0, true },
+  { "__builtin_alpha_mskqh",   ALPHA_BUILTIN_MSKQH,    0, true },
+  { "__builtin_alpha_umulh",   ALPHA_BUILTIN_UMULH,    0, true },
+  { "__builtin_alpha_zap",     ALPHA_BUILTIN_ZAP,      0, true },
+  { "__builtin_alpha_zapnot",  ALPHA_BUILTIN_ZAPNOT,   0, true },
+  { "__builtin_alpha_minub8",  ALPHA_BUILTIN_MINUB8,   MASK_MAX, true },
+  { "__builtin_alpha_minsb8",  ALPHA_BUILTIN_MINSB8,   MASK_MAX, true },
+  { "__builtin_alpha_minuw4",  ALPHA_BUILTIN_MINUW4,   MASK_MAX, true },
+  { "__builtin_alpha_minsw4",  ALPHA_BUILTIN_MINSW4,   MASK_MAX, true },
+  { "__builtin_alpha_maxub8",  ALPHA_BUILTIN_MAXUB8,   MASK_MAX, true },
+  { "__builtin_alpha_maxsb8",  ALPHA_BUILTIN_MAXSB8,   MASK_MAX, true },
+  { "__builtin_alpha_maxuw4",  ALPHA_BUILTIN_MAXUW4,   MASK_MAX, true },
+  { "__builtin_alpha_maxsw4",  ALPHA_BUILTIN_MAXSW4,   MASK_MAX, true },
+  { "__builtin_alpha_perr",    ALPHA_BUILTIN_PERR,     MASK_MAX, true }
+};
 
-rtx
-function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
-               enum machine_mode mode)
-{
-  unsigned int regnum;
-  enum mode_class class;
+static GTY(()) tree alpha_v8qi_u;
+static GTY(()) tree alpha_v8qi_s;
+static GTY(()) tree alpha_v4hi_u;
+static GTY(()) tree alpha_v4hi_s;
 
-#ifdef ENABLE_CHECKING
-  if (valtype && alpha_return_in_memory (valtype, func))
-    abort ();
-#endif
+static void
+alpha_init_builtins (void)
+{
+  const struct alpha_builtin_def *p;
+  tree ftype, attrs[2];
+  size_t i;
 
-  if (valtype)
-    mode = TYPE_MODE (valtype);
+  attrs[0] = tree_cons (get_identifier ("nothrow"), NULL, NULL);
+  attrs[1] = tree_cons (get_identifier ("const"), NULL, attrs[0]);
 
-  class = GET_MODE_CLASS (mode);
-  switch (class)
-    {
-    case MODE_INT:
-      /* Do the same thing as PROMOTE_MODE.  */
-      mode = DImode;
-      /* FALLTHRU */
+  ftype = build_function_type (long_integer_type_node, void_list_node);
 
-    case MODE_COMPLEX_INT:
-    case MODE_VECTOR_INT:
-      regnum = 0;
-      break;
+  p = zero_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (zero_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                                  NULL, attrs[p->is_const]);
 
-    case MODE_FLOAT:
-      regnum = 32;
-      break;
+  ftype = build_function_type_list (long_integer_type_node,
+                                   long_integer_type_node, NULL_TREE);
 
-    case MODE_COMPLEX_FLOAT:
-      {
-       enum machine_mode cmode = GET_MODE_INNER (mode);
+  p = one_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (one_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                                  NULL, attrs[p->is_const]);
 
-       return gen_rtx_PARALLEL
-         (VOIDmode,
-          gen_rtvec (2,
-                     gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 32),
-                                        const0_rtx),
-                     gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (cmode, 33),
-                                        GEN_INT (GET_MODE_SIZE (cmode)))));
-      }
+  ftype = build_function_type_list (long_integer_type_node,
+                                   long_integer_type_node,
+                                   long_integer_type_node, NULL_TREE);
 
-    default:
-      abort ();
-    }
+  p = two_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (two_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                                  NULL, attrs[p->is_const]);
 
-  return gen_rtx_REG (mode, regnum);
-}
+  ftype = build_function_type (ptr_type_node, void_list_node);
+  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
+                              ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+                              NULL, attrs[0]);
 
-/* TCmode complex values are passed by invisible reference.  We 
-   should not split these values.  */
+  ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+  lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype,
+                              ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
+                              NULL, attrs[0]);
 
-static bool
-alpha_split_complex_arg (tree type)
-{
-  return TYPE_MODE (type) != TCmode;
+  alpha_v8qi_u = build_vector_type (unsigned_intQI_type_node, 8);
+  alpha_v8qi_s = build_vector_type (intQI_type_node, 8);
+  alpha_v4hi_u = build_vector_type (unsigned_intHI_type_node, 4);
+  alpha_v4hi_s = build_vector_type (intHI_type_node, 4);
 }
 
-static tree
-alpha_build_builtin_va_list (void)
-{
-  tree base, ofs, space, record, type_decl;
-
-  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
-    return ptr_type_node;
+/* Expand an expression EXP that calls a built-in function,
+   with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
 
-  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
-  type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
-  TREE_CHAIN (record) = type_decl;
-  TYPE_NAME (record) = type_decl;
+static rtx
+alpha_expand_builtin (tree exp, rtx target,
+                     rtx subtarget ATTRIBUTE_UNUSED,
+                     enum machine_mode mode ATTRIBUTE_UNUSED,
+                     int ignore ATTRIBUTE_UNUSED)
+{
+#define MAX_ARGS 2
 
-  /* C++? SET_IS_AGGR_TYPE (record, 1); */
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum insn_code icode;
+  rtx op[MAX_ARGS], pat;
+  int arity;
+  bool nonvoid;
 
-  /* Dummy field to prevent alignment warnings.  */
-  space = build_decl (FIELD_DECL, NULL_TREE, integer_type_node);
-  DECL_FIELD_CONTEXT (space) = record;
-  DECL_ARTIFICIAL (space) = 1;
-  DECL_IGNORED_P (space) = 1;
+  if (fcode >= ALPHA_BUILTIN_max)
+    internal_error ("bad builtin fcode");
+  icode = code_for_builtin[fcode];
+  if (icode == 0)
+    internal_error ("bad builtin fcode");
 
-  ofs = build_decl (FIELD_DECL, get_identifier ("__offset"),
-                   integer_type_node);
-  DECL_FIELD_CONTEXT (ofs) = record;
-  TREE_CHAIN (ofs) = space;
+  nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
 
-  base = build_decl (FIELD_DECL, get_identifier ("__base"),
-                    ptr_type_node);
-  DECL_FIELD_CONTEXT (base) = record;
-  TREE_CHAIN (base) = ofs;
+  for (arglist = TREE_OPERAND (exp, 1), arity = 0;
+       arglist;
+       arglist = TREE_CHAIN (arglist), arity++)
+    {
+      const struct insn_operand_data *insn_op;
 
-  TYPE_FIELDS (record) = base;
-  layout_type (record);
+      tree arg = TREE_VALUE (arglist);
+      if (arg == error_mark_node)
+       return NULL_RTX;
+      if (arity > MAX_ARGS)
+       return NULL_RTX;
 
-  return record;
-}
+      insn_op = &insn_data[icode].operand[arity + nonvoid];
 
-/* Perform any needed actions needed for a function that is receiving a
-   variable number of arguments.  */
+      op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0);
 
-static void
-alpha_setup_incoming_varargs (CUMULATIVE_ARGS *pcum,
-                             enum machine_mode mode ATTRIBUTE_UNUSED,
-                             tree type ATTRIBUTE_UNUSED,
-                             int *pretend_size, int no_rtl)
-{
-#if TARGET_ABI_UNICOSMK
-  /* On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register
-     arguments on the stack. Unfortunately, it doesn't always store the first
-     one (i.e. the one that arrives in $16 or $f16). This is not a problem
-     with stdargs as we always have at least one named argument there.  */
-  int num_reg_words = pcum->num_reg_words;
-  if (num_reg_words < 6)
-    {
-      if (!no_rtl)
-       {
-         emit_insn (gen_umk_mismatch_args (GEN_INT (num_reg_words + 1)));
-         emit_insn (gen_arg_home_umk ());
-       }
-      *pretend_size = 0;
+      if (!(*insn_op->predicate) (op[arity], insn_op->mode))
+       op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
     }
-#elif TARGET_ABI_OPEN_VMS
-  /* For VMS, we allocate space for all 6 arg registers plus a count.
 
-     However, if NO registers need to be saved, don't allocate any space.
-     This is not only because we won't need the space, but because AP
-     includes the current_pretend_args_size and we don't want to mess up
-     any ap-relative addresses already made.  */
-  if (pcum->num_args < 6)
+  if (nonvoid)
     {
-      if (!no_rtl)
-       {
-         emit_move_insn (gen_rtx_REG (DImode, 1), virtual_incoming_args_rtx);
-         emit_insn (gen_arg_home ());
-       }
-      *pretend_size = 7 * UNITS_PER_WORD;
+      enum machine_mode tmode = insn_data[icode].operand[0].mode;
+      if (!target
+         || GET_MODE (target) != tmode
+         || !(*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
     }
-#else
-  /* On OSF/1 and friends, we allocate space for all 12 arg registers, but
-     only push those that are remaining.  However, if NO registers need to
-     be saved, don't allocate any space.  This is not only because we won't
-     need the space, but because AP includes the current_pretend_args_size
-     and we don't want to mess up any ap-relative addresses already made.
-
-     If we are not to use the floating-point registers, save the integer
-     registers where we would put the floating-point registers.  This is
-     not the most efficient way to implement varargs with just one register
-     class, but it isn't worth doing anything more efficient in this rare
-     case.  */
-  CUMULATIVE_ARGS cum = *pcum;
-
-  if (cum >= 6)
-    return;
 
-  if (!no_rtl)
+  switch (arity)
     {
-      int set = get_varargs_alias_set ();
-      rtx tmp;
+    case 0:
+      pat = GEN_FCN (icode) (target);
+      break;
+    case 1:
+      if (nonvoid)
+        pat = GEN_FCN (icode) (target, op[0]);
+      else
+       pat = GEN_FCN (icode) (op[0]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (target, op[0], op[1]);
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
 
-      tmp = gen_rtx_MEM (BLKmode,
-                        plus_constant (virtual_incoming_args_rtx,
-                                       (cum + 6) * UNITS_PER_WORD));
-      set_mem_alias_set (tmp, set);
-      move_block_from_reg (16 + cum, tmp, 6 - cum);
-
-      tmp = gen_rtx_MEM (BLKmode,
-                        plus_constant (virtual_incoming_args_rtx,
-                                       cum * UNITS_PER_WORD));
-      set_mem_alias_set (tmp, set);
-      move_block_from_reg (16 + (TARGET_FPREGS ? 32 : 0) + cum, tmp,
-                          6 - cum);
-     }
-  *pretend_size = 12 * UNITS_PER_WORD;
-#endif
+  if (nonvoid)
+    return target;
+  else
+    return const0_rtx;
 }
 
-void
-alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
-{
-  HOST_WIDE_INT offset;
-  tree t, offset_field, base_field;
-
-  if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK)
-    return;
-
-  if (TARGET_ABI_UNICOSMK)
-    std_expand_builtin_va_start (valist, nextarg);
-
-  /* For Unix, TARGET_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.
 
-     If no integer registers need be stored, then we must subtract 48
-     in order to account for the integer arg registers which are counted
-     in argsize above, but which are not actually stored on the stack.
-     Must further be careful here about structures straddling the last
-     integer argument register; that futzes with pretend_args_size, 
-     which changes the meaning of AP.  */
+/* Several bits below assume HWI >= 64 bits.  This should be enforced
+   by config.gcc.  */
+#if HOST_BITS_PER_WIDE_INT < 64
+# error "HOST_WIDE_INT too small"
+#endif
 
-  if (NUM_ARGS <= 6)
-    offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD;
-  else
-    offset = -6 * UNITS_PER_WORD + current_function_pretend_args_size;
+/* Fold the builtin for the CMPBGE instruction.  This is a vector comparison
+   with an 8 bit output vector.  OPINT contains the integer operands; bit N
+   of OP_CONST is set if OPINT[N] is valid.  */
 
-  if (TARGET_ABI_OPEN_VMS)
+static tree
+alpha_fold_builtin_cmpbge (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  if (op_const == 3)
     {
-      nextarg = plus_constant (nextarg, offset);
-      nextarg = plus_constant (nextarg, NUM_ARGS * UNITS_PER_WORD);
-      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
-                make_tree (ptr_type_node, nextarg));
-      TREE_SIDE_EFFECTS (t) = 1;
-
-      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      int i, val;
+      for (i = 0, val = 0; i < 8; ++i)
+       {
+         unsigned HOST_WIDE_INT c0 = (opint[0] >> (i * 8)) & 0xff;
+         unsigned HOST_WIDE_INT c1 = (opint[1] >> (i * 8)) & 0xff;
+         if (c0 >= c1)
+           val |= 1 << i;
+       }
+      return build_int_cst (long_integer_type_node, val);
     }
-  else
+  else if (op_const == 2 && opint[1] == 0)
+    return build_int_cst (long_integer_type_node, 0xff);
+  return NULL;
+}
+
+/* Fold the builtin for the ZAPNOT instruction.  This is essentially a 
+   specialized form of an AND operation.  Other byte manipulation instructions
+   are defined in terms of this instruction, so this is also used as a
+   subroutine for other builtins.
+
+   OP contains the tree operands; OPINT contains the extracted integer values.
+   Bit N of OP_CONST it set if OPINT[N] is valid.  OP may be null if only
+   OPINT may be considered.  */
+
+static tree
+alpha_fold_builtin_zapnot (tree *op, unsigned HOST_WIDE_INT opint[],
+                          long op_const)
+{
+  if (op_const & 2)
     {
-      base_field = TYPE_FIELDS (TREE_TYPE (valist));
-      offset_field = TREE_CHAIN (base_field);
+      unsigned HOST_WIDE_INT mask = 0;
+      int i;
 
-      base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
-                         valist, base_field, NULL_TREE);
-      offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
-                           valist, offset_field, NULL_TREE);
+      for (i = 0; i < 8; ++i)
+       if ((opint[1] >> i) & 1)
+         mask |= (unsigned HOST_WIDE_INT)0xff << (i * 8);
 
-      t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
-      t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
-      t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      if (op_const & 1)
+       return build_int_cst (long_integer_type_node, opint[0] & mask);
 
-      t = build_int_2 (NUM_ARGS * UNITS_PER_WORD, 0);
-      t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t);
-      TREE_SIDE_EFFECTS (t) = 1;
-      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      if (op)
+       return fold (build2 (BIT_AND_EXPR, long_integer_type_node, op[0],
+                            build_int_cst (long_integer_type_node, mask)));
     }
+  else if ((op_const & 1) && opint[0] == 0)
+    return build_int_cst (long_integer_type_node, 0);
+  return NULL;
 }
 
+/* Fold the builtins for the EXT family of instructions.  */
+
 static tree
-alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
+alpha_fold_builtin_extxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
 {
-  tree type_size, ptr_type, addend, t, addr, internal_post;
+  long zap_const = 2;
+  tree *zap_op = NULL;
 
-  /* If the type could not be passed in registers, skip the block
-     reserved for the registers.  */
-  if (targetm.calls.must_pass_in_stack (TYPE_MODE (type), type))
+  if (op_const & 2)
     {
-      t = fold_convert (TREE_TYPE (offset), build_int_2 (6*8, 0));
-      t = build (MODIFY_EXPR, TREE_TYPE (offset), offset,
-                build (MAX_EXPR, TREE_TYPE (offset), offset, t));
-      gimplify_and_add (t, pre_p);
+      unsigned HOST_WIDE_INT loc;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      loc *= 8;
+
+      if (loc != 0)
+       {
+         if (op_const & 1)
+           {
+             unsigned HOST_WIDE_INT temp = opint[0];
+             if (is_high)
+               temp <<= loc;
+             else
+               temp >>= loc;
+             opint[0] = temp;
+             zap_const = 3;
+           }
+       }
+      else
+       zap_op = op;
     }
+  
+  opint[1] = bytemask;
+  return alpha_fold_builtin_zapnot (zap_op, opint, zap_const);
+}
 
-  addend = offset;
-  ptr_type = build_pointer_type (type);
+/* Fold the builtins for the INS family of instructions.  */
 
-  if (TREE_CODE (type) == COMPLEX_TYPE)
-    {
-      tree real_part, imag_part, real_temp;
+static tree
+alpha_fold_builtin_insxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  if ((op_const & 1) && opint[0] == 0)
+    return build_int_cst (long_integer_type_node, 0);
 
-      real_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base,
-                                          offset, pre_p);
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT temp, loc, byteloc;
+      tree *zap_op = NULL;
 
-      /* Copy the value into a new temporary, lest the formal temporary
-        be reused out from under us.  */
-      real_temp = get_initialized_tmp_var (real_part, pre_p, NULL);
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
 
-      imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base,
-                                          offset, pre_p);
+      temp = opint[0];
+      if (is_high)
+       {
+         byteloc = (64 - (loc * 8)) & 0x3f;
+         if (byteloc == 0)
+           zap_op = op;
+         else
+           temp >>= byteloc;
+         bytemask >>= 8;
+       }
+      else
+       {
+         byteloc = loc * 8;
+         if (byteloc == 0)
+           zap_op = op;
+         else
+           temp <<= byteloc;
+       }
 
-      return build (COMPLEX_EXPR, type, real_temp, imag_part);
+      opint[0] = temp;
+      opint[1] = bytemask;
+      return alpha_fold_builtin_zapnot (zap_op, opint, op_const);
     }
-  else if (TREE_CODE (type) == REAL_TYPE)
+
+  return NULL;
+}
+
+static tree
+alpha_fold_builtin_mskxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  if (op_const & 2)
     {
-      tree fpaddend, cond, fourtyeight;
+      unsigned HOST_WIDE_INT loc;
 
-      fourtyeight = fold_convert (TREE_TYPE (addend), build_int_2 (6*8, 0));
-      fpaddend = fold (build (MINUS_EXPR, TREE_TYPE (addend),
-                             addend, fourtyeight));
-      cond = fold (build (LT_EXPR, boolean_type_node, addend, fourtyeight));
-      addend = fold (build (COND_EXPR, TREE_TYPE (addend), cond,
-                           fpaddend, addend));
-    }
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
 
-  /* Build the final address and force that value into a temporary.  */
-  addr = build (PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
-               fold_convert (ptr_type, addend));
-  internal_post = NULL;
-  gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue);
-  append_to_statement_list (internal_post, pre_p);
+      if (is_high)
+       bytemask >>= 8;
 
-  /* Update the offset field.  */
-  type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
-  if (type_size == NULL || TREE_OVERFLOW (type_size))
-    t = size_zero_node;
-  else
-    {
-      t = size_binop (PLUS_EXPR, type_size, size_int (7));
-      t = size_binop (TRUNC_DIV_EXPR, t, size_int (8));
-      t = size_binop (MULT_EXPR, t, size_int (8));
+      opint[1] = bytemask ^ 0xff;
     }
-  t = fold_convert (TREE_TYPE (offset), t);
-  t = build (MODIFY_EXPR, void_type_node, offset,
-            build (PLUS_EXPR, TREE_TYPE (offset), offset, t));
-  gimplify_and_add (t, pre_p);
 
-  return build_fold_indirect_ref (addr);
+  return alpha_fold_builtin_zapnot (op, opint, op_const);
 }
 
 static tree
-alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
+alpha_fold_builtin_umulh (unsigned HOST_WIDE_INT opint[], long op_const)
 {
-  tree offset_field, base_field, offset, base, t, r;
-  bool indirect;
+  switch (op_const)
+    {
+    case 3:
+      {
+       unsigned HOST_WIDE_INT l;
+       HOST_WIDE_INT h;
 
-  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
-    return std_gimplify_va_arg_expr (valist, type, pre_p, post_p);
+       mul_double (opint[0], 0, opint[1], 0, &l, &h);
 
-  base_field = TYPE_FIELDS (va_list_type_node);
-  offset_field = TREE_CHAIN (base_field);
-  base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
-                     valist, base_field, NULL_TREE);
-  offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
-                       valist, offset_field, NULL_TREE);
+#if HOST_BITS_PER_WIDE_INT > 64
+# error fixme
+#endif
 
-  /* Pull the fields of the structure out into temporaries.  Since we never
-     modify the base field, we can use a formal temporary.  Sign-extend the
-     offset field so that it's the proper width for pointer arithmetic.  */
-  base = get_formal_tmp_var (base_field, pre_p);
+       return build_int_cst (long_integer_type_node, h);
+      }
 
-  t = fold_convert (lang_hooks.types.type_for_size (64, 0), offset_field);
-  offset = get_initialized_tmp_var (t, pre_p, NULL);
+    case 1:
+      opint[1] = opint[0];
+      /* FALLTHRU */
+    case 2:
+      /* Note that (X*1) >> 64 == 0.  */
+      if (opint[1] == 0 || opint[1] == 1)
+       return build_int_cst (long_integer_type_node, 0);
+      break;
+    }
+  return NULL;
+}
 
-  indirect = pass_by_reference (NULL, TYPE_MODE (type), type, false);
-  if (indirect)
-    type = build_pointer_type (type);
+static tree
+alpha_fold_vector_minmax (enum tree_code code, tree op[], tree vtype)
+{
+  tree op0 = fold_convert (vtype, op[0]);
+  tree op1 = fold_convert (vtype, op[1]);
+  tree val = fold (build2 (code, vtype, op0, op1));
+  return fold_convert (long_integer_type_node, val);
+}
 
-  /* Find the value.  Note that this will be a stable indirection, or
-     a composite of stable indirections in the case of complex.  */
-  r = alpha_gimplify_va_arg_1 (type, base, offset, pre_p);
+static tree
+alpha_fold_builtin_perr (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp = 0;
+  int i;
 
-  /* Stuff the offset temporary back into its field.  */
-  t = build (MODIFY_EXPR, void_type_node, offset_field,
-            fold_convert (TREE_TYPE (offset_field), offset));
-  gimplify_and_add (t, pre_p);
+  if (op_const != 3)
+    return NULL;
 
-  if (indirect)
-    r = build_fold_indirect_ref (r);
+  for (i = 0; i < 8; ++i)
+    {
+      unsigned HOST_WIDE_INT a = (opint[0] >> (i * 8)) & 0xff;
+      unsigned HOST_WIDE_INT b = (opint[1] >> (i * 8)) & 0xff;
+      if (a >= b)
+       temp += a - b;
+      else
+       temp += b - a;
+    }
 
-  return r;
+  return build_int_cst (long_integer_type_node, temp);
 }
-\f
-/* Builtins.  */
 
-enum alpha_builtin
+static tree
+alpha_fold_builtin_pklb (unsigned HOST_WIDE_INT opint[], long op_const)
 {
-  ALPHA_BUILTIN_CMPBGE,
-  ALPHA_BUILTIN_EXTBL,
-  ALPHA_BUILTIN_EXTWL,
-  ALPHA_BUILTIN_EXTLL,
-  ALPHA_BUILTIN_EXTQL,
-  ALPHA_BUILTIN_EXTWH,
-  ALPHA_BUILTIN_EXTLH,
-  ALPHA_BUILTIN_EXTQH,
-  ALPHA_BUILTIN_INSBL,
-  ALPHA_BUILTIN_INSWL,
-  ALPHA_BUILTIN_INSLL,
-  ALPHA_BUILTIN_INSQL,
-  ALPHA_BUILTIN_INSWH,
-  ALPHA_BUILTIN_INSLH,
-  ALPHA_BUILTIN_INSQH,
-  ALPHA_BUILTIN_MSKBL,
-  ALPHA_BUILTIN_MSKWL,
-  ALPHA_BUILTIN_MSKLL,
-  ALPHA_BUILTIN_MSKQL,
-  ALPHA_BUILTIN_MSKWH,
-  ALPHA_BUILTIN_MSKLH,
-  ALPHA_BUILTIN_MSKQH,
-  ALPHA_BUILTIN_UMULH,
-  ALPHA_BUILTIN_ZAP,
-  ALPHA_BUILTIN_ZAPNOT,
-  ALPHA_BUILTIN_AMASK,
-  ALPHA_BUILTIN_IMPLVER,
-  ALPHA_BUILTIN_RPCC,
-  ALPHA_BUILTIN_THREAD_POINTER,
-  ALPHA_BUILTIN_SET_THREAD_POINTER,
+  unsigned HOST_WIDE_INT temp;
 
-  /* TARGET_MAX */
-  ALPHA_BUILTIN_MINUB8,
-  ALPHA_BUILTIN_MINSB8,
-  ALPHA_BUILTIN_MINUW4,
-  ALPHA_BUILTIN_MINSW4,
-  ALPHA_BUILTIN_MAXUB8,
-  ALPHA_BUILTIN_MAXSB8,
-  ALPHA_BUILTIN_MAXUW4,
-  ALPHA_BUILTIN_MAXSW4,
-  ALPHA_BUILTIN_PERR,
-  ALPHA_BUILTIN_PKLB,
-  ALPHA_BUILTIN_PKWB,
-  ALPHA_BUILTIN_UNPKBL,
-  ALPHA_BUILTIN_UNPKBW,
+  if (op_const == 0)
+    return NULL;
 
-  /* TARGET_CIX */
-  ALPHA_BUILTIN_CTTZ,
-  ALPHA_BUILTIN_CTLZ,
-  ALPHA_BUILTIN_CTPOP,
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >> 24) & 0xff00;
 
-  ALPHA_BUILTIN_max
-};
+  return build_int_cst (long_integer_type_node, temp);
+}
 
-static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = {
-  CODE_FOR_builtin_cmpbge,
-  CODE_FOR_builtin_extbl,
-  CODE_FOR_builtin_extwl,
-  CODE_FOR_builtin_extll,
-  CODE_FOR_builtin_extql,
-  CODE_FOR_builtin_extwh,
-  CODE_FOR_builtin_extlh,
-  CODE_FOR_builtin_extqh,
-  CODE_FOR_builtin_insbl,
-  CODE_FOR_builtin_inswl,
-  CODE_FOR_builtin_insll,
-  CODE_FOR_builtin_insql,
-  CODE_FOR_builtin_inswh,
-  CODE_FOR_builtin_inslh,
-  CODE_FOR_builtin_insqh,
-  CODE_FOR_builtin_mskbl,
-  CODE_FOR_builtin_mskwl,
-  CODE_FOR_builtin_mskll,
-  CODE_FOR_builtin_mskql,
-  CODE_FOR_builtin_mskwh,
-  CODE_FOR_builtin_msklh,
-  CODE_FOR_builtin_mskqh,
-  CODE_FOR_umuldi3_highpart,
-  CODE_FOR_builtin_zap,
-  CODE_FOR_builtin_zapnot,
-  CODE_FOR_builtin_amask,
-  CODE_FOR_builtin_implver,
-  CODE_FOR_builtin_rpcc,
-  CODE_FOR_load_tp,
-  CODE_FOR_set_tp,
+static tree
+alpha_fold_builtin_pkwb (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
 
-  /* TARGET_MAX */
-  CODE_FOR_builtin_minub8,
-  CODE_FOR_builtin_minsb8,
-  CODE_FOR_builtin_minuw4,
-  CODE_FOR_builtin_minsw4,
-  CODE_FOR_builtin_maxub8,
-  CODE_FOR_builtin_maxsb8,
-  CODE_FOR_builtin_maxuw4,
-  CODE_FOR_builtin_maxsw4,
-  CODE_FOR_builtin_perr,
-  CODE_FOR_builtin_pklb,
-  CODE_FOR_builtin_pkwb,
-  CODE_FOR_builtin_unpkbl,
-  CODE_FOR_builtin_unpkbw,
+  if (op_const == 0)
+    return NULL;
 
-  /* TARGET_CIX */
-  CODE_FOR_builtin_cttz,
-  CODE_FOR_builtin_ctlz,
-  CODE_FOR_builtin_ctpop
-};
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >>  8) & 0xff00;
+  temp |= (opint[0] >> 16) & 0xff0000;
+  temp |= (opint[0] >> 24) & 0xff000000;
 
-struct alpha_builtin_def
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_unpkbl (unsigned HOST_WIDE_INT opint[], long op_const)
 {
-  const char *name;
-  enum alpha_builtin code;
-  unsigned int target_mask;
-};
+  unsigned HOST_WIDE_INT temp;
 
-static struct alpha_builtin_def const zero_arg_builtins[] = {
-  { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER,  0 },
-  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0 }
-};
+  if (op_const == 0)
+    return NULL;
 
-static struct alpha_builtin_def const one_arg_builtins[] = {
-  { "__builtin_alpha_amask",   ALPHA_BUILTIN_AMASK,    0 },
-  { "__builtin_alpha_pklb",    ALPHA_BUILTIN_PKLB,     MASK_MAX },
-  { "__builtin_alpha_pkwb",    ALPHA_BUILTIN_PKWB,     MASK_MAX },
-  { "__builtin_alpha_unpkbl",  ALPHA_BUILTIN_UNPKBL,   MASK_MAX },
-  { "__builtin_alpha_unpkbw",  ALPHA_BUILTIN_UNPKBW,   MASK_MAX },
-  { "__builtin_alpha_cttz",    ALPHA_BUILTIN_CTTZ,     MASK_CIX },
-  { "__builtin_alpha_ctlz",    ALPHA_BUILTIN_CTLZ,     MASK_CIX },
-  { "__builtin_alpha_ctpop",   ALPHA_BUILTIN_CTPOP,    MASK_CIX }
-};
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0xff00) << 24;
 
-static struct alpha_builtin_def const two_arg_builtins[] = {
-  { "__builtin_alpha_cmpbge",  ALPHA_BUILTIN_CMPBGE,   0 },
-  { "__builtin_alpha_extbl",   ALPHA_BUILTIN_EXTBL,    0 },
-  { "__builtin_alpha_extwl",   ALPHA_BUILTIN_EXTWL,    0 },
-  { "__builtin_alpha_extll",   ALPHA_BUILTIN_EXTLL,    0 },
-  { "__builtin_alpha_extql",   ALPHA_BUILTIN_EXTQL,    0 },
-  { "__builtin_alpha_extwh",   ALPHA_BUILTIN_EXTWH,    0 },
-  { "__builtin_alpha_extlh",   ALPHA_BUILTIN_EXTLH,    0 },
-  { "__builtin_alpha_extqh",   ALPHA_BUILTIN_EXTQH,    0 },
-  { "__builtin_alpha_insbl",   ALPHA_BUILTIN_INSBL,    0 },
-  { "__builtin_alpha_inswl",   ALPHA_BUILTIN_INSWL,    0 },
-  { "__builtin_alpha_insll",   ALPHA_BUILTIN_INSLL,    0 },
-  { "__builtin_alpha_insql",   ALPHA_BUILTIN_INSQL,    0 },
-  { "__builtin_alpha_inswh",   ALPHA_BUILTIN_INSWH,    0 },
-  { "__builtin_alpha_inslh",   ALPHA_BUILTIN_INSLH,    0 },
-  { "__builtin_alpha_insqh",   ALPHA_BUILTIN_INSQH,    0 },
-  { "__builtin_alpha_mskbl",   ALPHA_BUILTIN_MSKBL,    0 },
-  { "__builtin_alpha_mskwl",   ALPHA_BUILTIN_MSKWL,    0 },
-  { "__builtin_alpha_mskll",   ALPHA_BUILTIN_MSKLL,    0 },
-  { "__builtin_alpha_mskql",   ALPHA_BUILTIN_MSKQL,    0 },
-  { "__builtin_alpha_mskwh",   ALPHA_BUILTIN_MSKWH,    0 },
-  { "__builtin_alpha_msklh",   ALPHA_BUILTIN_MSKLH,    0 },
-  { "__builtin_alpha_mskqh",   ALPHA_BUILTIN_MSKQH,    0 },
-  { "__builtin_alpha_umulh",   ALPHA_BUILTIN_UMULH,    0 },
-  { "__builtin_alpha_zap",     ALPHA_BUILTIN_ZAP,      0 },
-  { "__builtin_alpha_zapnot",  ALPHA_BUILTIN_ZAPNOT,   0 },
-  { "__builtin_alpha_minub8",  ALPHA_BUILTIN_MINUB8,   MASK_MAX },
-  { "__builtin_alpha_minsb8",  ALPHA_BUILTIN_MINSB8,   MASK_MAX },
-  { "__builtin_alpha_minuw4",  ALPHA_BUILTIN_MINUW4,   MASK_MAX },
-  { "__builtin_alpha_minsw4",  ALPHA_BUILTIN_MINSW4,   MASK_MAX },
-  { "__builtin_alpha_maxub8",  ALPHA_BUILTIN_MAXUB8,   MASK_MAX },
-  { "__builtin_alpha_maxsb8",  ALPHA_BUILTIN_MAXSB8,   MASK_MAX },
-  { "__builtin_alpha_maxuw4",  ALPHA_BUILTIN_MAXUW4,   MASK_MAX },
-  { "__builtin_alpha_maxsw4",  ALPHA_BUILTIN_MAXSW4,   MASK_MAX },
-  { "__builtin_alpha_perr",    ALPHA_BUILTIN_PERR,     MASK_MAX }
-};
+  return build_int_cst (long_integer_type_node, temp);
+}
 
-static void
-alpha_init_builtins (void)
+static tree
+alpha_fold_builtin_unpkbw (unsigned HOST_WIDE_INT opint[], long op_const)
 {
-  const struct alpha_builtin_def *p;
-  tree ftype;
-  size_t i;
+  unsigned HOST_WIDE_INT temp;
 
-  ftype = build_function_type (long_integer_type_node, void_list_node);
-
-  p = zero_arg_builtins;
-  for (i = 0; i < ARRAY_SIZE (zero_arg_builtins); ++i, ++p)
-    if ((target_flags & p->target_mask) == p->target_mask)
-      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+  if (op_const == 0)
+    return NULL;
 
-  ftype = build_function_type_list (long_integer_type_node,
-                                   long_integer_type_node, NULL_TREE);
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0x0000ff00) << 8;
+  temp |= (opint[0] & 0x00ff0000) << 16;
+  temp |= (opint[0] & 0xff000000) << 24;
 
-  p = one_arg_builtins;
-  for (i = 0; i < ARRAY_SIZE (one_arg_builtins); ++i, ++p)
-    if ((target_flags & p->target_mask) == p->target_mask)
-      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+  return build_int_cst (long_integer_type_node, temp);
+}
 
-  ftype = build_function_type_list (long_integer_type_node,
-                                   long_integer_type_node,
-                                   long_integer_type_node, NULL_TREE);
+static tree
+alpha_fold_builtin_cttz (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
 
-  p = two_arg_builtins;
-  for (i = 0; i < ARRAY_SIZE (two_arg_builtins); ++i, ++p)
-    if ((target_flags & p->target_mask) == p->target_mask)
-      lang_hooks.builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
-                                  NULL, NULL_TREE);
+  if (op_const == 0)
+    return NULL;
 
-  ftype = build_function_type (ptr_type_node, void_list_node);
-  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
-                              ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = exact_log2 (opint[0] & -opint[0]);
 
-  ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
-  lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype,
-                              ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+  return build_int_cst (long_integer_type_node, temp);
 }
 
-/* Expand an expression EXP that calls a built-in function,
-   with result going to TARGET if that's convenient
-   (and in mode MODE if that's convenient).
-   SUBTARGET may be used as the target for computing one of EXP's operands.
-   IGNORE is nonzero if the value is to be ignored.  */
-
-static rtx
-alpha_expand_builtin (tree exp, rtx target,
-                     rtx subtarget ATTRIBUTE_UNUSED,
-                     enum machine_mode mode ATTRIBUTE_UNUSED,
-                     int ignore ATTRIBUTE_UNUSED)
+static tree
+alpha_fold_builtin_ctlz (unsigned HOST_WIDE_INT opint[], long op_const)
 {
-#define MAX_ARGS 2
+  unsigned HOST_WIDE_INT temp;
 
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
-  tree arglist = TREE_OPERAND (exp, 1);
-  enum insn_code icode;
-  rtx op[MAX_ARGS], pat;
-  int arity;
-  bool nonvoid;
+  if (op_const == 0)
+    return NULL;
 
-  if (fcode >= ALPHA_BUILTIN_max)
-    internal_error ("bad builtin fcode");
-  icode = code_for_builtin[fcode];
-  if (icode == 0)
-    internal_error ("bad builtin fcode");
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = 64 - floor_log2 (opint[0]) - 1;
 
-  nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+  return build_int_cst (long_integer_type_node, temp);
+}
 
-  for (arglist = TREE_OPERAND (exp, 1), arity = 0;
-       arglist;
-       arglist = TREE_CHAIN (arglist), arity++)
-    {
-      const struct insn_operand_data *insn_op;
+static tree
+alpha_fold_builtin_ctpop (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp, op;
 
-      tree arg = TREE_VALUE (arglist);
-      if (arg == error_mark_node)
-       return NULL_RTX;
-      if (arity > MAX_ARGS)
-       return NULL_RTX;
+  if (op_const == 0)
+    return NULL;
 
-      insn_op = &insn_data[icode].operand[arity + nonvoid];
+  op = opint[0];
+  temp = 0;
+  while (op)
+    temp++, op &= op - 1;
 
-      op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0);
+  return build_int_cst (long_integer_type_node, temp);
+}
 
-      if (!(*insn_op->predicate) (op[arity], insn_op->mode))
-       op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
-    }
+/* Fold one of our builtin functions.  */
 
-  if (nonvoid)
-    {
-      enum machine_mode tmode = insn_data[icode].operand[0].mode;
-      if (!target
-         || GET_MODE (target) != tmode
-         || !(*insn_data[icode].operand[0].predicate) (target, tmode))
-       target = gen_reg_rtx (tmode);
-    }
+static tree
+alpha_fold_builtin (tree fndecl, tree arglist, bool ignore ATTRIBUTE_UNUSED)
+{
+  tree op[MAX_ARGS], t;
+  unsigned HOST_WIDE_INT opint[MAX_ARGS];
+  long op_const = 0, arity = 0;
 
-  switch (arity)
+  for (t = arglist; t ; t = TREE_CHAIN (t), ++arity)
     {
-    case 0:
-      pat = GEN_FCN (icode) (target);
-      break;
-    case 1:
-      if (nonvoid)
-        pat = GEN_FCN (icode) (target, op[0]);
-      else
-       pat = GEN_FCN (icode) (op[0]);
-      break;
-    case 2:
-      pat = GEN_FCN (icode) (target, op[0], op[1]);
-      break;
+      tree arg = TREE_VALUE (t);
+      if (arg == error_mark_node)
+       return NULL;
+      if (arity >= MAX_ARGS)
+       return NULL;
+
+      op[arity] = arg;
+      opint[arity] = 0;
+      if (TREE_CODE (arg) == INTEGER_CST)
+       {
+          op_const |= 1L << arity;
+         opint[arity] = int_cst_value (arg);
+       }
+    }
+
+  switch (DECL_FUNCTION_CODE (fndecl))
+    {
+    case ALPHA_BUILTIN_CMPBGE:
+      return alpha_fold_builtin_cmpbge (opint, op_const);
+
+    case ALPHA_BUILTIN_EXTBL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_EXTWL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_EXTLL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_EXTQL:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_EXTWH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_EXTLH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_EXTQH:
+      return alpha_fold_builtin_extxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_INSBL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_INSWL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_INSLL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_INSQL:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_INSWH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_INSLH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_INSQH:
+      return alpha_fold_builtin_insxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_MSKBL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x01, false);
+    case ALPHA_BUILTIN_MSKWL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, false);
+    case ALPHA_BUILTIN_MSKLL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, false);
+    case ALPHA_BUILTIN_MSKQL:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, false);
+    case ALPHA_BUILTIN_MSKWH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x03, true);
+    case ALPHA_BUILTIN_MSKLH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0x0f, true);
+    case ALPHA_BUILTIN_MSKQH:
+      return alpha_fold_builtin_mskxx (op, opint, op_const, 0xff, true);
+
+    case ALPHA_BUILTIN_UMULH:
+      return alpha_fold_builtin_umulh (opint, op_const);
+
+    case ALPHA_BUILTIN_ZAP:
+      opint[1] ^= 0xff;
+      /* FALLTHRU */
+    case ALPHA_BUILTIN_ZAPNOT:
+      return alpha_fold_builtin_zapnot (op, opint, op_const);
+
+    case ALPHA_BUILTIN_MINUB8:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_u);
+    case ALPHA_BUILTIN_MINSB8:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v8qi_s);
+    case ALPHA_BUILTIN_MINUW4:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_u);
+    case ALPHA_BUILTIN_MINSW4:
+      return alpha_fold_vector_minmax (MIN_EXPR, op, alpha_v4hi_s);
+    case ALPHA_BUILTIN_MAXUB8:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_u);
+    case ALPHA_BUILTIN_MAXSB8:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v8qi_s);
+    case ALPHA_BUILTIN_MAXUW4:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_u);
+    case ALPHA_BUILTIN_MAXSW4:
+      return alpha_fold_vector_minmax (MAX_EXPR, op, alpha_v4hi_s);
+
+    case ALPHA_BUILTIN_PERR:
+      return alpha_fold_builtin_perr (opint, op_const);
+    case ALPHA_BUILTIN_PKLB:
+      return alpha_fold_builtin_pklb (opint, op_const);
+    case ALPHA_BUILTIN_PKWB:
+      return alpha_fold_builtin_pkwb (opint, op_const);
+    case ALPHA_BUILTIN_UNPKBL:
+      return alpha_fold_builtin_unpkbl (opint, op_const);
+    case ALPHA_BUILTIN_UNPKBW:
+      return alpha_fold_builtin_unpkbw (opint, op_const);
+
+    case ALPHA_BUILTIN_CTTZ:
+      return alpha_fold_builtin_cttz (opint, op_const);
+    case ALPHA_BUILTIN_CTLZ:
+      return alpha_fold_builtin_ctlz (opint, op_const);
+    case ALPHA_BUILTIN_CTPOP:
+      return alpha_fold_builtin_ctpop (opint, op_const);
+
+    case ALPHA_BUILTIN_AMASK:
+    case ALPHA_BUILTIN_IMPLVER:
+    case ALPHA_BUILTIN_RPCC:
+    case ALPHA_BUILTIN_THREAD_POINTER:
+    case ALPHA_BUILTIN_SET_THREAD_POINTER:
+      /* None of these are foldable at compile-time.  */
     default:
-      abort ();
+      return NULL;
     }
-  if (!pat)
-    return NULL_RTX;
-  emit_insn (pat);
-
-  if (nonvoid)
-    return target;
-  else
-    return const0_rtx;
 }
 \f
 /* This page contains routines that are used to determine what the function
@@ -6703,13 +6923,8 @@ alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP)
            break;
          imask |= 1UL << regno;
        }
-
-      /* Glibc likes to use $31 as an unwind stopper for crt0.  To
-        avoid hackery in unwind-dw2.c, we need to actively store a
-        zero in the prologue of _Unwind_RaiseException et al.  */
-      imask |= 1UL << 31;
     }
-     
+
   /* If any register spilled, then spill the return address also.  */
   /* ??? This is required by the Digital stack unwind specification
      and isn't needed if we're doing Dwarf2 unwinding.  */
@@ -6835,14 +7050,20 @@ alpha_initial_elimination_offset (unsigned int from,
   ret = alpha_sa_size ();
   ret += ALPHA_ROUND (current_function_outgoing_args_size);
 
-  if (from == FRAME_POINTER_REGNUM)
-    ;
-  else if (from == ARG_POINTER_REGNUM)
-    ret += (ALPHA_ROUND (get_frame_size ()
-                        + current_function_pretend_args_size)
-           - current_function_pretend_args_size);
-  else
-    abort ();
+  switch (from)
+    {
+    case FRAME_POINTER_REGNUM:
+      break;
+
+    case ARG_POINTER_REGNUM:
+      ret += (ALPHA_ROUND (get_frame_size ()
+                          + current_function_pretend_args_size)
+             - current_function_pretend_args_size);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
 
   return ret;
 }
@@ -6910,7 +7131,7 @@ alpha_does_function_need_gp (void)
   if (current_function_has_nonlocal_goto)
     return 1;
 
-  /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. 
+  /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first.
      Even if we are a static function, we still need to do this in case
      our address is taken and passed to something like qsort.  */
 
@@ -6963,6 +7184,48 @@ set_frame_related_p (void)
 
 #define FRP(exp)  (start_sequence (), exp, set_frame_related_p ())
 
+/* Generates a store with the proper unwind info attached.  VALUE is
+   stored at BASE_REG+BASE_OFS.  If FRAME_BIAS is nonzero, then BASE_REG
+   contains SP+FRAME_BIAS, and that is the unwind info that should be
+   generated.  If FRAME_REG != VALUE, then VALUE is being stored on
+   behalf of FRAME_REG, and FRAME_REG should be present in the unwind.  */
+
+static void
+emit_frame_store_1 (rtx value, rtx base_reg, HOST_WIDE_INT frame_bias,
+                   HOST_WIDE_INT base_ofs, rtx frame_reg)
+{
+  rtx addr, mem, insn;
+
+  addr = plus_constant (base_reg, base_ofs);
+  mem = gen_rtx_MEM (DImode, addr);
+  set_mem_alias_set (mem, alpha_sr_alias_set);
+
+  insn = emit_move_insn (mem, value);
+  RTX_FRAME_RELATED_P (insn) = 1;
+
+  if (frame_bias || value != frame_reg)
+    {
+      if (frame_bias)
+       {
+         addr = plus_constant (stack_pointer_rtx, frame_bias + base_ofs);
+         mem = gen_rtx_MEM (DImode, addr);
+       }
+
+      REG_NOTES (insn)
+       = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
+                            gen_rtx_SET (VOIDmode, mem, frame_reg),
+                            REG_NOTES (insn));
+    }
+}
+
+static void
+emit_frame_store (unsigned int regno, rtx base_reg,
+                 HOST_WIDE_INT frame_bias, HOST_WIDE_INT base_ofs)
+{
+  rtx reg = gen_rtx_REG (DImode, regno);
+  emit_frame_store_1 (reg, base_reg, frame_bias, base_ofs, reg);
+}
+
 /* Write function prologue.  */
 
 /* On vms we have two kinds of functions:
@@ -6992,14 +7255,14 @@ alpha_expand_prologue (void)
   HOST_WIDE_INT frame_size;
   /* Offset from base reg to register save area.  */
   HOST_WIDE_INT reg_offset;
-  rtx sa_reg, mem;
+  rtx sa_reg;
   int i;
 
   sa_size = alpha_sa_size ();
 
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
-    frame_size = ALPHA_ROUND (sa_size 
+    frame_size = ALPHA_ROUND (sa_size
                              + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
@@ -7045,7 +7308,7 @@ alpha_expand_prologue (void)
      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. 
+     instructions.
 
      Note that we are only allowed to adjust sp once in the prologue.  */
 
@@ -7106,7 +7369,7 @@ alpha_expand_prologue (void)
          /* For NT stack unwind (done by 'reverse execution'), it's
             not OK to take the result of a loop, even though the value
             is already in ptr, so we reload it via a single operation
-            and subtract it to sp. 
+            and subtract it to sp.
 
             Yes, that's correct -- we have to reload the whole constant
             into a temporary via ldah+lda then subtract from sp.  */
@@ -7142,37 +7405,40 @@ alpha_expand_prologue (void)
 
   if (!TARGET_ABI_UNICOSMK)
     {
+      HOST_WIDE_INT sa_bias = 0;
+
       /* Cope with very large offsets to the register save area.  */
       sa_reg = stack_pointer_rtx;
       if (reg_offset + sa_size > 0x8000)
        {
          int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
-         HOST_WIDE_INT bias;
+         rtx sa_bias_rtx;
 
          if (low + sa_size <= 0x8000)
-           bias = reg_offset - low, reg_offset = low;
-         else 
-           bias = reg_offset, reg_offset = 0;
+           sa_bias = reg_offset - low, reg_offset = low;
+         else
+           sa_bias = reg_offset, reg_offset = 0;
 
          sa_reg = gen_rtx_REG (DImode, 24);
-         FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx,
-                                     GEN_INT (bias))));
+         sa_bias_rtx = GEN_INT (sa_bias);
+
+         if (add_operand (sa_bias_rtx, DImode))
+           emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_bias_rtx));
+         else
+           {
+             emit_move_insn (sa_reg, sa_bias_rtx);
+             emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, sa_reg));
+           }
        }
-    
+
       /* Save regs in stack order.  Beginning with VMS PV.  */
       if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
-       {
-         mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
-         set_mem_alias_set (mem, alpha_sr_alias_set);
-         FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
-       }
+       emit_frame_store (REG_PV, stack_pointer_rtx, 0, 0);
 
       /* Save register RA next.  */
       if (imask & (1UL << REG_RA))
        {
-         mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
-         set_mem_alias_set (mem, alpha_sr_alias_set);
-         FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
+         emit_frame_store (REG_RA, sa_reg, sa_bias, reg_offset);
          imask &= ~(1UL << REG_RA);
          reg_offset += 8;
        }
@@ -7181,36 +7447,14 @@ alpha_expand_prologue (void)
       for (i = 0; i < 31; i++)
        if (imask & (1UL << i))
          {
-           mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
-           set_mem_alias_set (mem, alpha_sr_alias_set);
-           FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+           emit_frame_store (i, sa_reg, sa_bias, reg_offset);
            reg_offset += 8;
          }
 
-      /* Store a zero if requested for unwinding.  */
-      if (imask & (1UL << 31))
-       {
-         rtx insn, t;
-
-         mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
-         set_mem_alias_set (mem, alpha_sr_alias_set);
-         insn = emit_move_insn (mem, const0_rtx);
-
-         RTX_FRAME_RELATED_P (insn) = 1;
-         t = gen_rtx_REG (Pmode, 31);
-         t = gen_rtx_SET (VOIDmode, mem, t);
-         t = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, t, REG_NOTES (insn));
-         REG_NOTES (insn) = t;
-
-         reg_offset += 8;
-       }
-
       for (i = 0; i < 31; i++)
        if (fmask & (1UL << i))
          {
-           mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
-           set_mem_alias_set (mem, alpha_sr_alias_set);
-           FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+           emit_frame_store (i+32, sa_reg, sa_bias, reg_offset);
            reg_offset += 8;
          }
     }
@@ -7224,19 +7468,13 @@ alpha_expand_prologue (void)
       for (i = 9; i < 15; i++)
        if (imask & (1UL << i))
          {
-           mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
-                                                    reg_offset));
-           set_mem_alias_set (mem, alpha_sr_alias_set);
-           FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+           emit_frame_store (i, hard_frame_pointer_rtx, 0, reg_offset);
            reg_offset -= 8;
          }
       for (i = 2; i < 10; i++)
        if (fmask & (1UL << i))
          {
-           mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx,
-                                                     reg_offset));
-           set_mem_alias_set (mem, alpha_sr_alias_set);
-           FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+           emit_frame_store (i+32, hard_frame_pointer_rtx, 0, reg_offset);
            reg_offset -= 8;
          }
     }
@@ -7261,12 +7499,12 @@ alpha_expand_prologue (void)
       if (current_function_outgoing_args_size != 0)
        {
          rtx seq
-           = emit_move_insn (stack_pointer_rtx, 
+           = emit_move_insn (stack_pointer_rtx,
                              plus_constant
                              (hard_frame_pointer_rtx,
                               - (ALPHA_ROUND
                                  (current_function_outgoing_args_size))));
-         
+
          /* Only set FRAME_RELATED_P on the stack adjustment we just emitted
             if ! frame_pointer_needed. Setting the bit will change the CFA
             computation rule to use sp again, which would be wrong if we had
@@ -7306,7 +7544,7 @@ alpha_expand_prologue (void)
      (clobber:BLK (scratch)), but this doesn't work for fp insns.  So we
      have to prevent all such scheduling with a blockage.
 
-     Linux, on the other hand, never bothered to implement OSF/1's 
+     Linux, on the other hand, never bothered to implement OSF/1's
      exception handling, and so doesn't care about such things.  Anyone
      planning to use dwarf2 frame-unwind info can also omit the blockage.  */
 
@@ -7314,6 +7552,9 @@ alpha_expand_prologue (void)
     emit_insn (gen_blockage ());
 }
 
+/* Count the number of .file directives, so that .loc is up to date.  */
+int num_source_filenames = 0;
+
 /* Output the textual info surrounding the prologue.  */
 
 void
@@ -7344,7 +7585,7 @@ alpha_start_function (FILE *file, const char *fnname,
 
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
-    frame_size = ALPHA_ROUND (sa_size 
+    frame_size = ALPHA_ROUND (sa_size
                              + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
@@ -7380,10 +7621,10 @@ alpha_start_function (FILE *file, const char *fnname,
       ASM_OUTPUT_SOURCE_FILENAME (file,
                                  DECL_SOURCE_FILE (current_function_decl));
 #endif
-#ifdef ASM_OUTPUT_SOURCE_LINE
+#ifdef SDB_OUTPUT_SOURCE_LINE
       if (debug_info_level != DINFO_LEVEL_TERSE)
-        ASM_OUTPUT_SOURCE_LINE (file,
-                               DECL_SOURCE_LINE (current_function_decl), 0);
+        SDB_OUTPUT_SOURCE_LINE (file,
+                               DECL_SOURCE_LINE (current_function_decl));
 #endif
     }
 
@@ -7515,7 +7756,7 @@ alpha_output_function_end_prologue (FILE *file)
 
 /* Write function epilogue.  */
 
-/* ??? At some point we will want to support full unwind, and so will 
+/* ??? At some point we will want to support full unwind, and so will
    need to mark the epilogue as well.  At the moment, we just confuse
    dwarf2out.  */
 #undef FRP
@@ -7543,7 +7784,7 @@ alpha_expand_epilogue (void)
 
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
-    frame_size = ALPHA_ROUND (sa_size 
+    frame_size = ALPHA_ROUND (sa_size
                              + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
@@ -7597,7 +7838,7 @@ alpha_expand_epilogue (void)
 
          if (low + sa_size <= 0x8000)
            bias = reg_offset - low, reg_offset = low;
-         else 
+         else
            bias = reg_offset, reg_offset = 0;
 
          sa_reg = gen_rtx_REG (DImode, 22);
@@ -7605,7 +7846,7 @@ alpha_expand_epilogue (void)
 
          FRP (emit_move_insn (sa_reg, sa_reg_exp));
        }
-         
+
       /* Restore registers in order, excepting a true frame pointer.  */
 
       mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
@@ -7630,9 +7871,6 @@ alpha_expand_epilogue (void)
            reg_offset += 8;
          }
 
-      if (imask & (1UL << 31))
-       reg_offset += 8;
-
       for (i = 0; i < 31; ++i)
        if (fmask & (1UL << i))
          {
@@ -7715,15 +7953,15 @@ alpha_expand_epilogue (void)
       else
        {
          rtx tmp = gen_rtx_REG (DImode, 23);
-         FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size, 3));
+         FRP (sp_adj2 = alpha_emit_set_const (tmp, DImode, frame_size,
+                                              3, false));
          if (!sp_adj2)
            {
              /* We can't drop new things to memory this late, afaik,
                 so build it up by pieces.  */
              FRP (sp_adj2 = alpha_emit_set_long_const (tmp, frame_size,
                                                        -(frame_size < 0)));
-             if (!sp_adj2)
-               abort ();
+             gcc_assert (sp_adj2);
            }
        }
 
@@ -7760,7 +7998,7 @@ alpha_expand_epilogue (void)
        FRP (emit_move_insn (stack_pointer_rtx,
                             gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
     }
-  else 
+  else
     {
       if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER)
         {
@@ -7905,7 +8143,7 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn_locators_initialize ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
+  final (insn, file, 1);
   final_end_function ();
 }
 #endif /* TARGET_ABI_OSF */
@@ -7919,14 +8157,6 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
 
 int sdb_label_count = 0;
 
-/* Next label # for each statement.  */
-
-static int sym_lineno = 0;
-
-/* Count the number of .file directives, so that .loc is up to date.  */
-
-static int num_source_filenames = 0;
-
 /* Name of the file containing the current function.  */
 
 static const char *current_function_file = "";
@@ -7942,7 +8172,6 @@ void
 alpha_output_filename (FILE *stream, const char *name)
 {
   static int first_time = TRUE;
-  char ltext_label_name[100];
 
   if (first_time)
     {
@@ -7957,12 +8186,8 @@ alpha_output_filename (FILE *stream, const char *name)
     }
 
   else if (write_symbols == DBX_DEBUG)
-    {
-      ASM_GENERATE_INTERNAL_LABEL (ltext_label_name, "Ltext", 0);
-      fprintf (stream, "%s", ASM_STABS_OP);
-      output_quoted_string (stream, name);
-      fprintf (stream, ",%d,0,0,%s\n", N_SOL, &ltext_label_name[1]);
-    }
+    /* dbxout.c will emit an appropriate .stabs directive.  */
+    return;
 
   else if (name != current_function_file
           && strcmp (name, current_function_file) != 0)
@@ -7980,22 +8205,6 @@ alpha_output_filename (FILE *stream, const char *name)
       fprintf (stream, "\n");
     }
 }
-
-/* Emit a linenumber to a stream.  */
-
-void
-alpha_output_lineno (FILE *stream, int line)
-{
-  if (write_symbols == DBX_DEBUG)
-    {
-      /* mips-tfile doesn't understand .stabd directives.  */
-      ++sym_lineno;
-      fprintf (stream, "$LM%d:\n%s%d,0,%d,$LM%d\n",
-              sym_lineno, ASM_STABN_OP, N_SLINE, line, sym_lineno);
-    }
-  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.  */
 
@@ -8106,7 +8315,7 @@ summarize_insn (rtx x, struct shadow_summary *sum, int set)
     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: 
+    case SQRT:  case FFS:
       summarize_insn (XEXP (x, 0), sum, 0);
       break;
 
@@ -8128,7 +8337,7 @@ summarize_insn (rtx x, struct shadow_summary *sum, int set)
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
     }
 }
@@ -8179,7 +8388,7 @@ alpha_handle_trap_shadows (void)
   shadow.used.fp = 0;
   shadow.used.mem = 0;
   shadow.defd = shadow.used;
-  
+
   for (i = get_insns (); i ; i = NEXT_INSN (i))
     {
       if (GET_CODE (i) == NOTE)
@@ -8226,7 +8435,7 @@ alpha_handle_trap_shadows (void)
                  switch (GET_CODE (i))
                    {
                    case INSN:
-                     /* Annoyingly, get_attr_trap will abort on these.  */
+                     /* Annoyingly, get_attr_trap will die on these.  */
                      if (GET_CODE (PATTERN (i)) == USE
                          || GET_CODE (PATTERN (i)) == CLOBBER)
                        break;
@@ -8253,10 +8462,9 @@ alpha_handle_trap_shadows (void)
                          || (sum.defd.mem & shadow.used.mem))
                        {
                          /* (a) would be violated (also takes care of (b))  */
-                         if (get_attr_trap (i) == TRAP_YES
-                             && ((sum.defd.i & sum.used.i)
-                                 || (sum.defd.fp & sum.used.fp)))
-                           abort ();
+                         gcc_assert (get_attr_trap (i) != TRAP_YES
+                                     || (!(sum.defd.i & sum.used.i)
+                                         && !(sum.defd.fp & sum.used.fp)));
 
                          goto close_shadow;
                        }
@@ -8268,7 +8476,7 @@ alpha_handle_trap_shadows (void)
                      goto close_shadow;
 
                    default:
-                     abort ();
+                     gcc_unreachable ();
                    }
                }
              else
@@ -8331,21 +8539,22 @@ alphaev4_insn_pipe (rtx insn)
   switch (get_attr_type (insn))
     {
     case TYPE_ILD:
+    case TYPE_LDSYM:
     case TYPE_FLD:
+    case TYPE_LD_L:
       return EV4_IBX;
 
-    case TYPE_LDSYM:
     case TYPE_IADD:
     case TYPE_ILOG:
     case TYPE_ICMOV:
     case TYPE_ICMP:
-    case TYPE_IST:
     case TYPE_FST:
     case TYPE_SHIFT:
     case TYPE_IMUL:
     case TYPE_FBR:
       return EV4_IB0;
 
+    case TYPE_IST:
     case TYPE_MISC:
     case TYPE_IBR:
     case TYPE_JSR:
@@ -8355,10 +8564,12 @@ alphaev4_insn_pipe (rtx insn)
     case TYPE_FADD:
     case TYPE_FDIV:
     case TYPE_FMUL:
+    case TYPE_ST_C:
+    case TYPE_MB:
       return EV4_IB1;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -8387,6 +8598,9 @@ alphaev5_insn_pipe (rtx insn)
     case TYPE_IMUL:
     case TYPE_MISC:
     case TYPE_MVI:
+    case TYPE_LD_L:
+    case TYPE_ST_C:
+    case TYPE_MB:
       return EV5_E0;
 
     case TYPE_IBR:
@@ -8407,13 +8621,13 @@ alphaev5_insn_pipe (rtx insn)
       return EV5_FM;
 
     default:
-      abort();
+      gcc_unreachable ();
     }
 }
 
-/* IN_USE is a mask of the slots currently filled within the insn group. 
+/* IN_USE is a mask of the slots currently filled within the insn group.
    The mask bits come from alphaev4_pipe above.  If EV4_IBX is set, then
-   the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1. 
+   the insn in EV4_IB0 can be swapped by the hardware into EV4_IB1.
 
    LEN is, of course, the length of the group in bytes.  */
 
@@ -8441,7 +8655,7 @@ alphaev4_next_group (rtx insn, int *pin_use, int *plen)
          if (in_use)
            goto done;
 
-         /* If this is a completely unrecognized insn, its an asm.
+         /* If this is a completely unrecognized insn, it's an asm.
             We don't know how long it is, so record length as -1 to
             signal a needed realignment.  */
          if (recog_memoized (insn) < 0)
@@ -8478,10 +8692,10 @@ alphaev4_next_group (rtx insn, int *pin_use, int *plen)
          break;
 
        default:
-         abort();
+         gcc_unreachable ();
        }
       len += 4;
-      
+
       /* Haifa doesn't do well scheduling branches.  */
       if (GET_CODE (insn) == JUMP_INSN)
        goto next_and_done;
@@ -8509,9 +8723,9 @@ alphaev4_next_group (rtx insn, int *pin_use, int *plen)
   return insn;
 }
 
-/* IN_USE is a mask of the slots currently filled within the insn group. 
+/* IN_USE is a mask of the slots currently filled within the insn group.
    The mask bits come from alphaev5_pipe above.  If EV5_E01 is set, then
-   the insn in EV5_E0 can be swapped by the hardware into EV5_E1. 
+   the insn in EV5_E0 can be swapped by the hardware into EV5_E1.
 
    LEN is, of course, the length of the group in bytes.  */
 
@@ -8539,7 +8753,7 @@ alphaev5_next_group (rtx insn, int *pin_use, int *plen)
          if (in_use)
            goto done;
 
-         /* If this is a completely unrecognized insn, its an asm.
+         /* If this is a completely unrecognized insn, it's an asm.
             We don't know how long it is, so record length as -1 to
             signal a needed realignment.  */
          if (recog_memoized (insn) < 0)
@@ -8548,11 +8762,11 @@ alphaev5_next_group (rtx insn, int *pin_use, int *plen)
            len = get_attr_length (insn);
          goto next_and_done;
 
-       /* ??? Most of the places below, we would like to abort, as 
-          it would indicate an error either in Haifa, or in the 
-          scheduling description.  Unfortunately, Haifa never 
-          schedules the last instruction of the BB, so we don't
-          have an accurate TI bit to go off.  */
+       /* ??? Most of the places below, we would like to assert never
+          happen, as it would indicate an error either in Haifa, or
+          in the scheduling description.  Unfortunately, Haifa never
+          schedules the last instruction of the BB, so we don't have
+          an accurate TI bit to go off.  */
        case EV5_E01:
          if (in_use & EV5_E0)
            {
@@ -8607,10 +8821,10 @@ alphaev5_next_group (rtx insn, int *pin_use, int *plen)
          break;
 
        default:
-         abort();
+         gcc_unreachable ();
        }
       len += 4;
-      
+
       /* Haifa doesn't do well scheduling branches.  */
       /* ??? If this is predicted not-taken, slotting continues, except
         that no more IBR, FBR, or JSR insns may be slotted.  */
@@ -8742,8 +8956,7 @@ alpha_align_insns (unsigned int max_align,
 
          else if (ofs & (new_align-1))
            ofs = (ofs | (new_align-1)) + 1;
-         if (len != 0)
-           abort();
+         gcc_assert (!len);
        }
 
       /* Handle complex instructions special.  */
@@ -8809,7 +9022,7 @@ alpha_align_insns (unsigned int max_align,
          else
            where = i;
 
-         do 
+         do
            emit_insn_before ((*next_nop)(&prev_in_use), where);
          while (--nop_count);
          ofs = 0;
@@ -8836,9 +9049,9 @@ alpha_reorg (void)
       && alpha_tp != ALPHA_TP_INSN
       && flag_schedule_insns_after_reload)
     {
-      if (alpha_cpu == PROCESSOR_EV4)
+      if (alpha_tune == PROCESSOR_EV4)
        alpha_align_insns (8, alphaev4_next_group, alphaev4_next_nop);
-      else if (alpha_cpu == PROCESSOR_EV5)
+      else if (alpha_tune == PROCESSOR_EV5)
        alpha_align_insns (16, alphaev5_next_group, alphaev5_next_nop);
     }
 }
@@ -8871,12 +9084,22 @@ alpha_file_start (void)
   if (TARGET_EXPLICIT_RELOCS)
     fputs ("\t.set nomacro\n", asm_out_file);
   if (TARGET_SUPPORT_ARCH | TARGET_BWX | TARGET_MAX | TARGET_FIX | TARGET_CIX)
-    fprintf (asm_out_file,
-            "\t.arch %s\n",
-            TARGET_CPU_EV6 ? "ev6"        
-            : (TARGET_CPU_EV5
-               ? (TARGET_MAX ? "pca56" : TARGET_BWX ? "ev56" : "ev5")
-               : "ev4"));
+    {
+      const char *arch;
+
+      if (alpha_cpu == PROCESSOR_EV6 || TARGET_FIX || TARGET_CIX)
+       arch = "ev6";
+      else if (TARGET_MAX)
+       arch = "pca56";
+      else if (TARGET_BWX)
+       arch = "ev56";
+      else if (alpha_cpu == PROCESSOR_EV5)
+       arch = "ev5";
+      else
+       arch = "ev4";
+
+      fprintf (asm_out_file, "\t.arch %s\n", arch);
+    }
 }
 #endif
 
@@ -8981,7 +9204,7 @@ alpha_need_linkage (const char *name, int is_local)
       if (!alpha_funcs_tree)
         alpha_funcs_tree = splay_tree_new_ggc ((splay_tree_compare_fn)
                                               splay_tree_compare_pointers);
-    
+
       cfaf = (struct alpha_funcs *) ggc_alloc (sizeof (struct alpha_funcs));
 
       cfaf->links = 0;
@@ -9111,7 +9334,7 @@ alpha_use_linkage (rtx linkage, tree cfundecl, int lflag, int rflag)
     al->rkind = KIND_CODEADDR;
   else
     al->rkind = KIND_LINKAGE;
-      
+
   if (lflag)
     return gen_rtx_MEM (Pmode, plus_constant (al->linkage, 8));
   else
@@ -9215,7 +9438,8 @@ vms_section_type_flags (tree decl, const char *name, int reloc)
    the section; 0 if the default should be used.  */
 
 static void
-vms_asm_named_section (const char *name, unsigned int flags)
+vms_asm_named_section (const char *name, unsigned int flags, 
+                      tree decl ATTRIBUTE_UNUSED)
 {
   fputc ('\n', asm_out_file);
   fprintf (asm_out_file, ".section\t%s", name);
@@ -9234,7 +9458,7 @@ vms_asm_named_section (const char *name, unsigned int flags)
 
 /* Record an element in the table of global constructors.  SYMBOL is
    a SYMBOL_REF of the function to be called; PRIORITY is a number
-   between 0 and MAX_INIT_PRIORITY.  
+   between 0 and MAX_INIT_PRIORITY.
 
    Differs from default_ctors_section_asm_out_constructor in that the
    width of the .ctors entry is always 64 bits, rather than the 32 bits
@@ -9302,13 +9526,13 @@ int
 unicosmk_initial_elimination_offset (int from, int to)
 {
   int fixed_size;
-  
+
   fixed_size = alpha_sa_size();
   if (fixed_size != 0)
     fixed_size += 48;
 
   if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
-    return -fixed_size; 
+    return -fixed_size;
   else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
     return 0;
   else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
@@ -9316,10 +9540,10 @@ unicosmk_initial_elimination_offset (int from, int to)
            + ALPHA_ROUND (get_frame_size()));
   else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
     return (ALPHA_ROUND (fixed_size)
-           + ALPHA_ROUND (get_frame_size() 
+           + ALPHA_ROUND (get_frame_size()
                           + current_function_outgoing_args_size));
   else
-    abort ();
+    gcc_unreachable ();
 }
 
 /* Output the module name for .ident and .end directives. We have to strip
@@ -9333,7 +9557,7 @@ unicosmk_output_module_name (FILE *file)
   unsigned len = strlen (name);
   char *clean_name = alloca (len + 2);
   char *ptr = clean_name;
-  
+
   /* CAM only accepts module names that start with a letter or '$'. We
      prefix the module name with a '$' if necessary.  */
 
@@ -9403,8 +9627,7 @@ unicosmk_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
   const char *name;
   int len;
 
-  if (!decl) 
-    abort ();
+  gcc_assert (decl);
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
   name = default_strip_name_encoding (name);
@@ -9414,8 +9637,8 @@ unicosmk_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
     {
       char *string;
 
-      /* It is essential that we prefix the section name here because 
-        otherwise the section names generated for constructors and 
+      /* It is essential that we prefix the section name here because
+        otherwise the section names generated for constructors and
         destructors confuse collect2.  */
 
       string = alloca (len + 6);
@@ -9439,7 +9662,8 @@ unicosmk_unique_section (tree decl, int reloc ATTRIBUTE_UNUSED)
    the section; 0 if the default should be used.  */
 
 static void
-unicosmk_asm_named_section (const char *name, unsigned int flags)
+unicosmk_asm_named_section (const char *name, unsigned int flags, 
+                           tree decl ATTRIBUTE_UNUSED)
 {
   const char *kind;
 
@@ -9476,7 +9700,7 @@ unicosmk_insert_attributes (tree decl, tree *attr_ptr ATTRIBUTE_UNUSED)
 
 /* Output an alignment directive. We have to use the macro 'gcc@code@align'
    in code sections because .align fill unused space with zeroes.  */
-      
+
 void
 unicosmk_output_align (FILE *file, int align)
 {
@@ -9494,10 +9718,10 @@ void
 unicosmk_defer_case_vector (rtx lab, rtx vec)
 {
   struct machine_function *machine = cfun->machine;
-  
+
   vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
   machine->addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec,
-                                         machine->addr_list); 
+                                         machine->addr_list);
 }
 
 /* Output a case vector.  */
@@ -9543,7 +9767,7 @@ unicosmk_output_deferred_case_vectors (FILE *file)
 static const char *
 unicosmk_ssib_name (void)
 {
-  /* This is ok since CAM won't be able to deal with names longer than that 
+  /* This is ok since CAM won't be able to deal with names longer than that
      anyway.  */
 
   static char name[256];
@@ -9553,11 +9777,9 @@ unicosmk_ssib_name (void)
   int len;
 
   x = DECL_RTL (cfun->decl);
-  if (GET_CODE (x) != MEM)
-    abort ();
+  gcc_assert (GET_CODE (x) == MEM);
   x = XEXP (x, 0);
-  if (GET_CODE (x) != SYMBOL_REF)
-    abort ();
+  gcc_assert (GET_CODE (x) == SYMBOL_REF);
   fnname = XSTR (x, 0);
 
   len = strlen (fnname);
@@ -9571,8 +9793,8 @@ unicosmk_ssib_name (void)
   return name;
 }
 
-/* Set up the dynamic subprogram information block (DSIB) and update the 
-   frame pointer register ($15) for subroutines which have a frame. If the 
+/* Set up the dynamic subprogram information block (DSIB) and update the
+   frame pointer register ($15) for subroutines which have a frame. If the
    subroutine doesn't have a frame, simply increment $15.  */
 
 static void
@@ -9729,7 +9951,7 @@ char *
 unicosmk_text_section (void)
 {
   static int count = 0;
-  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code", 
+  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code",
                                 count++);
   return unicosmk_section_buf;
 }
@@ -9738,7 +9960,7 @@ char *
 unicosmk_data_section (void)
 {
   static int count = 1;
-  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data", 
+  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data",
                                 count++);
   return unicosmk_section_buf;
 }
@@ -9792,14 +10014,14 @@ unicosmk_output_externs (FILE *file)
   len = strlen (user_label_prefix);
   for (p = unicosmk_extern_head; p != 0; p = p->next)
     {
-      /* We have to strip the encoding and possibly remove user_label_prefix 
+      /* We have to strip the encoding and possibly remove user_label_prefix
         from the identifier in order to handle -fleading-underscore and
         explicit asm names correctly (cf. gcc.dg/asm-names-1.c).  */
       real_name = default_strip_name_encoding (p->name);
       if (len && p->name[0] == '*'
          && !memcmp (real_name, user_label_prefix, len))
        real_name += len;
-       
+
       name_tree = get_identifier (real_name);
       if (! TREE_ASM_WRITTEN (name_tree))
        {
@@ -9810,7 +10032,7 @@ unicosmk_output_externs (FILE *file)
        }
     }
 }
-      
+
 /* Record an extern.  */
 
 void
@@ -9838,10 +10060,10 @@ struct unicosmk_dex {
   const char *name;
 };
 
-/* List of identifiers which have been replaced by DEX expressions. The DEX 
+/* List of identifiers which have been replaced by DEX expressions. The DEX
    number is determined by the position in the list.  */
 
-static struct unicosmk_dex *unicosmk_dex_list = NULL; 
+static struct unicosmk_dex *unicosmk_dex_list = NULL;
 
 /* The number of elements in the DEX list.  */
 
@@ -9884,7 +10106,7 @@ unicosmk_need_dex (rtx x)
   struct unicosmk_dex *dex;
   const char *name;
   int i;
-  
+
   if (GET_CODE (x) != SYMBOL_REF)
     return 0;
 
@@ -9899,7 +10121,7 @@ unicosmk_need_dex (rtx x)
         return i;
       --i;
     }
-      
+
   dex = (struct unicosmk_dex *) xmalloc (sizeof (struct unicosmk_dex));
   dex->name = name;
   dex->next = unicosmk_dex_list;
@@ -9930,13 +10152,13 @@ unicosmk_output_dex (FILE *file)
       putc ('\n', file);
       --i;
     }
-  
+
   fprintf (file, "\t.dexend\n");
 }
 
 /* Output text that to appear at the beginning of an assembler file.  */
 
-static void 
+static void
 unicosmk_file_start (void)
 {
   int i;
@@ -9999,7 +10221,7 @@ unicosmk_file_end (void)
 
   unicosmk_output_externs (asm_out_file);
 
-  /* Output dex definitions used for functions whose names conflict with 
+  /* Output dex definitions used for functions whose names conflict with
      register names.  */
 
   unicosmk_output_dex (asm_out_file);
@@ -10148,17 +10370,23 @@ alpha_init_libfuncs (void)
 #define TARGET_INIT_BUILTINS alpha_init_builtins
 #undef  TARGET_EXPAND_BUILTIN
 #define TARGET_EXPAND_BUILTIN alpha_expand_builtin
+#undef  TARGET_FOLD_BUILTIN
+#define TARGET_FOLD_BUILTIN alpha_fold_builtin
 
 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
 #define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall
 #undef TARGET_CANNOT_COPY_INSN_P
 #define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM alpha_cannot_force_const_mem
 
 #if TARGET_ABI_OSF
 #undef TARGET_ASM_OUTPUT_MI_THUNK
 #define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf
 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#undef TARGET_STDARG_OPTIMIZE_HOOK
+#define TARGET_STDARG_OPTIMIZE_HOOK alpha_stdarg_optimize_hook
 #endif
 
 #undef TARGET_RTX_COSTS
@@ -10189,12 +10417,30 @@ alpha_init_libfuncs (void)
 #define TARGET_SPLIT_COMPLEX_ARG alpha_split_complex_arg
 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
 #define TARGET_GIMPLIFY_VA_ARG_EXPR alpha_gimplify_va_arg
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES alpha_arg_partial_bytes
+
+#undef TARGET_SCALAR_MODE_SUPPORTED_P
+#define TARGET_SCALAR_MODE_SUPPORTED_P alpha_scalar_mode_supported_p
+#undef TARGET_VECTOR_MODE_SUPPORTED_P
+#define TARGET_VECTOR_MODE_SUPPORTED_P alpha_vector_mode_supported_p
 
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list
 
+/* The Alpha architecture does not require sequential consistency.  See
+   http://www.cs.umd.edu/~pugh/java/memoryModel/AlphaReordering.html
+   for an example of how it can be violated in practice.  */
+#undef TARGET_RELAXED_ORDERING
+#define TARGET_RELAXED_ORDERING true
+
+#undef TARGET_DEFAULT_TARGET_FLAGS
+#define TARGET_DEFAULT_TARGET_FLAGS \
+  (TARGET_DEFAULT | TARGET_CPU_DEFAULT | TARGET_DEFAULT_EXPLICIT_RELOCS)
+#undef TARGET_HANDLE_OPTION
+#define TARGET_HANDLE_OPTION alpha_handle_option
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 \f
 #include "gt-alpha.h"
-