OSDN Git Service

2008-04-03 Jan Hubicka <jh@suse.cz>
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index eeff191..9e650b9 100644 (file)
@@ -1,13 +1,13 @@
 /* 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.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -16,9 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 #include "config.h"
@@ -53,10 +52,17 @@ Boston, MA 02111-1307, USA.  */
 #include <splay-tree.h>
 #include "cfglayout.h"
 #include "tree-gimple.h"
+#include "tree-flow.h"
+#include "tree-stdarg.h"
+#include "tm-constrs.h"
+#include "df.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[] =
 {
   "ev4", "ev5", "ev6"
@@ -74,20 +80,6 @@ enum alpha_fp_rounding_mode alpha_fprm;
 
 enum alpha_fp_trap_mode alpha_fptm;
 
-/* Specify bit size of immediate TLS offsets.  */
-
-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] */
-
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
 
@@ -108,7 +100,7 @@ static int alpha_function_needs_gp;
 
 /* The alias set for prologue/epilogue register save/restore.  */
 
-static GTY(()) int alpha_sr_alias_set;
+static GTY(()) alias_set_type alpha_sr_alias_set;
 
 /* The assembler name of the current function.  */
 
@@ -207,7 +199,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,40 +210,80 @@ 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_mtls_size_:
+      if (value != 16 && value != 32 && value != 64)
+       error ("bad value %qs for -mtls-size switch", arg);
+      break;
+    }
+
+  return true;
+}
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+/* Implement TARGET_MANGLE_TYPE.  */
+
+static const char *
+alpha_mangle_type (const_tree type)
+{
+  if (TYPE_MAIN_VARIANT (type) == long_double_type_node
+      && TARGET_LONG_DOUBLE_128)
+    return "g";
+
+  /* For all other types, use normal C++ mangling.  */
+  return NULL;
+}
+#endif
+
 /* 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;
     }
@@ -275,7 +307,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 +318,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 +335,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 +349,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 +364,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 +386,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 +420,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;
     }
 
@@ -440,14 +455,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 +472,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;
       }
 
@@ -502,6 +517,16 @@ override_options (void)
       REAL_MODE_FORMAT (DFmode) = &vax_g_format;
       REAL_MODE_FORMAT (TFmode) = NULL;
     }
+
+#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
+  if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
+    target_flags |= MASK_LONG_DOUBLE_128;
+#endif
+
+  /* If using typedef char *va_list, signal that __builtin_va_start (&ap, 0)
+     can be optimized to ap = __builtin_next_arg (0).  */
+  if (TARGET_ABI_UNICOSMK)
+    targetm.expand_builtin_va_start = NULL;
 }
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -534,27 +559,16 @@ tls_symbolic_operand_1 (rtx op, int size, int unspec)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
-  if (SYMBOL_REF_LOCAL_P (op))
-    {
-      if (alpha_tls_size > size)
-       return 0;
-    }
-  else
-    {
-      if (size != 64)
-       return 0;
-    }
-
   switch (SYMBOL_REF_TLS_MODEL (op))
     {
     case TLS_MODEL_LOCAL_DYNAMIC:
-      return unspec == UNSPEC_DTPREL;
+      return unspec == UNSPEC_DTPREL && size == alpha_tls_size;
     case TLS_MODEL_INITIAL_EXEC:
       return unspec == UNSPEC_TPREL && size == 64;
     case TLS_MODEL_LOCAL_EXEC:
-      return unspec == UNSPEC_TPREL;
+      return unspec == UNSPEC_TPREL && size == alpha_tls_size;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -580,96 +594,6 @@ resolve_reload_operand (rtx op)
   return op;
 }
 
-/* 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)
-{
-  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;
-    }
-}
-
-/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
-   matches for C in [GH].  */
-
-bool
-alpha_const_double_ok_for_letter_p (rtx value, int c)
-{
-  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)));
-
-    default:
-      return false;
-    }
-}
-
-/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
-   matches for C.  */
-
-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;
-    }
-}
-
 /* 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
@@ -798,7 +722,7 @@ tls_symbolic_operand_type (rtx symbol)
    function in the current unit of translation.  */
 
 static bool
-decl_has_samegp (tree decl)
+decl_has_samegp (const_tree decl)
 {
   /* Functions that are not local can be overridden, and thus may
      not share the same gp.  */
@@ -821,7 +745,7 @@ decl_has_samegp (tree decl)
 /* Return true if EXP should be placed in the small data section.  */
 
 static bool
-alpha_in_small_data_p (tree exp)
+alpha_in_small_data_p (const_tree exp)
 {
   /* We want to merge strings, so we never consider them small data.  */
   if (TREE_CODE (exp) == STRING_CST)
@@ -1013,7 +937,7 @@ alpha_legitimize_address (rtx x, rtx scratch,
      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
+  if (can_create_pseudo_p ()
       && GET_CODE (x) == CONST
       && GET_CODE (XEXP (x, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
@@ -1026,7 +950,7 @@ alpha_legitimize_address (rtx x, rtx scratch,
   /* 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
+  if (can_create_pseudo_p ()
       && GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == CONST
@@ -1047,6 +971,9 @@ alpha_legitimize_address (rtx x, rtx scratch,
 
       switch (tls_symbolic_operand_type (x))
        {
+       case TLS_MODEL_NONE:
+         break;
+
        case TLS_MODEL_GLOBAL_DYNAMIC:
          start_sequence ();
 
@@ -1135,6 +1062,9 @@ alpha_legitimize_address (rtx x, rtx scratch,
              emit_insn (gen_rtx_SET (VOIDmode, tp, insn));
            }
          return gen_rtx_LO_SUM (Pmode, tp, eqv);
+
+       default:
+         gcc_unreachable ();
        }
 
       if (local_symbolic_operand (x, Pmode))
@@ -1143,7 +1073,7 @@ alpha_legitimize_address (rtx x, rtx scratch,
            return x;
          else
            {
-             if (!no_new_pseudos)
+             if (can_create_pseudo_p ())
                scratch = gen_reg_rtx (Pmode);
              emit_insn (gen_rtx_SET (VOIDmode, scratch,
                                      gen_rtx_HIGH (Pmode, x)));
@@ -1165,11 +1095,11 @@ alpha_legitimize_address (rtx x, rtx scratch,
 
     if (addend)
       x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
-                              (no_new_pseudos ? scratch : NULL_RTX),
+                              (!can_create_pseudo_p () ? 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),
+                              (!can_create_pseudo_p () ? scratch : NULL_RTX),
                               1, OPTAB_LIB_WIDEN);
 
     return plus_constant (x, low);
@@ -1339,7 +1269,7 @@ alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
   if (optimize_size)
     cost_data = &alpha_rtx_cost_size;
   else
-    cost_data = &alpha_rtx_cost_data[alpha_cpu];
+    cost_data = &alpha_rtx_cost_data[alpha_tune];
 
   switch (code)
     {
@@ -1384,6 +1314,11 @@ alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
        *total = COSTS_N_INSNS (optimize_size ? 1 : alpha_memory_latency);
       return true;
 
+    case HIGH:
+      /* This is effectively an add_operand.  */
+      *total = 2;
+      return true;
+
     case PLUS:
     case MINUS:
       if (float_mode_p)
@@ -1463,11 +1398,17 @@ alpha_rtx_costs (rtx x, int code, int outer_code, int *total)
     case UNSIGNED_FLOAT:
     case FIX:
     case UNSIGNED_FIX:
-    case FLOAT_EXTEND:
     case FLOAT_TRUNCATE:
       *total = cost_data->fp_add;
       return false;
 
+    case FLOAT_EXTEND:
+      if (GET_CODE (XEXP (x, 0)) == MEM)
+       *total = 0;
+      else
+       *total = cost_data->fp_add;
+      return false;
+
     default:
       return false;
     }
@@ -1482,66 +1423,85 @@ void
 get_aligned_mem (rtx ref, rtx *paligned_mem, rtx *pbitnum)
 {
   rtx base;
-  HOST_WIDE_INT offset = 0;
+  HOST_WIDE_INT disp, offset;
 
-  if (GET_CODE (ref) != MEM)
-    abort ();
+  gcc_assert (GET_CODE (ref) == MEM);
 
   if (reload_in_progress
       && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     {
       base = find_replacement (&XEXP (ref, 0));
-
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
+      gcc_assert (memory_address_p (GET_MODE (ref), base));
     }
   else
-    {
-      base = XEXP (ref, 0);
-    }
+    base = XEXP (ref, 0);
 
   if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+    disp = INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+  else
+    disp = 0;
+
+  /* Find the byte offset within an aligned word.  If the memory itself is
+     claimed to be aligned, believe it.  Otherwise, aligned_memory_operand
+     will have examined the base register and determined it is aligned, and
+     thus displacements from it are naturally alignable.  */
+  if (MEM_ALIGN (ref) >= 32)
+    offset = 0;
+  else
+    offset = disp & 3;
 
-  *paligned_mem
-    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
+  /* Access the entire aligned word.  */
+  *paligned_mem = widen_memory_access (ref, SImode, -offset);
 
+  /* Convert the byte offset within the word to a bit offset.  */
   if (WORDS_BIG_ENDIAN)
-    *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
-                             + (offset & 3) * 8));
+    offset = 32 - (GET_MODE_BITSIZE (GET_MODE (ref)) + offset * 8);
   else
-    *pbitnum = GEN_INT ((offset & 3) * 8);
+    offset *= 8;
+  *pbitnum = GEN_INT (offset);
 }
 
 /* Similar, but just get the address.  Handle the two reload cases.
    Add EXTRA_OFFSET to the address we return.  */
 
 rtx
-get_unaligned_address (rtx ref, int extra_offset)
+get_unaligned_address (rtx ref)
 {
   rtx base;
   HOST_WIDE_INT offset = 0;
 
-  if (GET_CODE (ref) != MEM)
-    abort ();
+  gcc_assert (GET_CODE (ref) == MEM);
 
   if (reload_in_progress
       && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
     {
       base = find_replacement (&XEXP (ref, 0));
 
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
+      gcc_assert (memory_address_p (GET_MODE (ref), base));
     }
   else
-    {
-      base = XEXP (ref, 0);
-    }
+    base = XEXP (ref, 0);
 
   if (GET_CODE (base) == PLUS)
     offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  return plus_constant (base, offset + extra_offset);
+  return plus_constant (base, offset);
+}
+
+/* Compute a value X, such that X & 7 == (ADDR + OFS) & 7.
+   X is always returned in a register.  */
+
+rtx
+get_unaligned_offset (rtx addr, HOST_WIDE_INT ofs)
+{
+  if (GET_CODE (addr) == PLUS)
+    {
+      ofs += INTVAL (XEXP (addr, 1));
+      addr = XEXP (addr, 0);
+    }
+
+  return expand_simple_binop (Pmode, PLUS, addr, GEN_INT (ofs & 7),
+                             NULL_RTX, 1, OPTAB_LIB_WIDEN);
 }
 
 /* On the Alpha, all (non-symbolic) constants except zero go into
@@ -1557,7 +1517,9 @@ alpha_preferred_reload_class(rtx x, enum reg_class class)
     return class;
 
   /* These sorts of constants we can easily drop to memory.  */
-  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+  if (GET_CODE (x) == CONST_INT
+      || GET_CODE (x) == CONST_DOUBLE
+      || GET_CODE (x) == CONST_VECTOR)
     {
       if (class == FLOAT_REGS)
        return NO_REGS;
@@ -1575,47 +1537,39 @@ alpha_preferred_reload_class(rtx x, enum reg_class class)
   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.
+/* Inform reload about cases where moving X with a mode MODE to a register in
+   CLASS requires an extra scratch or immediate register.  Return the class
+   needed for the immediate register.  */
 
-   We also cannot do integral arithmetic into FP regs, as might result
-   from register elimination into a DImode fp register.  */
-
-enum reg_class
-secondary_reload_class (enum reg_class class, enum machine_mode mode,
-                       rtx x, int in)
+static enum reg_class
+alpha_secondary_reload (bool in_p, rtx x, enum reg_class class,
+                       enum machine_mode mode, secondary_reload_info *sri)
 {
-  if ((mode == QImode || mode == HImode) && ! TARGET_BWX)
+  /* Loading and storing HImode or QImode values to and from memory
+     usually requires a scratch register.  */
+  if (!TARGET_BWX && (mode == QImode || mode == HImode || mode == CQImode))
     {
-      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 (any_memory_operand (x, mode))
        {
-         if (!in || !aligned_memory_operand(x, mode))
-           return GENERAL_REGS;
+         if (in_p)
+           {
+             if (!aligned_memory_operand (x, mode))
+               sri->icode = reload_in_optab[mode];
+           }
+         else
+           sri->icode = reload_out_optab[mode];
+         return NO_REGS;
        }
     }
 
+  /* We also cannot do integral arithmetic into FP regs, as might result
+     from register elimination into a DImode fp register.  */
   if (class == FLOAT_REGS)
     {
-      if (GET_CODE (x) == MEM && GET_CODE (XEXP (x, 0)) == AND)
-       return GENERAL_REGS;
-
-      if (GET_CODE (x) == SUBREG
-         && (GET_MODE_SIZE (GET_MODE (x))
-             > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+      if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == AND)
        return GENERAL_REGS;
-
-      if (in && INTEGRAL_MODE_P (mode)
-         && ! (memory_operand (x, mode) || x == const0_rtx))
+      if (in_p && INTEGRAL_MODE_P (mode)
+         && !MEM_P (x) && !REG_P (x) && !CONST_INT_P (x))
        return GENERAL_REGS;
     }
 
@@ -1679,17 +1633,22 @@ alpha_set_memflags (rtx insn, rtx ref)
   for_each_rtx (base_ptr, alpha_set_memflags_1, (void *) ref);
 }
 \f
-/* Internal routine for alpha_emit_set_const to check for N or below insns.  */
+static rtx alpha_emit_set_const (rtx, enum machine_mode, HOST_WIDE_INT,
+                                int, bool);
+
+/* 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.  */
 
 static rtx
 alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
-                       HOST_WIDE_INT c, int n)
+                       HOST_WIDE_INT c, int n, bool no_output)
 {
   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);
+    = (flag_expensive_optimizations && can_create_pseudo_p () ? 0 : target);
   rtx temp, insn;
 
   /* If this is a sign-extended 32-bit constant, we can do this in at most
@@ -1722,6 +1681,8 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
             emit_move_insn to gen_movdi.  So instead, since we know exactly
             what we want, create it explicitly.  */
 
+         if (no_output)
+           return pc_rtx;
          if (target == NULL)
            target = gen_reg_rtx (mode);
          emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (c)));
@@ -1729,7 +1690,9 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
        }
       else if (n >= 2 + (extra != 0))
        {
-         if (no_new_pseudos)
+         if (no_output)
+           return pc_rtx;
+         if (!can_create_pseudo_p ())
            {
              emit_insn (gen_rtx_SET (VOIDmode, target, GEN_INT (high << 16)));
              temp = target;
@@ -1768,7 +1731,7 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
      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))
+  if (n == 1 || (mode == SImode && !can_create_pseudo_p ()))
     return 0;
 
   /* Next, see if we can load a related constant and then shift and possibly
@@ -1781,14 +1744,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
         high bits.  */
 
       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 (new != 0)
+       {
+          temp = alpha_emit_set_const (subtarget, mode, c - new, i, no_output);
+         if (temp)
+           {
+             if (no_output)
+               return temp;
+             return expand_binop (mode, add_optab, temp, GEN_INT (new),
+                                  target, 0, OPTAB_WIDEN);
+           }
+       }
 
       /* Next try complementing.  */
-      if ((temp = alpha_emit_set_const (subtarget, mode, ~ c, i)) != 0)
-       return expand_unop (mode, one_cmpl_optab, temp, target, 0);
+      temp = alpha_emit_set_const (subtarget, mode, ~c, i, no_output);
+      if (temp)
+       {
+         if (no_output)
+           return temp;
+         return expand_unop (mode, one_cmpl_optab, temp, target, 0);
+       }
 
       /* 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
@@ -1799,16 +1774,26 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
         bits to shift, but try all possibilities in case a ZAPNOT will
         be useful.  */
 
-      if ((bits = exact_log2 (c & - c)) > 0)
+      bits = exact_log2 (c & -c);
+      if (bits > 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);
+         {
+           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);
+             }
+         }
 
       /* 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
@@ -1816,35 +1801,53 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
       /* 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 ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (c) - 1 - (HOST_BITS_PER_WIDE_INT < 64))) > 0)
+      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--)
-         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);
+         {
+           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);
+             }
+         }
 
       /* 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.  */
 
-      if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
-                  - floor_log2 (~ c) - 2)) > 0)
+      bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
+             - floor_log2 (~ c) - 2);
+      if (bits > 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);
+         {
+           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);
+             }
+         }
     }
 
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -1863,10 +1866,17 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
   if (mode == SImode)
     new = ((new & 0xffffffff) ^ 0x80000000) - 0x80000000;
 
-  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);
+  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 0;
@@ -1878,32 +1888,46 @@ alpha_emit_set_const_1 (rtx target, enum machine_mode mode,
    emitted.  If it would take more than N insns, zero is returned and no
    insns and emitted.  */
 
-rtx
+static rtx
 alpha_emit_set_const (rtx target, enum machine_mode mode,
-                     HOST_WIDE_INT c, int n)
+                     HOST_WIDE_INT c, int n, bool no_output)
 {
-  rtx result = 0;
+  enum machine_mode orig_mode = mode;
   rtx orig_target = target;
+  rtx result = 0;
   int i;
 
   /* 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 (!can_create_pseudo_p () && 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;
+
+      target = no_output ? NULL : gen_lowpart (DImode, target);
+      mode = DImode;
+    }
+  else if (mode == V8QImode || mode == V4HImode || mode == V2SImode)
     {
-      target = gen_lowpart (DImode, target);
+      target = no_output ? NULL : gen_lowpart (DImode, target);
       mode = DImode;
     }
 
   /* 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);
+      result = alpha_emit_set_const_1 (target, mode, c, i, no_output);
       if (result)
        {
-         rtx insn = get_last_insn ();
-         rtx set = single_set (insn);
+         rtx insn, set;
+
+         if (no_output)
+           return result;
+
+         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;
@@ -1911,8 +1935,13 @@ alpha_emit_set_const (rtx target, enum machine_mode mode,
     }
 
   /* Allow for the case where we changed the mode of TARGET.  */
-  if (result == target)
-    result = orig_target;
+  if (result)
+    {
+      if (result == target)
+       result = orig_target;
+      else if (mode != orig_mode)
+       result = gen_lowpart (orig_mode, result);
+    }
 
   return result;
 }
@@ -1922,15 +1951,14 @@ alpha_emit_set_const (rtx target, enum machine_mode mode,
    exponential run times encountered when looking for longer sequences
    with alpha_emit_set_const.  */
 
-rtx
+static rtx
 alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
 {
   HOST_WIDE_INT d1, d2, d3, d4;
 
   /* Decompose the entire word */
 #if HOST_BITS_PER_WIDE_INT >= 64
-  if (c2 != -(c1 < 0))
-    abort ();
+  gcc_assert (c2 == -(c1 < 0));
   d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
   c1 -= d1;
   d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
@@ -1938,20 +1966,17 @@ alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
   d3 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
   c1 -= d3;
   d4 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c1 != d4)
-    abort ();
+  gcc_assert (c1 == d4);
 #else
   d1 = ((c1 & 0xffff) ^ 0x8000) - 0x8000;
   c1 -= d1;
   d2 = ((c1 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c1 != d2)
-    abort ();
+  gcc_assert (c1 == d2);
   c2 += (d2 < 0);
   d3 = ((c2 & 0xffff) ^ 0x8000) - 0x8000;
   c2 -= d3;
   d4 = ((c2 & 0xffffffff) ^ 0x80000000) - 0x80000000;
-  if (c2 != d4)
-    abort ();
+  gcc_assert (c2 == d4);
 #endif
 
   /* Construct the high word */
@@ -1976,42 +2001,128 @@ alpha_emit_set_long_const (rtx target, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
   return target;
 }
 
-/* Expand a move instruction; return true if all work is done.
-   We don't handle non-bwx subword loads here.  */
+/* 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);
+    }
+
+  *p0 = i0;
+  *p1 = i1;
+}
+
+/* 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_expand_mov (enum machine_mode mode, rtx *operands)
+alpha_legitimate_constant_p (rtx x)
 {
-  /* Honor misaligned loads, for those we promised to do so.  */
-  if (GET_CODE (operands[1]) == MEM
-      && alpha_vector_mode_supported_p (mode)
-      && MEM_ALIGN (operands[1]) < GET_MODE_ALIGNMENT (mode))
+  enum machine_mode mode = GET_MODE (x);
+  HOST_WIDE_INT i0, i1;
+
+  switch (GET_CODE (x))
     {
-      rtx tmp;
-      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])
+    case CONST:
+    case LABEL_REF:
+    case HIGH:
+      return true;
+
+    case SYMBOL_REF:
+      /* TLS symbols are never valid.  */
+      return SYMBOL_REF_TLS_MODEL (x) == 0;
+
+    case CONST_DOUBLE:
+      if (x == CONST0_RTX (mode))
+       return true;
+      if (FLOAT_MODE_P (mode))
+       return false;
+      goto do_integer;
+
+    case CONST_VECTOR:
+      if (x == CONST0_RTX (mode))
        return true;
-      operands[1] = tmp;
+      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;
     }
 
+  return false;
+}
+
+/* Expand a move instruction; return true if all work is done.
+   We don't handle non-bwx subword loads here.  */
+
+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]);
 
-  /* Honor misaligned stores, for those we promised to do so.  */
-  if (GET_CODE (operands[0]) == MEM
-      && alpha_vector_mode_supported_p (mode)
-      && MEM_ALIGN (operands[0]) < GET_MODE_ALIGNMENT (mode))
-    {
-      alpha_expand_unaligned_store (operands[0], operands[1], 8, 0);
-      return true;
-    }
-
   /* Allow legitimize_address to perform some simplifications.  */
   if (mode == Pmode && symbolic_operand (operands[1], mode))
     {
@@ -2033,49 +2144,19 @@ alpha_expand_mov (enum machine_mode mode, rtx *operands)
 
   /* Split large integers.  */
   if (GET_CODE (operands[1]) == CONST_INT
-      || GET_CODE (operands[1]) == CONST_DOUBLE)
+      || GET_CODE (operands[1]) == CONST_DOUBLE
+      || GET_CODE (operands[1]) == CONST_VECTOR)
     {
-      HOST_WIDE_INT i0, i1;
-      rtx temp = NULL_RTX;
-
-      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 (HOST_BITS_PER_WIDE_INT >= 64 || i1 == -(i0 < 0))
-       temp = alpha_emit_set_const (operands[0], mode, i0, 3);
-
-      if (!temp && TARGET_BUILD_CONSTANTS)
-       temp = alpha_emit_set_long_const (operands[0], i0, i1);
-
-      if (temp)
-       {
-         if (rtx_equal_p (operands[0], temp))
-           return true;
-         operands[1] = temp;
-         return false;
-       }
-    }
+      if (alpha_split_const_mov (mode, operands))
+       return true;
+    }
 
   /* Otherwise we've nothing left but to drop the thing to memory.  */
   operands[1] = force_const_mem (mode, operands[1]);
   if (reload_in_progress)
     {
       emit_move_insn (operands[0], XEXP (operands[1], 0));
-      operands[1] = copy_rtx (operands[1]);
-      XEXP (operands[1], 0) = operands[0];
+      operands[1] = replace_equiv_address (operands[1], operands[0]);
     }
   else
     operands[1] = validize_mem (operands[1]);
@@ -2088,32 +2169,27 @@ alpha_expand_mov (enum machine_mode mode, rtx *operands)
 bool
 alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
 {
+  rtx seq;
+
   /* If the output is not a register, the input must be.  */
-  if (GET_CODE (operands[0]) == MEM)
+  if (MEM_P (operands[0]))
     operands[1] = force_reg (mode, operands[1]);
 
   /* 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 (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 (any_memory_operand (operands[1], mode))
     {
       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]))));
+             if (mode == QImode)
+               seq = gen_reload_inqi_aligned (operands[0], operands[1]);
+             else
+               seq = gen_reload_inhi_aligned (operands[0], operands[1]);
+             emit_insn (seq);
            }
          else
            {
@@ -2130,10 +2206,13 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
              else
                subtarget = gen_reg_rtx (DImode), copyout = true;
 
-             emit_insn ((mode == QImode
-                         ? gen_aligned_loadqi
-                         : gen_aligned_loadhi)
-                        (subtarget, aligned_mem, bitnum, scratch));
+             if (mode == QImode)
+               seq = gen_aligned_loadqi (subtarget, aligned_mem,
+                                         bitnum, scratch);
+             else
+               seq = gen_aligned_loadhi (subtarget, aligned_mem,
+                                         bitnum, scratch);
+             emit_insn (seq);
 
              if (copyout)
                emit_move_insn (operands[0], gen_lowpart (mode, subtarget));
@@ -2145,7 +2224,7 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
             code depend on parameter evaluation order which will cause
             bootstrap failures.  */
 
-         rtx temp1, temp2, seq, subtarget;
+         rtx temp1, temp2, subtarget, ua;
          bool copyout;
 
          temp1 = gen_reg_rtx (DImode);
@@ -2157,11 +2236,12 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
          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));
+         ua = get_unaligned_address (operands[1]);
+         if (mode == QImode)
+           seq = gen_unaligned_loadqi (subtarget, ua, temp1, temp2);
+         else
+           seq = gen_unaligned_loadhi (subtarget, ua, temp1, temp2);
+
          alpha_set_memflags (seq, operands[1]);
          emit_insn (seq);
 
@@ -2171,14 +2251,7 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
       return true;
     }
 
-  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 (any_memory_operand (operands[0], mode))
     {
       if (aligned_memory_operand (operands[0], mode))
        {
@@ -2196,11 +2269,12 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
          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));
+         rtx ua = get_unaligned_address (operands[0]);
+
+         if (mode == QImode)
+           seq = gen_unaligned_storeqi (ua, operands[1], temp1, temp2, temp3);
+         else
+           seq = gen_unaligned_storehi (ua, operands[1], temp1, temp2, temp3);
 
          alpha_set_memflags (seq, operands[0]);
          emit_insn (seq);
@@ -2211,6 +2285,36 @@ alpha_expand_mov_nobwx (enum machine_mode mode, rtx *operands)
   return false;
 }
 
+/* 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)
+{
+  /* Honor misaligned loads, for those we promised to do so.  */
+  if (MEM_P (operands[1]))
+    {
+      rtx tmp;
+
+      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]))
+    {
+      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 ();
+}
+
 /* Generate an unsigned DImode to FP conversion.  This is the same code
    optabs would emit if we didn't have TFmode patterns.
 
@@ -2305,36 +2409,7 @@ alpha_emit_conditional_branch (enum rtx_code code)
 
   if (alpha_compare.fp_p && GET_MODE (op0) == TFmode)
     {
-      if (! TARGET_HAS_XFLOATING_LIBS)
-       abort ();
-
-      /* X_floating library comparison functions return
-          -1  unordered
-           0  false
-           1  true
-        Convert the compare against the raw return value.  */
-
-      switch (code)
-       {
-       case UNORDERED:
-         cmp_code = EQ;
-         code = LT;
-         break;
-       case ORDERED:
-         cmp_code = EQ;
-         code = GE;
-         break;
-       case NE:
-         cmp_code = NE;
-         code = NE;
-         break;
-       default:
-         cmp_code = code;
-         code = GT;
-         break;
-       }
-
-      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+      op0 = alpha_emit_xfloating_compare (&code, op0, op1);
       op1 = const0_rtx;
       alpha_compare.fp_p = 0;
     }
@@ -2371,7 +2446,7 @@ alpha_emit_conditional_branch (enum rtx_code code)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (alpha_compare.fp_p)
@@ -2421,15 +2496,12 @@ alpha_emit_conditional_branch (enum rtx_code code)
                   && !(symbolic_operand (op0, VOIDmode)
                        || (GET_CODE (op0) == REG && REG_POINTER (op0))))
            {
-             HOST_WIDE_INT v = INTVAL (op1), n = -v;
+             rtx n_op1 = GEN_INT (-INTVAL (op1));
 
-             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);
-               }
+             if (! satisfies_constraint_I (op1)
+                 && (satisfies_constraint_K (n_op1)
+                     || satisfies_constraint_L (n_op1)))
+               cmp_code = PLUS, branch_code = code, op1 = n_op1;
            }
        }
 
@@ -2470,30 +2542,9 @@ alpha_emit_setcc (enum rtx_code code)
 
   if (fp_p && GET_MODE (op0) == TFmode)
     {
-      if (! TARGET_HAS_XFLOATING_LIBS)
-       abort ();
-
-      /* X_floating library comparison functions return
-          -1  unordered
-           0  false
-           1  true
-        Convert the compare against the raw return value.  */
-
-      if (code == UNORDERED || code == ORDERED)
-       cmp_code = EQ;
-      else
-       cmp_code = code;
-
-      op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
+      op0 = alpha_emit_xfloating_compare (&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)
@@ -2534,7 +2585,7 @@ alpha_emit_setcc (enum rtx_code code)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (!fp_p)
@@ -2626,7 +2677,7 @@ alpha_emit_conditional_move (rtx cmp, enum machine_mode mode)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       tem = gen_reg_rtx (cmp_op_mode);
@@ -2653,7 +2704,7 @@ alpha_emit_conditional_move (rtx cmp, enum machine_mode mode)
      conditional move.  Make sure we emit only comparisons we have;
      swap or reverse as necessary.  */
 
-  if (no_new_pseudos)
+  if (!can_create_pseudo_p ())
     return NULL_RTX;
 
   switch (code)
@@ -2678,7 +2729,7 @@ alpha_emit_conditional_move (rtx cmp, enum machine_mode mode)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   if (!fp_p)
@@ -2730,7 +2781,7 @@ alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond,
   if (mode != DImode)
     {
       target = gen_lowpart (DImode, dest);
-      if (! no_new_pseudos)
+      if (can_create_pseudo_p ())
         subtarget = gen_reg_rtx (DImode);
       else
        subtarget = target;
@@ -2743,7 +2794,7 @@ alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond,
       /* 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))
+      && (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));
@@ -2831,6 +2882,8 @@ alpha_lookup_xfloating_lib_func (enum rtx_code code)
   long n = ARRAY_SIZE (xfloating_ops);
   long i;
 
+  gcc_assert (TARGET_HAS_XFLOATING_LIBS);
+
   /* How irritating.  Nothing to key off for the main table.  */
   if (TARGET_FLOAT_VAX && (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE))
     {
@@ -2851,7 +2904,7 @@ alpha_lookup_xfloating_lib_func (enum rtx_code code)
         return func;
       }
 
-  abort();
+  gcc_unreachable ();
 }
 
 /* Most X_floating operations take the rounding mode as an argument.
@@ -2878,7 +2931,7 @@ alpha_compute_xfloating_mode_arg (enum rtx_code code,
       mode = 4;
       break;
     default:
-      abort ();
+      gcc_unreachable ();
 
     /* XXX For reference, round to +inf is mode = 3.  */
     }
@@ -2926,8 +2979,7 @@ alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
          break;
 
        case VOIDmode:
-         if (GET_CODE (operands[i]) != CONST_INT)
-           abort ();
+         gcc_assert (GET_CODE (operands[i]) == CONST_INT);
          /* FALLTHRU */
        case DImode:
          reg = gen_rtx_REG (DImode, regno);
@@ -2935,7 +2987,7 @@ alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
 
       emit_move_insn (reg, operands[i]);
@@ -2954,7 +3006,7 @@ alpha_emit_xfloating_libcall (rtx func, rtx target, rtx operands[],
       reg = gen_rtx_REG (DImode, 0);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   tmp = gen_rtx_MEM (QImode, func);
@@ -2992,21 +3044,56 @@ alpha_emit_xfloating_arith (enum rtx_code code, rtx operands[])
 /* Emit an X_floating library function call for a comparison.  */
 
 static rtx
-alpha_emit_xfloating_compare (enum rtx_code code, rtx op0, rtx op1)
+alpha_emit_xfloating_compare (enum rtx_code *pcode, rtx op0, rtx op1)
 {
-  rtx func;
-  rtx out, operands[2];
+  enum rtx_code cmp_code, res_code;
+  rtx func, out, operands[2], note;
 
-  func = alpha_lookup_xfloating_lib_func (code);
+  /* X_floating library comparison functions return
+          -1  unordered
+           0  false
+           1  true
+     Convert the compare against the raw return value.  */
+
+  cmp_code = *pcode;
+  switch (cmp_code)
+    {
+    case UNORDERED:
+      cmp_code = EQ;
+      res_code = LT;
+      break;
+    case ORDERED:
+      cmp_code = EQ;
+      res_code = GE;
+      break;
+    case NE:
+      res_code = NE;
+      break;
+    case EQ:
+    case LT:
+    case GT:
+    case LE:
+    case GE:
+      res_code = GT;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  *pcode = res_code;
+
+  func = alpha_lookup_xfloating_lib_func (cmp_code);
 
   operands[0] = op0;
   operands[1] = op1;
   out = gen_reg_rtx (DImode);
 
-  /* ??? 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));
+  /* What's actually returned is -1,0,1, not a proper boolean value,
+     so use an EXPR_LIST as with a generic libcall instead of a 
+     comparison type expression.  */
+  note = gen_rtx_EXPR_LIST (VOIDmode, op1, NULL_RTX);
+  note = gen_rtx_EXPR_LIST (VOIDmode, op0, note);
+  note = gen_rtx_EXPR_LIST (VOIDmode, func, note);
+  alpha_emit_xfloating_libcall (func, out, operands, 2, note);
 
   return out;
 }
@@ -3050,40 +3137,62 @@ alpha_emit_xfloating_cvt (enum rtx_code orig_code, rtx operands[])
                                               operands[1]));
 }
 
-/* Split a TFmode OP[1] into DImode OP[2,3] and likewise for
-   OP[0] into OP[0,1].  Naturally, output operand ordering is
-   little-endian.  */
-
+/* Split a TImode or TFmode move from OP[1] to OP[0] into a pair of
+   DImode moves from OP[2,3] to OP[0,1].  If FIXUP_OVERLAP is true,
+   guarantee that the sequence
+     set (OP[0] OP[2])
+     set (OP[1] OP[3])
+   is valid.  Naturally, output operand ordering is little-endian.
+   This is used by *movtf_internal and *movti_internal.  */
+  
 void
-alpha_split_tfmode_pair (rtx operands[4])
+alpha_split_tmode_pair (rtx operands[4], enum machine_mode mode,
+                       bool fixup_overlap)
 {
-  if (GET_CODE (operands[1]) == REG)
+  switch (GET_CODE (operands[1]))
     {
+    case 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)
-    {
+      break;
+
+    case MEM:
       operands[3] = adjust_address (operands[1], DImode, 8);
       operands[2] = adjust_address (operands[1], DImode, 0);
+      break;
+
+    case CONST_INT:
+    case CONST_DOUBLE:
+      gcc_assert (operands[1] == CONST0_RTX (mode));
+      operands[2] = operands[3] = const0_rtx;
+      break;
+
+    default:
+      gcc_unreachable ();
     }
-  else if (operands[1] == CONST0_RTX (TFmode))
-    operands[2] = operands[3] = const0_rtx;
-  else
-    abort ();
 
-  if (GET_CODE (operands[0]) == REG)
+  switch (GET_CODE (operands[0]))
     {
+    case REG:
       operands[1] = gen_rtx_REG (DImode, REGNO (operands[0]) + 1);
       operands[0] = gen_rtx_REG (DImode, REGNO (operands[0]));
-    }
-  else if (GET_CODE (operands[0]) == MEM)
-    {
+      break;
+
+    case MEM:
       operands[1] = adjust_address (operands[0], DImode, 8);
       operands[0] = adjust_address (operands[0], DImode, 0);
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (fixup_overlap && reg_overlap_mentioned_p (operands[0], operands[3]))
+    {
+      rtx tmp;
+      tmp = operands[0], operands[0] = operands[1], operands[1] = tmp;
+      tmp = operands[2], operands[2] = operands[3], operands[3] = tmp;
     }
-  else
-    abort ();
 }
 
 /* Implement negtf2 or abstf2.  Op0 is destination, op1 is source,
@@ -3097,7 +3206,7 @@ alpha_split_tfmode_frobsign (rtx operands[3], rtx (*operation) (rtx, rtx, rtx))
   rtx scratch;
   int move;
 
-  alpha_split_tfmode_pair (operands);
+  alpha_split_tmode_pair (operands, TFmode, false);
 
   /* Detect three flavors of operand overlap.  */
   move = 1;
@@ -3164,6 +3273,35 @@ alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
   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
+       {
+         if (GET_MODE (tgt) != DImode)
+           addr = gen_lowpart (GET_MODE (tgt), addr);
+         emit_move_insn (tgt, addr);
+       }
+      return;
+    }
+
   meml = gen_reg_rtx (DImode);
   memh = gen_reg_rtx (DImode);
   addr = gen_reg_rtx (DImode);
@@ -3212,7 +3350,7 @@ alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
 
       /* 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.  */
+        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);
@@ -3240,7 +3378,7 @@ alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
              break;
 
            default:
-             abort ();
+             gcc_unreachable ();
            }
          emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr));
        }
@@ -3266,7 +3404,7 @@ alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
              break;
 
            default:
-             abort();
+             gcc_unreachable ();
            }
        }
 
@@ -3276,7 +3414,7 @@ alpha_expand_unaligned_load (rtx tgt, rtx mem, HOST_WIDE_INT size,
     }
 
   if (addr != tgt)
-    emit_move_insn (tgt, gen_lowpart(GET_MODE (tgt), addr));
+    emit_move_insn (tgt, gen_lowpart (GET_MODE (tgt), addr));
 }
 
 /* Similarly, use ins and msk instructions to perform unaligned stores.  */
@@ -3287,6 +3425,28 @@ alpha_expand_unaligned_store (rtx dst, rtx src,
 {
   rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
 
+  if (TARGET_BWX && size == 2)
+    {
+      if (src != const0_rtx)
+       {
+         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;
+
+      meml = adjust_address (dst, QImode, ofs);
+      memh = adjust_address (dst, QImode, ofs+1);
+      if (BYTES_BIG_ENDIAN)
+       addr = meml, meml = memh, memh = addr;
+
+      emit_move_insn (meml, dstl);
+      emit_move_insn (memh, dsth);
+      return;
+    }
+
   dstl = gen_reg_rtx (DImode);
   dsth = gen_reg_rtx (DImode);
   insl = gen_reg_rtx (DImode);
@@ -3770,8 +3930,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.  */
 
@@ -3858,16 +4017,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;
 }
 
@@ -3875,7 +4033,7 @@ int
 alpha_expand_block_clear (rtx operands[])
 {
   rtx bytes_rtx        = operands[1];
-  rtx align_rtx = operands[2];
+  rtx align_rtx = operands[3];
   HOST_WIDE_INT orig_bytes = INTVAL (bytes_rtx);
   HOST_WIDE_INT bytes = orig_bytes;
   HOST_WIDE_INT align = INTVAL (align_rtx) * BITS_PER_UNIT;
@@ -4165,10 +4323,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;
@@ -4185,8 +4345,6 @@ alpha_expand_zap_mask (HOST_WIDE_INT value)
 
       result = immed_double_const (mask_lo, mask_hi, DImode);
     }
-  else
-    abort ();
 
   return result;
 }
@@ -4210,6 +4368,311 @@ alpha_expand_builtin_vector_binop (rtx (*gen) (rtx, rtx, rtx),
 
   emit_insn ((*gen) (op0, op1, op2));
 }
+
+/* A subroutine of the atomic operation splitters.  Jump to LABEL if
+   COND is true.  Mark the jump as unlikely to be taken.  */
+
+static void
+emit_unlikely_jump (rtx cond, rtx label)
+{
+  rtx very_unlikely = GEN_INT (REG_BR_PROB_BASE / 100 - 1);
+  rtx x;
+
+  x = gen_rtx_IF_THEN_ELSE (VOIDmode, cond, 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);
+}
+
+/* A subroutine of the atomic operation splitters.  Emit a load-locked
+   instruction in MODE.  */
+
+static void
+emit_load_locked (enum machine_mode mode, rtx reg, rtx mem)
+{
+  rtx (*fn) (rtx, rtx) = NULL;
+  if (mode == SImode)
+    fn = gen_load_locked_si;
+  else if (mode == DImode)
+    fn = gen_load_locked_di;
+  emit_insn (fn (reg, mem));
+}
+
+/* A subroutine of the atomic operation splitters.  Emit a store-conditional
+   instruction in MODE.  */
+
+static void
+emit_store_conditional (enum machine_mode mode, rtx res, rtx mem, rtx val)
+{
+  rtx (*fn) (rtx, rtx, rtx) = NULL;
+  if (mode == SImode)
+    fn = gen_store_conditional_si;
+  else if (mode == DImode)
+    fn = gen_store_conditional_di;
+  emit_insn (fn (res, mem, val));
+}
+
+/* A subroutine of the atomic operation splitters.  Emit an insxl
+   instruction in MODE.  */
+
+static rtx
+emit_insxl (enum machine_mode mode, rtx op1, rtx op2)
+{
+  rtx ret = gen_reg_rtx (DImode);
+  rtx (*fn) (rtx, rtx, rtx);
+
+  if (WORDS_BIG_ENDIAN)
+    {
+      if (mode == QImode)
+       fn = gen_insbl_be;
+      else
+       fn = gen_inswl_be;
+    }
+  else
+    {
+      if (mode == QImode)
+       fn = gen_insbl_le;
+      else
+       fn = gen_inswl_le;
+    }
+  /* The insbl and inswl patterns require a register operand.  */
+  op1 = force_reg (mode, op1);
+  emit_insn (fn (ret, op1, op2));
+
+  return ret;
+}
+
+/* Expand 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 machine_mode mode = GET_MODE (mem);
+  rtx label, x, cond = gen_rtx_REG (DImode, REGNO (scratch));
+
+  emit_insn (gen_memory_barrier ());
+
+  label = gen_label_rtx ();
+  emit_label (label);
+  label = gen_rtx_LABEL_REF (DImode, label);
+
+  if (before == NULL)
+    before = scratch;
+  emit_load_locked (mode, before, mem);
+
+  if (code == NOT)
+    x = gen_rtx_AND (mode, gen_rtx_NOT (mode, before), 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));
+
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, cond, const0_rtx);
+  emit_unlikely_jump (x, label);
+
+  emit_insn (gen_memory_barrier ());
+}
+
+/* Expand a compare and swap operation.  */
+
+void
+alpha_split_compare_and_swap (rtx retval, rtx mem, rtx oldval, rtx newval,
+                             rtx scratch)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label1, label2, x, cond = gen_lowpart (DImode, scratch);
+
+  emit_insn (gen_memory_barrier ());
+
+  label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label1, 0));
+
+  emit_load_locked (mode, retval, mem);
+
+  x = gen_lowpart (DImode, retval);
+  if (oldval == const0_rtx)
+    x = gen_rtx_NE (DImode, x, const0_rtx);
+  else
+    {
+      x = gen_rtx_EQ (DImode, x, oldval);
+      emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+      x = gen_rtx_EQ (DImode, cond, const0_rtx);
+    }
+  emit_unlikely_jump (x, label2);
+
+  emit_move_insn (scratch, newval);
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, cond, const0_rtx);
+  emit_unlikely_jump (x, label1);
+
+  emit_insn (gen_memory_barrier ());
+  emit_label (XEXP (label2, 0));
+}
+
+void
+alpha_expand_compare_and_swap_12 (rtx dst, rtx mem, rtx oldval, rtx newval)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx addr, align, wdst;
+  rtx (*fn5) (rtx, rtx, rtx, rtx, rtx);
+
+  addr = force_reg (DImode, XEXP (mem, 0));
+  align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+                              NULL_RTX, 1, OPTAB_DIRECT);
+
+  oldval = convert_modes (DImode, mode, oldval, 1);
+  newval = emit_insxl (mode, newval, addr);
+
+  wdst = gen_reg_rtx (DImode);
+  if (mode == QImode)
+    fn5 = gen_sync_compare_and_swapqi_1;
+  else
+    fn5 = gen_sync_compare_and_swaphi_1;
+  emit_insn (fn5 (wdst, addr, oldval, newval, align));
+
+  emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_compare_and_swap_12 (enum machine_mode mode, rtx dest, rtx addr,
+                                rtx oldval, rtx newval, rtx align,
+                                rtx scratch, rtx cond)
+{
+  rtx label1, label2, mem, width, mask, x;
+
+  mem = gen_rtx_MEM (DImode, align);
+  MEM_VOLATILE_P (mem) = 1;
+
+  emit_insn (gen_memory_barrier ());
+  label1 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  label2 = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label1, 0));
+
+  emit_load_locked (DImode, scratch, mem);
+  
+  width = GEN_INT (GET_MODE_BITSIZE (mode));
+  mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_extxl_be (dest, scratch, width, addr));
+  else
+    emit_insn (gen_extxl_le (dest, scratch, width, addr));
+
+  if (oldval == const0_rtx)
+    x = gen_rtx_NE (DImode, dest, const0_rtx);
+  else
+    {
+      x = gen_rtx_EQ (DImode, dest, oldval);
+      emit_insn (gen_rtx_SET (VOIDmode, cond, x));
+      x = gen_rtx_EQ (DImode, cond, const0_rtx);
+    }
+  emit_unlikely_jump (x, label2);
+
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+  else
+    emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+  emit_insn (gen_iordi3 (scratch, scratch, newval));
+
+  emit_store_conditional (DImode, scratch, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+  emit_unlikely_jump (x, label1);
+
+  emit_insn (gen_memory_barrier ());
+  emit_label (XEXP (label2, 0));
+}
+
+/* Expand an atomic exchange operation.  */
+
+void
+alpha_split_lock_test_and_set (rtx retval, rtx mem, rtx val, rtx scratch)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx label, x, cond = gen_lowpart (DImode, scratch);
+
+  emit_insn (gen_memory_barrier ());
+
+  label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label, 0));
+
+  emit_load_locked (mode, retval, mem);
+  emit_move_insn (scratch, val);
+  emit_store_conditional (mode, cond, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, cond, const0_rtx);
+  emit_unlikely_jump (x, label);
+}
+
+void
+alpha_expand_lock_test_and_set_12 (rtx dst, rtx mem, rtx val)
+{
+  enum machine_mode mode = GET_MODE (mem);
+  rtx addr, align, wdst;
+  rtx (*fn4) (rtx, rtx, rtx, rtx);
+
+  /* Force the address into a register.  */
+  addr = force_reg (DImode, XEXP (mem, 0));
+
+  /* Align it to a multiple of 8.  */
+  align = expand_simple_binop (Pmode, AND, addr, GEN_INT (-8),
+                              NULL_RTX, 1, OPTAB_DIRECT);
+
+  /* Insert val into the correct byte location within the word.  */
+  val = emit_insxl (mode, val, addr);
+
+  wdst = gen_reg_rtx (DImode);
+  if (mode == QImode)
+    fn4 = gen_sync_lock_test_and_setqi_1;
+  else
+    fn4 = gen_sync_lock_test_and_sethi_1;
+  emit_insn (fn4 (wdst, addr, val, align));
+
+  emit_move_insn (dst, gen_lowpart (mode, wdst));
+}
+
+void
+alpha_split_lock_test_and_set_12 (enum machine_mode mode, rtx dest, rtx addr,
+                                 rtx val, rtx align, rtx scratch)
+{
+  rtx label, mem, width, mask, x;
+
+  mem = gen_rtx_MEM (DImode, align);
+  MEM_VOLATILE_P (mem) = 1;
+
+  emit_insn (gen_memory_barrier ());
+  label = gen_rtx_LABEL_REF (DImode, gen_label_rtx ());
+  emit_label (XEXP (label, 0));
+
+  emit_load_locked (DImode, scratch, mem);
+  
+  width = GEN_INT (GET_MODE_BITSIZE (mode));
+  mask = GEN_INT (mode == QImode ? 0xff : 0xffff);
+  if (WORDS_BIG_ENDIAN)
+    {
+      emit_insn (gen_extxl_be (dest, scratch, width, addr));
+      emit_insn (gen_mskxl_be (scratch, scratch, mask, addr));
+    }
+  else
+    {
+      emit_insn (gen_extxl_le (dest, scratch, width, addr));
+      emit_insn (gen_mskxl_le (scratch, scratch, mask, addr));
+    }
+  emit_insn (gen_iordi3 (scratch, scratch, val));
+
+  emit_store_conditional (DImode, scratch, mem, scratch);
+
+  x = gen_rtx_EQ (DImode, scratch, const0_rtx);
+  emit_unlikely_jump (x, label);
+}
 \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.  */
@@ -4248,7 +4711,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
@@ -4262,7 +4725,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.  */
@@ -4325,7 +4788,14 @@ alpha_gp_save_rtx (void)
 
       seq = get_insns ();
       end_sequence ();
-      emit_insn_after (seq, entry_of_function ());
+
+      /* We used to simply emit the sequence after entry_of_function.
+        However this breaks the CFG if the first instruction in the
+        first block is not the NOTE_INSN_BASIC_BLOCK, for example a
+        label.  Emit the sequence properly on the edge.  We are only
+        invoked from dw2_build_landing_pads and finish_eh_generation
+        will call commit_edge_insertions thanks to a kludge.  */
+      insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR));
 
       cfun->machine->gp_save_rtx = m;
     }
@@ -4339,7 +4809,7 @@ alpha_ra_ever_killed (void)
   rtx top;
 
   if (!has_hard_reg_initial_val (Pmode, REG_RA))
-    return regs_ever_live[REG_RA];
+    return (int)df_regs_ever_live_p (REG_RA);
 
   push_topmost_sequence ();
   top = get_insns ();
@@ -4382,8 +4852,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)
@@ -4396,6 +4867,8 @@ get_trap_mode_suffix (void)
          return "sv";
        case ALPHA_FPTM_SUI:
          return "svi";
+       default:
+         gcc_unreachable ();
        }
       break;
 
@@ -4410,10 +4883,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
@@ -4439,13 +4917,18 @@ get_round_mode_suffix (void)
          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
@@ -4479,7 +4962,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.  */
@@ -4521,13 +5004,6 @@ print_operand (FILE *file, rtx x, int code)
       fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file);
       break;
 
-    case '+':
-      /* Generates a nop after a noreturn call at the very end of the
-        function.  */
-      if (next_real_insn (current_output_insn) == 0)
-       fprintf (file, "\n\tnop");
-      break;
-
     case '#':
       if (alpha_this_literal_sequence_number == 0)
        alpha_this_literal_sequence_number = alpha_next_sequence_number++;
@@ -4574,6 +5050,20 @@ print_operand (FILE *file, rtx x, int code)
       }
       break;
 
+    case 'j':
+      {
+       const char *lituse;
+
+#ifdef HAVE_AS_JSRDIRECT_RELOCS
+       lituse = "lituse_jsrdirect";
+#else
+       lituse = "lituse_jsr";
+#endif
+
+       gcc_assert (INTVAL (x) != 0);
+       fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x));
+      }
+      break;
     case 'r':
       /* If this operand is the constant zero, write it as "$31".  */
       if (GET_CODE (x) == REG)
@@ -4888,46 +5378,56 @@ print_operand_address (FILE *file, rtx addr)
        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);
 }
@@ -4964,28 +5464,6 @@ alpha_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt,
   addr = memory_address (mode, plus_constant (tramp, cxtofs));
   emit_move_insn (gen_rtx_MEM (mode, addr), cxt);
 
-  /* This has been disabled since the hint only has a 32k range, and in
-     no existing OS is the stack within 32k of the text segment.  */
-  if (0 && jmpofs >= 0)
-    {
-      /* Compute hint value.  */
-      temp = force_operand (plus_constant (tramp, jmpofs+4), NULL_RTX);
-      temp = expand_binop (DImode, sub_optab, fnaddr, temp, temp, 1,
-                          OPTAB_WIDEN);
-      temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
-                          build_int_cst (NULL_TREE, 2), NULL_RTX, 1);
-      temp = expand_and (SImode, gen_lowpart (SImode, temp),
-                        GEN_INT (0x3fff), 0);
-
-      /* Merge in the hint.  */
-      addr = memory_address (SImode, plus_constant (tramp, jmpofs));
-      temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr));
-      temp1 = expand_and (SImode, temp1, GEN_INT (0xffffc000), NULL_RTX);
-      temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
-                           OPTAB_WIDEN);
-      emit_move_insn (gen_rtx_MEM (SImode, addr), temp1);
-    }
-
 #ifdef ENABLE_EXECUTE_STACK
   emit_library_call (init_one_libfunc ("__enable_execute_stack"),
                     0, VOIDmode, 1, tramp, Pmode);
@@ -5026,8 +5504,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
@@ -5134,10 +5611,35 @@ 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
-alpha_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
+alpha_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED)
 {
   enum machine_mode mode = VOIDmode;
   int size;
@@ -5172,8 +5674,9 @@ alpha_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
 
     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.  */
+        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;
     }
 
@@ -5186,7 +5689,7 @@ alpha_return_in_memory (tree type, tree fndecl ATTRIBUTE_UNUSED)
 static bool
 alpha_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
                         enum machine_mode mode,
-                        tree type ATTRIBUTE_UNUSED,
+                        const_tree type ATTRIBUTE_UNUSED,
                         bool named ATTRIBUTE_UNUSED)
 {
   return mode == TFmode || mode == TCmode;
@@ -5201,16 +5704,13 @@ alpha_pass_by_reference (CUMULATIVE_ARGS *ca ATTRIBUTE_UNUSED,
    $f0 for floating-point functions.  */
 
 rtx
-function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
+function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED,
                enum machine_mode mode)
 {
   unsigned int regnum, dummy;
   enum mode_class class;
 
-#ifdef ENABLE_CHECKING
-  if (valtype && alpha_return_in_memory (valtype, func))
-    abort ();
-#endif
+  gcc_assert (!valtype || !alpha_return_in_memory (valtype, func));
 
   if (valtype)
     mode = TYPE_MODE (valtype);
@@ -5245,7 +5745,7 @@ function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
       }
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   return gen_rtx_REG (mode, regnum);
@@ -5255,7 +5755,7 @@ function_value (tree valtype, tree func ATTRIBUTE_UNUSED,
    should not split these values.  */
 
 static bool
-alpha_split_complex_arg (tree type)
+alpha_split_complex_arg (const_tree type)
 {
   return TYPE_MODE (type) != TCmode;
 }
@@ -5294,29 +5794,191 @@ alpha_build_builtin_va_list (void)
   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) != GIMPLE_MODIFY_STMT
+         || GIMPLE_STMT_OPERAND (stmt, 0) != lhs)
+       return lhs;
+
+      rhs = GIMPLE_STMT_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 (rhs) != POINTER_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.
+
+   Also look for LHS = (*ptr).field, where ptr is one of the forms
+   listed above.
+
+   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, const_tree lhs, const_tree rhs)
+{
+  tree base, offset, arg1, arg2;
+  int offset_arg = 1;
+
+  while (handled_component_p (rhs))
+    rhs = TREE_OPERAND (rhs, 0);
+  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) != POINTER_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, DECL_UID (base)))
+    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 ATTRIBUTE_UNUSED,
-                             tree type ATTRIBUTE_UNUSED,
-                             int *pretend_size, int no_rtl)
+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.  */
-  int num_reg_words = pcum->num_reg_words;
-  if (num_reg_words < 6)
+  if (cum.num_reg_words < 6)
     {
       if (!no_rtl)
        {
-         emit_insn (gen_umk_mismatch_args (GEN_INT (num_reg_words + 1)));
+         emit_insn (gen_umk_mismatch_args (GEN_INT (cum.num_reg_words)));
          emit_insn (gen_arg_home_umk ());
        }
       *pretend_size = 0;
@@ -5328,7 +5990,7 @@ alpha_setup_incoming_varargs (CUMULATIVE_ARGS *pcum,
      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 (cum.num_args < 6)
     {
       if (!no_rtl)
        {
@@ -5349,34 +6011,51 @@ alpha_setup_incoming_varargs (CUMULATIVE_ARGS *pcum,
      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)
     {
-      int set = get_varargs_alias_set ();
+      int count;
+      alias_set_type set = get_varargs_alias_set ();
       rtx tmp;
 
-      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);
+      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));
+         MEM_NOTRAP_P (tmp) = 1;
+         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));
+         MEM_NOTRAP_P (tmp) = 1;
+         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
+static void
 alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
 {
   HOST_WIDE_INT offset;
@@ -5400,7 +6079,7 @@ alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
      integer argument register; that futzes with pretend_args_size,
      which changes the meaning of AP.  */
 
-  if (NUM_ARGS <= 6)
+  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;
@@ -5409,8 +6088,8 @@ alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
     {
       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));
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (valist), valist,
+                 make_tree (ptr_type_node, nextarg));
       TREE_SIDE_EFFECTS (t) = 1;
 
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -5420,20 +6099,21 @@ alpha_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
       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);
+      base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field),
+                          valist, base_field, NULL_TREE);
+      offset_field = build3 (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);
+      t = build2 (POINTER_PLUS_EXPR, ptr_type_node, t,
+                 size_int (offset));
+      t = build2 (GIMPLE_MODIFY_STMT, 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);
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (offset_field),
+                 offset_field, t);
       TREE_SIDE_EFFECTS (t) = 1;
       expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
     }
@@ -5449,8 +6129,8 @@ alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
   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));
+      t = build2 (GIMPLE_MODIFY_STMT, TREE_TYPE (offset), offset,
+                 build2 (MAX_EXPR, TREE_TYPE (offset), offset, t));
       gimplify_and_add (t, pre_p);
     }
 
@@ -5471,23 +6151,23 @@ alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
       imag_part = alpha_gimplify_va_arg_1 (TREE_TYPE (type), base,
                                           offset, pre_p);
 
-      return build (COMPLEX_EXPR, type, real_temp, imag_part);
+      return build2 (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));
+      fpaddend = fold_build2 (MINUS_EXPR, TREE_TYPE (addend),
+                             addend, fourtyeight);
+      cond = fold_build2 (LT_EXPR, boolean_type_node, addend, fourtyeight);
+      addend = fold_build3 (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));
+  addr = build2 (POINTER_PLUS_EXPR, ptr_type, fold_convert (ptr_type, base),
+                fold_convert (sizetype, addend));
   internal_post = NULL;
   gimplify_expr (&addr, pre_p, &internal_post, is_gimple_val, fb_rvalue);
   append_to_statement_list (internal_post, pre_p);
@@ -5503,11 +6183,11 @@ alpha_gimplify_va_arg_1 (tree type, tree base, tree offset, tree *pre_p)
       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));
+  t = build2 (GIMPLE_MODIFY_STMT, void_type_node, offset,
+             build2 (PLUS_EXPR, TREE_TYPE (offset), offset, t));
   gimplify_and_add (t, pre_p);
 
-  return build_fold_indirect_ref (addr);
+  return build_va_arg_indirect_ref (addr);
 }
 
 static tree
@@ -5521,10 +6201,10 @@ alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *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);
+  base_field = build3 (COMPONENT_REF, TREE_TYPE (base_field),
+                      valist, base_field, NULL_TREE);
+  offset_field = build3 (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
@@ -5543,12 +6223,12 @@ alpha_gimplify_va_arg (tree valist, tree type, tree *pre_p, tree *post_p)
   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));
+  t = build2 (GIMPLE_MODIFY_STMT, 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);
+    r = build_va_arg_indirect_ref (r);
 
   return r;
 }
@@ -5659,9 +6339,9 @@ static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = {
   CODE_FOR_builtin_unpkbw,
 
   /* TARGET_CIX */
-  CODE_FOR_builtin_cttz,
-  CODE_FOR_builtin_ctlz,
-  CODE_FOR_builtin_ctpop
+  CODE_FOR_ctzdi2,
+  CODE_FOR_clzdi2,
+  CODE_FOR_popcountdi2
 };
 
 struct alpha_builtin_def
@@ -5669,104 +6349,128 @@ 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 },
-  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0 }
+  { "__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 },
-  { "__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 }
+  { "__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 },
-  { "__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 }
-};
+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 }
+};
+
+static GTY(()) tree alpha_v8qi_u;
+static GTY(()) tree alpha_v8qi_s;
+static GTY(()) tree alpha_v4hi_u;
+static GTY(()) tree alpha_v4hi_s;
+
+/* Helper function of alpha_init_builtins.  Add the COUNT built-in
+   functions pointed to by P, with function type FTYPE.  */
+
+static void
+alpha_add_builtins (const struct alpha_builtin_def *p, size_t count,
+                   tree ftype)
+{
+  tree decl;
+  size_t i;
+
+  for (i = 0; i < count; ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      {
+       decl = add_builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                                    NULL, NULL);
+       if (p->is_const)
+         TREE_READONLY (decl) = 1;
+       TREE_NOTHROW (decl) = 1;
+      }
+}
+
 
 static void
 alpha_init_builtins (void)
 {
-  const struct alpha_builtin_def *p;
-  tree ftype;
-  size_t i;
-
-  ftype = build_function_type (long_integer_type_node, void_list_node);
+  tree dimode_integer_type_node;
+  tree ftype, decl;
 
-  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);
-
-  ftype = build_function_type_list (long_integer_type_node,
-                                   long_integer_type_node, NULL_TREE);
+  dimode_integer_type_node = lang_hooks.types.type_for_mode (DImode, 0);
 
-  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);
+  ftype = build_function_type (dimode_integer_type_node, void_list_node);
+  alpha_add_builtins (zero_arg_builtins, ARRAY_SIZE (zero_arg_builtins),
+                     ftype);
 
-  ftype = build_function_type_list (long_integer_type_node,
-                                   long_integer_type_node,
-                                   long_integer_type_node, NULL_TREE);
+  ftype = build_function_type_list (dimode_integer_type_node,
+                                   dimode_integer_type_node, NULL_TREE);
+  alpha_add_builtins (one_arg_builtins, ARRAY_SIZE (one_arg_builtins),
+                     ftype);
 
-  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);
+  ftype = build_function_type_list (dimode_integer_type_node,
+                                   dimode_integer_type_node,
+                                   dimode_integer_type_node, NULL_TREE);
+  alpha_add_builtins (two_arg_builtins, ARRAY_SIZE (two_arg_builtins),
+                     ftype);
 
   ftype = build_function_type (ptr_type_node, void_list_node);
-  lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
+  decl = add_builtin_function ("__builtin_thread_pointer", ftype,
                               ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+                              NULL, NULL);
+  TREE_NOTHROW (decl) = 1;
 
   ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
-  lang_hooks.builtin_function ("__builtin_set_thread_pointer", ftype,
+  decl = add_builtin_function ("__builtin_set_thread_pointer", ftype,
                               ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
-                              NULL, NULL_TREE);
+                              NULL, NULL);
+  TREE_NOTHROW (decl) = 1;
+
+  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);
 }
 
 /* Expand an expression EXP that calls a built-in function,
@@ -5783,9 +6487,10 @@ alpha_expand_builtin (tree exp, rtx target,
 {
 #define MAX_ARGS 2
 
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
-  tree arglist = TREE_OPERAND (exp, 1);
+  tree arg;
+  call_expr_arg_iterator iter;
   enum insn_code icode;
   rtx op[MAX_ARGS], pat;
   int arity;
@@ -5799,13 +6504,11 @@ alpha_expand_builtin (tree exp, rtx target,
 
   nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
 
-  for (arglist = TREE_OPERAND (exp, 1), arity = 0;
-       arglist;
-       arglist = TREE_CHAIN (arglist), arity++)
+  arity = 0;
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
     {
       const struct insn_operand_data *insn_op;
 
-      tree arg = TREE_VALUE (arglist);
       if (arg == error_mark_node)
        return NULL_RTX;
       if (arity > MAX_ARGS)
@@ -5817,6 +6520,7 @@ alpha_expand_builtin (tree exp, rtx target,
 
       if (!(*insn_op->predicate) (op[arity], insn_op->mode))
        op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
+      arity++;
     }
 
   if (nonvoid)
@@ -5843,7 +6547,7 @@ alpha_expand_builtin (tree exp, rtx target,
       pat = GEN_FCN (icode) (target, op[0], op[1]);
       break;
     default:
-      abort ();
+      gcc_unreachable ();
     }
   if (!pat)
     return NULL_RTX;
@@ -5854,6 +6558,482 @@ alpha_expand_builtin (tree exp, rtx target,
   else
     return const0_rtx;
 }
+
+
+/* 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
+
+/* 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.  */
+
+static tree
+alpha_fold_builtin_cmpbge (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  if (op_const == 3)
+    {
+      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 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)
+    {
+      unsigned HOST_WIDE_INT mask = 0;
+      int i;
+
+      for (i = 0; i < 8; ++i)
+       if ((opint[1] >> i) & 1)
+         mask |= (unsigned HOST_WIDE_INT)0xff << (i * 8);
+
+      if (op_const & 1)
+       return build_int_cst (long_integer_type_node, opint[0] & mask);
+
+      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_fold_builtin_extxx (tree op[], unsigned HOST_WIDE_INT opint[],
+                         long op_const, unsigned HOST_WIDE_INT bytemask,
+                         bool is_high)
+{
+  long zap_const = 2;
+  tree *zap_op = NULL;
+
+  if (op_const & 2)
+    {
+      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);
+}
+
+/* Fold the builtins for the INS family of instructions.  */
+
+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);
+
+  if (op_const & 2)
+    {
+      unsigned HOST_WIDE_INT temp, loc, byteloc;
+      tree *zap_op = NULL;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
+
+      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;
+       }
+
+      opint[0] = temp;
+      opint[1] = bytemask;
+      return alpha_fold_builtin_zapnot (zap_op, opint, op_const);
+    }
+
+  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)
+    {
+      unsigned HOST_WIDE_INT loc;
+
+      loc = opint[1] & 7;
+      if (BYTES_BIG_ENDIAN)
+        loc ^= 7;
+      bytemask <<= loc;
+
+      if (is_high)
+       bytemask >>= 8;
+
+      opint[1] = bytemask ^ 0xff;
+    }
+
+  return alpha_fold_builtin_zapnot (op, opint, op_const);
+}
+
+static tree
+alpha_fold_builtin_umulh (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  switch (op_const)
+    {
+    case 3:
+      {
+       unsigned HOST_WIDE_INT l;
+       HOST_WIDE_INT h;
+
+       mul_double (opint[0], 0, opint[1], 0, &l, &h);
+
+#if HOST_BITS_PER_WIDE_INT > 64
+# error fixme
+#endif
+
+       return build_int_cst (long_integer_type_node, h);
+      }
+
+    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;
+}
+
+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);
+}
+
+static tree
+alpha_fold_builtin_perr (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp = 0;
+  int i;
+
+  if (op_const != 3)
+    return NULL;
+
+  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 build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_pklb (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >> 24) & 0xff00;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_pkwb (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] >>  8) & 0xff00;
+  temp |= (opint[0] >> 16) & 0xff0000;
+  temp |= (opint[0] >> 24) & 0xff000000;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_unpkbl (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0xff00) << 24;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_unpkbw (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  temp = opint[0] & 0xff;
+  temp |= (opint[0] & 0x0000ff00) << 8;
+  temp |= (opint[0] & 0x00ff0000) << 16;
+  temp |= (opint[0] & 0xff000000) << 24;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_cttz (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = exact_log2 (opint[0] & -opint[0]);
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_ctlz (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp;
+
+  if (op_const == 0)
+    return NULL;
+
+  if (opint[0] == 0)
+    temp = 64;
+  else
+    temp = 64 - floor_log2 (opint[0]) - 1;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+static tree
+alpha_fold_builtin_ctpop (unsigned HOST_WIDE_INT opint[], long op_const)
+{
+  unsigned HOST_WIDE_INT temp, op;
+
+  if (op_const == 0)
+    return NULL;
+
+  op = opint[0];
+  temp = 0;
+  while (op)
+    temp++, op &= op - 1;
+
+  return build_int_cst (long_integer_type_node, temp);
+}
+
+/* Fold one of our builtin functions.  */
+
+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;
+
+  for (t = arglist; t ; t = TREE_CHAIN (t), ++arity)
+    {
+      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:
+      return NULL;
+    }
+}
 \f
 /* This page contains routines that are used to determine what the function
    prologue and epilogue code will do and write them out.  */
@@ -5905,7 +7085,7 @@ alpha_sa_mask (unsigned long *imaskP, unsigned long *fmaskP)
   /* One for every register we have to save.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     if (! fixed_regs[i] && ! call_used_regs[i]
-       && regs_ever_live[i] && i != REG_RA
+       && df_regs_ever_live_p (i) && i != REG_RA
        && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
       {
        if (i < 32)
@@ -6013,7 +7193,7 @@ alpha_sa_size (void)
       vms_save_fp_regno = -1;
       if (vms_base_regno == HARD_FRAME_POINTER_REGNUM)
        for (i = 0; i < 32; i++)
-         if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
+         if (! fixed_regs[i] && call_used_regs[i] && ! df_regs_ever_live_p (i))
            vms_save_fp_regno = i;
 
       if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
@@ -6051,14 +7231,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;
 }
@@ -6136,6 +7322,7 @@ alpha_does_function_need_gp (void)
 
   for (; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn)
+       && ! JUMP_TABLE_DATA_P (insn)
        && GET_CODE (PATTERN (insn)) != USE
        && GET_CODE (PATTERN (insn)) != CLOBBER
        && get_attr_usegp (insn))
@@ -6311,16 +7498,15 @@ alpha_expand_prologue (void)
     {
       if (frame_size > 4096)
        {
-         int probed = 4096;
+         int probed;
 
-         do
+         for (probed = 4096; probed < frame_size; probed += 8192)
            emit_insn (gen_probe_stack (GEN_INT (TARGET_ABI_UNICOSMK
                                                 ? -probed + 64
                                                 : -probed)));
-         while ((probed += 8192) < frame_size);
 
          /* We only have to do this probe if we aren't saving registers.  */
-         if (sa_size == 0 && probed + 4096 < frame_size)
+         if (sa_size == 0 && frame_size > probed - 4096)
            emit_insn (gen_probe_stack (GEN_INT (-frame_size)));
        }
 
@@ -6548,7 +7734,7 @@ alpha_expand_prologue (void)
 }
 
 /* Count the number of .file directives, so that .loc is up to date.  */
-static int num_source_filenames = 0;
+int num_source_filenames = 0;
 
 /* Output the textual info surrounding the prologue.  */
 
@@ -6562,6 +7748,10 @@ alpha_start_function (FILE *file, const char *fnname,
   HOST_WIDE_INT sa_size;
   /* Complete stack size needed.  */
   unsigned HOST_WIDE_INT frame_size;
+  /* The maximum debuggable frame size (512 Kbytes using Tru64 as).  */
+  unsigned HOST_WIDE_INT max_frame_size = TARGET_ABI_OSF && !TARGET_GAS
+                                         ? 524288
+                                         : 1UL << 31;
   /* Offset from base reg to register save area.  */
   HOST_WIDE_INT reg_offset;
   char *entry_label = (char *) alloca (strlen (fnname) + 6);
@@ -6686,7 +7876,7 @@ alpha_start_function (FILE *file, const char *fnname,
     fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,%d\n",
             (frame_pointer_needed
              ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM),
-            frame_size >= (1UL << 31) ? 0 : frame_size,
+            frame_size >= max_frame_size ? 0 : frame_size,
             current_function_pretend_args_size);
 
   /* Describe which registers were spilled.  */
@@ -6708,7 +7898,7 @@ alpha_start_function (FILE *file, const char *fnname,
       if (imask)
        {
          fprintf (file, "\t.mask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", imask,
-                  frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size);
+                  frame_size >= max_frame_size ? 0 : reg_offset - frame_size);
 
          for (i = 0; i < 32; ++i)
            if (imask & (1UL << i))
@@ -6717,19 +7907,19 @@ alpha_start_function (FILE *file, const char *fnname,
 
       if (fmask)
        fprintf (file, "\t.fmask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", fmask,
-                frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size);
+                frame_size >= max_frame_size ? 0 : reg_offset - frame_size);
     }
 
 #if TARGET_ABI_OPEN_VMS
   /* Ifdef'ed cause link_section are only available then.  */
-  readonly_data_section ();
+  switch_to_section (readonly_data_section);
   fprintf (file, "\t.align 3\n");
   assemble_name (file, fnname); fputs ("..na:\n", file);
   fputs ("\t.ascii \"", file);
   assemble_name (file, fnname);
   fputs ("\\0\"\n", file);
   alpha_need_linkage (fnname, 1);
-  text_section ();
+  switch_to_section (text_section);
 #endif
 }
 
@@ -6948,15 +8138,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);
            }
        }
 
@@ -7018,6 +8208,17 @@ alpha_expand_epilogue (void)
 void
 alpha_end_function (FILE *file, const char *fnname, tree decl ATTRIBUTE_UNUSED)
 {
+  rtx insn;
+
+  /* We output a nop after noreturn calls at the very end of the function to
+     ensure that the return address always remains in the caller's code range,
+     as not doing so might confuse unwinding engines.  */
+  insn = get_last_insn ();
+  if (!INSN_P (insn))
+    insn = prev_active_insn (insn);
+  if (GET_CODE (insn) == CALL_INSN)
+    output_asm_insn (get_insn_template (CODE_FOR_nop, NULL), NULL);
+
 #if TARGET_ABI_OPEN_VMS
   alpha_write_linkage (file, fnname, decl);
 #endif
@@ -7057,8 +8258,6 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   HOST_WIDE_INT hi, lo;
   rtx this, insn, funexp;
 
-  reset_block_changes ();
-
   /* We always require a valid GP.  */
   emit_insn (gen_prologue_ldgp ());
   emit_note (NOTE_INSN_PROLOGUE_END);
@@ -7135,11 +8334,12 @@ alpha_output_mi_thunk_osf (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
      instruction scheduling worth while.  Note that use_thunk calls
      assemble_start_function and assemble_end_function.  */
   insn = get_insns ();
-  insn_locators_initialize ();
+  insn_locators_alloc ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
-  final (insn, file, 1, 0);
+  final (insn, file, 1);
   final_end_function ();
+  free_after_compilation (cfun);
 }
 #endif /* TARGET_ABI_OSF */
 \f
@@ -7332,7 +8532,7 @@ summarize_insn (rtx x, struct shadow_summary *sum, int set)
            break;
 
          default:
-           abort ();
+           gcc_unreachable ();
          }
     }
 }
@@ -7388,7 +8588,7 @@ alpha_handle_trap_shadows (void)
     {
       if (GET_CODE (i) == NOTE)
        {
-         switch (NOTE_LINE_NUMBER (i))
+         switch (NOTE_KIND (i))
            {
            case NOTE_INSN_EH_REGION_BEG:
              exception_nesting++;
@@ -7430,7 +8630,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;
@@ -7457,10 +8657,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;
                        }
@@ -7472,7 +8671,7 @@ alpha_handle_trap_shadows (void)
                      goto close_shadow;
 
                    default:
-                     abort ();
+                     gcc_unreachable ();
                    }
                }
              else
@@ -7505,6 +8704,11 @@ alpha_handle_trap_shadows (void)
 \f
 /* Alpha can only issue instruction groups simultaneously if they are
    suitably aligned.  This is very processor-specific.  */
+/* There are a number of entries in alphaev4_insn_pipe and alphaev5_insn_pipe
+   that are marked "fake".  These instructions do not exist on that target,
+   but it is possible to see these insns with deranged combinations of 
+   command-line options, such as "-mtune=ev4 -mmax".  Instead of aborting,
+   choose a result at random.  */
 
 enum alphaev4_pipe {
   EV4_STOP = 0,
@@ -7535,21 +8739,23 @@ 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:
+    case TYPE_MVI:             /* fake */
       return EV4_IB0;
 
+    case TYPE_IST:
     case TYPE_MISC:
     case TYPE_IBR:
     case TYPE_JSR:
@@ -7559,10 +8765,15 @@ alphaev4_insn_pipe (rtx insn)
     case TYPE_FADD:
     case TYPE_FDIV:
     case TYPE_FMUL:
+    case TYPE_ST_C:
+    case TYPE_MB:
+    case TYPE_FSQRT:           /* fake */
+    case TYPE_FTOI:            /* fake */
+    case TYPE_ITOF:            /* fake */
       return EV4_IB1;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }
 
@@ -7591,6 +8802,11 @@ 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:
+    case TYPE_FTOI:            /* fake */
+    case TYPE_ITOF:            /* fake */
       return EV5_E0;
 
     case TYPE_IBR:
@@ -7605,13 +8821,14 @@ alphaev5_insn_pipe (rtx insn)
     case TYPE_FCMOV:
     case TYPE_FADD:
     case TYPE_FDIV:
+    case TYPE_FSQRT:           /* fake */
       return EV5_FA;
 
     case TYPE_FMUL:
       return EV5_FM;
 
     default:
-      abort();
+      gcc_unreachable ();
     }
 }
 
@@ -7645,7 +8862,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)
@@ -7682,7 +8899,7 @@ alphaev4_next_group (rtx insn, int *pin_use, int *plen)
          break;
 
        default:
-         abort();
+         gcc_unreachable ();
        }
       len += 4;
 
@@ -7743,7 +8960,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)
@@ -7752,11 +8969,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)
            {
@@ -7811,7 +9028,7 @@ alphaev5_next_group (rtx insn, int *pin_use, int *plen)
          break;
 
        default:
-         abort();
+         gcc_unreachable ();
        }
       len += 4;
 
@@ -7911,7 +9128,7 @@ alpha_align_insns (unsigned int max_align,
   unsigned int align;
   /* OFS is the offset of the current insn in the insn group.  */
   int ofs;
-  int prev_in_use, in_use, len;
+  int prev_in_use, in_use, len, ldgp;
   rtx i, next;
 
   /* Let shorten branches care for assigning alignments to code labels.  */
@@ -7929,6 +9146,8 @@ alpha_align_insns (unsigned int max_align,
   if (GET_CODE (i) == NOTE)
     i = next_nonnote_insn (i);
 
+  ldgp = alpha_function_needs_gp ? 8 : 0;
+
   while (i)
     {
       next = (*next_group) (i, &in_use, &len);
@@ -7946,8 +9165,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.  */
@@ -7985,6 +9203,10 @@ alpha_align_insns (unsigned int max_align,
            }
        }
 
+      /* We may not insert padding inside the initial ldgp sequence.  */
+      else if (ldgp > 0)
+       ldgp -= len;
+
       /* If the group won't fit in the same INT16 as the previous,
         we need to add padding to keep the group together.  Rather
         than simply leaving the insn filling to the assembler, we
@@ -8040,9 +9262,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);
     }
 }
@@ -8075,31 +9297,65 @@ 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
 
 #ifdef OBJECT_FORMAT_ELF
+/* Since we don't have a .dynbss section, we should not allow global
+   relocations in the .rodata section.  */
+
+static int
+alpha_elf_reloc_rw_mask (void)
+{
+  return flag_pic ? 3 : 2;
+}
 
-/* Switch to the section to which we should output X.  The only thing
-   special we do here is to honor small data.  */
+/* Return a section for X.  The only special thing we do here is to
+   honor small data.  */
 
-static void
+static section *
 alpha_elf_select_rtx_section (enum machine_mode mode, rtx x,
                              unsigned HOST_WIDE_INT align)
 {
   if (TARGET_SMALL_DATA && GET_MODE_SIZE (mode) <= g_switch_value)
     /* ??? Consider using mergeable sdata sections.  */
-    sdata_section ();
+    return sdata_section;
   else
-    default_elf_select_rtx_section (mode, x, align);
+    return default_elf_select_rtx_section (mode, x, align);
 }
 
+static unsigned int
+alpha_elf_section_type_flags (tree decl, const char *name, int reloc)
+{
+  unsigned int flags = 0;
+
+  if (strcmp (name, ".sdata") == 0
+      || strncmp (name, ".sdata.", 7) == 0
+      || strncmp (name, ".gnu.linkonce.s.", 16) == 0
+      || strcmp (name, ".sbss") == 0
+      || strncmp (name, ".sbss.", 6) == 0
+      || strncmp (name, ".gnu.linkonce.sb.", 17) == 0)
+    flags = SECTION_SMALL;
+
+  flags |= default_section_type_flags (decl, name, reloc);
+  return flags;
+}
 #endif /* OBJECT_FORMAT_ELF */
 \f
 /* Structure to collect function names for final output in link section.  */
@@ -8367,8 +9623,10 @@ alpha_write_linkage (FILE *stream, const char *funname, tree fundecl)
   splay_tree_node node;
   struct alpha_funcs *func;
 
-  link_section ();
+  fprintf (stream, "\t.link\n");
   fprintf (stream, "\t.align 3\n");
+  in_section = NULL;
+
   node = splay_tree_lookup (alpha_funcs_tree, (splay_tree_key) fundecl);
   func = (struct alpha_funcs *) node->value;
 
@@ -8448,7 +9706,7 @@ vms_asm_named_section (const char *name, unsigned int flags,
 static void
 vms_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 {
-  ctors_section ();
+  switch_to_section (ctors_section);
   assemble_align (BITS_PER_WORD);
   assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
 }
@@ -8456,7 +9714,7 @@ vms_asm_out_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 static void
 vms_asm_out_destructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
 {
-  dtors_section ();
+  switch_to_section (dtors_section);
   assemble_align (BITS_PER_WORD);
   assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
 }
@@ -8487,7 +9745,7 @@ alpha_use_linkage (rtx linkage ATTRIBUTE_UNUSED,
    registers.  */
 
 static bool
-unicosmk_must_pass_in_stack (enum machine_mode mode, tree type)
+unicosmk_must_pass_in_stack (enum machine_mode mode, const_tree type)
 {
   if (type == NULL)
     return false;
@@ -8524,7 +9782,7 @@ unicosmk_initial_elimination_offset (int from, int to)
            + 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
@@ -8557,7 +9815,7 @@ unicosmk_output_common (FILE *file, const char *name, int size, int align)
   tree name_tree;
   printf ("T3E__: common %s\n", name);
 
-  common_section ();
+  in_section = NULL;
   fputs("\t.endp\n\n\t.psect ", file);
   assemble_name(file, name);
   fprintf(file, ",%d,common\n", floor_log2 (align / BITS_PER_UNIT));
@@ -8572,6 +9830,43 @@ unicosmk_output_common (FILE *file, const char *name, int size, int align)
 #define SECTION_MAIN (SECTION_PUBLIC << 1)
 static int current_section_align;
 
+/* A get_unnamed_section callback for switching to the text section.  */
+
+static void
+unicosmk_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+{
+  static int count = 0;
+  fprintf (asm_out_file, "\t.endp\n\n\t.psect\tgcc@text___%d,code\n", count++);
+}
+
+/* A get_unnamed_section callback for switching to the data section.  */
+
+static void
+unicosmk_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
+{
+  static int count = 1;
+  fprintf (asm_out_file, "\t.endp\n\n\t.psect\tgcc@data___%d,data\n", count++);
+}
+
+/* Implement TARGET_ASM_INIT_SECTIONS.
+
+   The Cray assembler is really weird with respect to sections. It has only
+   named sections and you can't reopen a section once it has been closed.
+   This means that we have to generate unique names whenever we want to
+   reenter the text or the data section.  */
+
+static void
+unicosmk_init_sections (void)
+{
+  text_section = get_unnamed_section (SECTION_CODE,
+                                     unicosmk_output_text_section_asm_op,
+                                     NULL);
+  data_section = get_unnamed_section (SECTION_WRITE,
+                                     unicosmk_output_data_section_asm_op,
+                                     NULL);
+  readonly_data_section = data_section;
+}
+
 static unsigned int
 unicosmk_section_type_flags (tree decl, const char *name,
                             int reloc ATTRIBUTE_UNUSED)
@@ -8608,8 +9903,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);
@@ -8736,7 +10030,7 @@ unicosmk_output_deferred_case_vectors (FILE *file)
   if (machine->addr_list == NULL_RTX)
     return;
 
-  data_section ();
+  switch_to_section (data_section);
   for (t = machine->addr_list; t; t = XEXP (t, 1))
     unicosmk_output_addr_vec (file, XEXP (t, 0));
 }
@@ -8759,11 +10053,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);
@@ -8857,7 +10149,7 @@ unicosmk_output_ssib (FILE *file, const char *fnname)
   rtx ciw;
   struct machine_function *machine = cfun->machine;
 
-  ssib_section ();
+  in_section = NULL;
   fprintf (file, "\t.endp\n\n\t.psect\t%s%s,data\n", user_label_prefix,
           unicosmk_ssib_name ());
 
@@ -8929,26 +10221,6 @@ unicosmk_add_call_info_word (rtx x)
                  + strlen (current_function_name ())/8 + 5);
 }
 
-static char unicosmk_section_buf[100];
-
-char *
-unicosmk_text_section (void)
-{
-  static int count = 0;
-  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@text___%d,code",
-                                count++);
-  return unicosmk_section_buf;
-}
-
-char *
-unicosmk_data_section (void)
-{
-  static int count = 1;
-  sprintf (unicosmk_section_buf, "\t.endp\n\n\t.psect\tgcc@data___%d,data",
-                                count++);
-  return unicosmk_section_buf;
-}
-
 /* The Cray assembler doesn't accept extern declarations for symbols which
    are defined in the same file. We have to keep track of all global
    symbols which are referenced and/or defined in a source file and output
@@ -9317,8 +10589,12 @@ alpha_init_libfuncs (void)
 #endif
 
 #ifdef OBJECT_FORMAT_ELF
+#undef  TARGET_ASM_RELOC_RW_MASK
+#define TARGET_ASM_RELOC_RW_MASK  alpha_elf_reloc_rw_mask
 #undef TARGET_ASM_SELECT_RTX_SECTION
 #define        TARGET_ASM_SELECT_RTX_SECTION  alpha_elf_select_rtx_section
+#undef  TARGET_SECTION_TYPE_FLAGS
+#define TARGET_SECTION_TYPE_FLAGS  alpha_elf_section_type_flags
 #endif
 
 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
@@ -9354,6 +10630,8 @@ 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
@@ -9366,7 +10644,9 @@ alpha_init_libfuncs (void)
 #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
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_const_tree_hwi_hwi_const_tree_true
+#undef TARGET_STDARG_OPTIMIZE_HOOK
+#define TARGET_STDARG_OPTIMIZE_HOOK alpha_stdarg_optimize_hook
 #endif
 
 #undef TARGET_RTX_COSTS
@@ -9378,11 +10658,11 @@ alpha_init_libfuncs (void)
 #define TARGET_MACHINE_DEPENDENT_REORG alpha_reorg
 
 #undef TARGET_PROMOTE_FUNCTION_ARGS
-#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_const_tree_true
 #undef TARGET_PROMOTE_FUNCTION_RETURN
-#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
+#define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_const_tree_true
 #undef TARGET_PROMOTE_PROTOTYPES
-#define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_false
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_false
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY alpha_return_in_memory
 #undef TARGET_PASS_BY_REFERENCE
@@ -9397,6 +10677,11 @@ 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_SECONDARY_RELOAD
+#define TARGET_SECONDARY_RELOAD alpha_secondary_reload
 
 #undef TARGET_SCALAR_MODE_SUPPORTED_P
 #define TARGET_SCALAR_MODE_SUPPORTED_P alpha_scalar_mode_supported_p
@@ -9406,8 +10691,25 @@ alpha_init_libfuncs (void)
 #undef TARGET_BUILD_BUILTIN_VA_LIST
 #define TARGET_BUILD_BUILTIN_VA_LIST alpha_build_builtin_va_list
 
-#undef TARGET_VECTORIZE_MISALIGNED_MEM_OK
-#define TARGET_VECTORIZE_MISALIGNED_MEM_OK alpha_vector_mode_supported_p
+#undef TARGET_EXPAND_BUILTIN_VA_START
+#define TARGET_EXPAND_BUILTIN_VA_START alpha_va_start
+
+/* 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
+
+#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
+#undef TARGET_MANGLE_TYPE
+#define TARGET_MANGLE_TYPE alpha_mangle_type
+#endif
 
 struct gcc_target targetm = TARGET_INITIALIZER;