OSDN Git Service

* varasm.c (make_decl_rtl): Remove call to REDO_SECTION_INFO_P;
[pf3gnuchains/gcc-fork.git] / gcc / config / alpha / alpha.c
index 37a8313..5875346 100644 (file)
@@ -24,6 +24,7 @@ Boston, MA 02111-1307, USA.  */
 #include "config.h"
 #include "system.h"
 #include "rtl.h"
+#include "tree.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "real.h"
@@ -33,23 +34,21 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-attr.h"
 #include "flags.h"
 #include "recog.h"
-#include "reload.h"
-#include "tree.h"
 #include "expr.h"
+#include "optabs.h"
+#include "reload.h"
 #include "obstack.h"
 #include "except.h"
 #include "function.h"
 #include "toplev.h"
 #include "ggc.h"
-#include "tm_p.h"
 #include "integrate.h"
+#include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
+#include "debug.h"
 
-/* External data.  */
-extern int rtx_equal_function_value_matters;
-
-/* Specify which cpu to schedule for. */
+/* Specify which cpu to schedule for.  */
 
 enum processor_type alpha_cpu;
 static const char * const alpha_cpu_name[] = 
@@ -104,7 +103,23 @@ static int alpha_sr_alias_set;
 
 static const char *alpha_fnname;
 
+/* The next explicit relocation sequence number.  */
+int alpha_next_sequence_number = 1;
+
+/* The literal and gpdisp sequence numbers for this insn, as printed
+   by %# and %* respectively.  */
+int alpha_this_literal_sequence_number;
+int alpha_this_gpdisp_sequence_number;
+
 /* Declarations of static functions.  */
+static bool decl_in_text_section
+  PARAMS ((tree));
+static int some_small_symbolic_operand_1
+  PARAMS ((rtx *, void *));
+static int split_small_symbolic_operand_1
+  PARAMS ((rtx *, void *));
+static bool local_symbol_p
+  PARAMS ((rtx));
 static void alpha_set_memflags_1
   PARAMS ((rtx, int, int, int));
 static rtx alpha_emit_set_const_1
@@ -115,16 +130,16 @@ static void alpha_expand_unaligned_store_words
   PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
 static void alpha_sa_mask
   PARAMS ((unsigned long *imaskP, unsigned long *fmaskP));
+static int find_lo_sum
+  PARAMS ((rtx *, void *));
 static int alpha_does_function_need_gp
   PARAMS ((void));
-static void alpha_init_machine_status
-  PARAMS ((struct function *p));
-static void alpha_mark_machine_status
-  PARAMS ((struct function *p));
-static void alpha_free_machine_status
-  PARAMS ((struct function *p));
 static int alpha_ra_ever_killed
   PARAMS ((void));
+static const char *get_trap_mode_suffix
+  PARAMS ((void));
+static const char *get_round_mode_suffix
+  PARAMS ((void));
 static rtx set_frame_related_p
   PARAMS ((void));
 static const char *alpha_lookup_xfloating_lib_func
@@ -135,9 +150,31 @@ static void alpha_emit_xfloating_libcall
   PARAMS ((const char *, rtx, rtx[], int, rtx));
 static rtx alpha_emit_xfloating_compare
   PARAMS ((enum rtx_code, rtx, rtx));
+static void alpha_output_function_end_prologue
+  PARAMS ((FILE *));
+static int alpha_adjust_cost
+  PARAMS ((rtx, rtx, rtx, int));
+static int alpha_issue_rate
+  PARAMS ((void));
+static int alpha_variable_issue
+  PARAMS ((FILE *, int, rtx, int));
+
+#if TARGET_ABI_UNICOSMK
+static void alpha_init_machine_status
+  PARAMS ((struct function *p));
+static void alpha_mark_machine_status
+  PARAMS ((struct function *p));
+static void alpha_free_machine_status
+  PARAMS ((struct function *p));
+#endif
+
+static void unicosmk_output_deferred_case_vectors PARAMS ((FILE *));
+static void unicosmk_gen_dsib PARAMS ((unsigned long *imaskP));
+static void unicosmk_output_ssib PARAMS ((FILE *, const char *));
+static int unicosmk_need_dex PARAMS ((rtx));
 
 /* Get the number of args of a function in one of two ways.  */
-#ifdef OPEN_VMS
+#if TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK
 #define NUM_ARGS current_function_args_info.num_args
 #else
 #define NUM_ARGS current_function_args_info
@@ -147,19 +184,67 @@ static rtx alpha_emit_xfloating_compare
 #define REG_RA 26
 \f
 /* Initialize the GCC target structure.  */
+#if TARGET_ABI_OPEN_VMS
+const struct attribute_spec vms_attribute_table[];
+static unsigned int vms_section_type_flags PARAMS ((tree, const char *, int));
+static void vms_asm_named_section PARAMS ((const char *, unsigned int));
+static void vms_asm_out_constructor PARAMS ((rtx, int));
+static void vms_asm_out_destructor PARAMS ((rtx, int));
+# undef TARGET_ATTRIBUTE_TABLE
+# define TARGET_ATTRIBUTE_TABLE vms_attribute_table
+# undef TARGET_SECTION_TYPE_FLAGS
+# define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
+#endif
+
+#if TARGET_ABI_UNICOSMK
+static void unicosmk_asm_named_section PARAMS ((const char *, unsigned int));
+static void unicosmk_insert_attributes PARAMS ((tree, tree *));
+static unsigned int unicosmk_section_type_flags PARAMS ((tree, const char *, 
+                                                        int));
+# undef TARGET_INSERT_ATTRIBUTES
+# define TARGET_INSERT_ATTRIBUTES unicosmk_insert_attributes
+# undef TARGET_SECTION_TYPE_FLAGS
+# define TARGET_SECTION_TYPE_FLAGS unicosmk_section_type_flags
+#endif
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* Default unaligned ops are provided for ELF systems.  To get unaligned
+   data for non-ELF systems, we have to turn off auto alignment.  */
+#ifndef OBJECT_FORMAT_ELF
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t"
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t"
+#endif
 
-struct gcc_target target = TARGET_INITIALIZER;
+#undef TARGET_ASM_FUNCTION_END_PROLOGUE
+#define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue
+
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST alpha_adjust_cost
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE alpha_issue_rate
+#undef TARGET_SCHED_VARIABLE_ISSUE
+#define TARGET_SCHED_VARIABLE_ISSUE alpha_variable_issue
+
+struct gcc_target targetm = TARGET_INITIALIZER;
 \f
-/* Parse target option strings. */
+/* Parse target option strings.  */
 
 void
 override_options ()
 {
   int i;
-  static struct cpu_table {
-    const char *name;
-    enum processor_type processor;
-    int flags;
+  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)
@@ -180,20 +265,50 @@ override_options ()
     { 0, 0, 0 }
   };
                   
+  /* Unicos/Mk doesn't have shared libraries.  */
+  if (TARGET_ABI_UNICOSMK && flag_pic)
+    {
+      warning ("-f%s ignored for Unicos/Mk (not supported)",
+              (flag_pic > 1) ? "PIC" : "pic");
+      flag_pic = 0;
+    }
+
+  /* On Unicos/Mk, the native compiler consistenly generates /d suffices for 
+     floating-point instructions.  Make that the default for this target.  */
+  if (TARGET_ABI_UNICOSMK)
+    alpha_fprm = ALPHA_FPRM_DYN;
+  else
+    alpha_fprm = ALPHA_FPRM_NORM;
+
   alpha_tp = ALPHA_TP_PROG;
-  alpha_fprm = ALPHA_FPRM_NORM;
   alpha_fptm = ALPHA_FPTM_N;
 
+  /* We cannot use su and sui qualifiers for conversion instructions on 
+     Unicos/Mk.  I'm not sure if this is due to assembler or hardware
+     limitations.  Right now, we issue a warning if -mieee is specified
+     and then ignore it; eventually, we should either get it right or
+     disable the option altogether.  */
+
   if (TARGET_IEEE)
     {
-      alpha_tp = ALPHA_TP_INSN;
-      alpha_fptm = ALPHA_FPTM_SU;
+      if (TARGET_ABI_UNICOSMK)
+       warning ("-mieee not supported on Unicos/Mk");
+      else
+       {
+         alpha_tp = ALPHA_TP_INSN;
+         alpha_fptm = ALPHA_FPTM_SU;
+       }
     }
 
   if (TARGET_IEEE_WITH_INEXACT)
     {
-      alpha_tp = ALPHA_TP_INSN;
-      alpha_fptm = ALPHA_FPTM_SUI;
+      if (TARGET_ABI_UNICOSMK)
+       warning ("-mieee-with-inexact not supported on Unicos/Mk");
+      else
+       {
+         alpha_tp = ALPHA_TP_INSN;
+         alpha_fptm = ALPHA_FPTM_SUI;
+       }
     }
 
   if (alpha_tp_string)
@@ -268,7 +383,13 @@ override_options ()
        error ("bad value `%s' for -mcpu switch", alpha_tune_string);
     }
 
-  /* Do some sanity checks on the above options. */
+  /* 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");
+      alpha_fptm = ALPHA_FPTM_N;
+    }
 
   if ((alpha_fptm == ALPHA_FPTM_SU || alpha_fptm == ALPHA_FPTM_SUI)
       && alpha_tp != ALPHA_TP_INSN && ! TARGET_CPU_EV6)
@@ -317,7 +438,7 @@ override_options ()
        {
          { 3, 30, -1 },        /* ev4 -- Bcache is a guess */
          { 2, 12, 38 },        /* ev5 -- Bcache from PC164 LMbench numbers */
-         { 3, 12, 30 },        /* ev6 -- Bcache from DS20 LMbench. */
+         { 3, 12, 30 },        /* ev6 -- Bcache from DS20 LMbench.  */
        };
 
        lat = alpha_mlat_string[1] - '0';
@@ -349,9 +470,15 @@ override_options ()
   if (!g_switch_set)
     g_switch_value = 8;
 
+  /* Infer TARGET_SMALL_DATA from -fpic/-fPIC.  */
+  if (flag_pic == 1)
+    target_flags |= MASK_SMALL_DATA;
+  else if (flag_pic == 2)
+    target_flags &= ~MASK_SMALL_DATA;
+
   /* Align labels and loops for optimal branching.  */
   /* ??? Kludge these by not doing anything if we don't optimize and also if
-     we are writing ECOFF symbols to work around a bug in DEC's assembler. */
+     we are writing ECOFF symbols to work around a bug in DEC's assembler.  */
   if (optimize > 0 && write_symbols != SDB_DEBUG)
     {
       if (align_loops <= 0)
@@ -364,6 +491,15 @@ override_options ()
 
   /* Acquire a unique set number for our register saves and restores.  */
   alpha_sr_alias_set = new_alias_set ();
+
+  /* Register variables and functions with the garbage collector.  */
+
+#if TARGET_ABI_UNICOSMK
+  /* Set up function hooks.  */
+  init_machine_status = alpha_init_machine_status;
+  mark_machine_status = alpha_mark_machine_status;
+  free_machine_status = alpha_free_machine_status;
+#endif
 }
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -634,7 +770,7 @@ some_operand (op, mode)
   switch (GET_CODE (op))
     {
     case REG:  case MEM:  case CONST_DOUBLE:  case CONST_INT:  case LABEL_REF:
-    case SYMBOL_REF:  case CONST:
+    case SYMBOL_REF:  case CONST:  case HIGH:
       return 1;
 
     case SUBREG:
@@ -681,9 +817,23 @@ input_operand (op, mode)
     case LABEL_REF:
     case SYMBOL_REF:
     case CONST:
+      if (TARGET_EXPLICIT_RELOCS)
+       {
+         /* We don't split symbolic operands into something unintelligable
+            until after reload, but we do not wish non-small, non-global
+            symbolic operands to be reconstructed from their high/lo_sum
+            form.  */
+         return (small_symbolic_operand (op, mode)
+                 || global_symbolic_operand (op, mode));
+       }
+
       /* This handles both the Windows/NT and OSF cases.  */
       return mode == ptr_mode || mode == DImode;
 
+    case HIGH:
+      return (TARGET_EXPLICIT_RELOCS
+             && local_symbolic_operand (XEXP (op, 0), mode));
+
     case REG:
     case ADDRESSOF:
       return 1;
@@ -691,7 +841,7 @@ input_operand (op, mode)
     case SUBREG:
       if (register_operand (op, mode))
        return 1;
-      /* ... fall through ... */
+      /* ... fall through ...  */
     case MEM:
       return ((TARGET_BWX || (mode != HImode && mode != QImode))
              && general_operand (op, mode));
@@ -713,17 +863,149 @@ input_operand (op, mode)
 }
 
 /* Return 1 if OP is a SYMBOL_REF for a function known to be in this
-   file.  */
+   file, and in the same section as the current function.  */
 
 int
 current_file_function_operand (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  return (GET_CODE (op) == SYMBOL_REF
-         && ! profile_flag && ! profile_block_flag
-         && (SYMBOL_REF_FLAG (op)
-             || op == XEXP (DECL_RTL (current_function_decl), 0)));
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  /* Easy test for recursion.  */
+  if (op == XEXP (DECL_RTL (current_function_decl), 0))
+    return 1;
+
+  /* Otherwise, we need the DECL for the SYMBOL_REF, which we can't get.
+     So SYMBOL_REF_FLAG has been declared to imply that the function is
+     in the default text section.  So we must also check that the current
+     function is also in the text section.  */
+  if (SYMBOL_REF_FLAG (op) && decl_in_text_section (current_function_decl))
+    return 1;
+
+  return 0;
+}
+
+/* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr.  */
+
+int
+direct_call_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  /* Must be defined in this file.  */
+  if (! current_file_function_operand (op, mode))
+    return 0;
+
+  /* If profiling is implemented via linker tricks, we can't jump
+     to the nogp alternate entry point.  */
+  /* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
+     but is approximately correct for the OSF ABIs.  Don't know
+     what to do for VMS, NT, or UMK.  */
+  if (! TARGET_PROFILING_NEEDS_GP
+      && ! current_function_profile)
+    return 0;
+
+  return 1;
+}
+
+/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
+   a variable known to be defined in this file.  */
+
+static bool
+local_symbol_p (op)
+     rtx op;
+{
+  const char *str = XSTR (op, 0);
+
+  /* ??? SYMBOL_REF_FLAG is set for local function symbols, but we
+     run into problems with the rtl inliner in that the symbol was
+     once external, but is local after inlining, which results in
+     unrecognizable insns.  */
+
+  return (CONSTANT_POOL_ADDRESS_P (op)
+         /* If @, then ENCODE_SECTION_INFO sez it's local.  */
+         || str[0] == '@'
+         /* If *$, then ASM_GENERATE_INTERNAL_LABEL sez it's local.  */
+         || (str[0] == '*' && str[1] == '$'));
+}
+
+int
+local_symbolic_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) == LABEL_REF)
+    return 1;
+
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+    op = XEXP (XEXP (op, 0), 0);
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  return local_symbol_p (op);
+}
+
+/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
+   known to be defined in this file in the small data area.  */
+
+int
+small_symbolic_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  const char *str;
+
+  if (! TARGET_SMALL_DATA)
+    return 0;
+
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+    op = XEXP (XEXP (op, 0), 0);
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  if (CONSTANT_POOL_ADDRESS_P (op))
+    return GET_MODE_SIZE (get_pool_mode (op)) <= (unsigned) g_switch_value;
+  else
+    {
+      str = XSTR (op, 0);
+      return str[0] == '@' && str[1] == 's';
+    }
+}
+
+/* Return true if OP is a SYMBOL_REF or CONST referencing a variable
+   not known (or known not) to be defined in this file.  */
+
+int
+global_symbolic_operand (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST_INT)
+    op = XEXP (XEXP (op, 0), 0);
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  return ! local_symbol_p (op);
 }
 
 /* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
@@ -736,9 +1018,44 @@ call_operand (op, mode)
   if (mode != Pmode)
     return 0;
 
-  return (GET_CODE (op) == SYMBOL_REF
-         || (GET_CODE (op) == REG
-             && (TARGET_OPEN_VMS || TARGET_WINDOWS_NT || REGNO (op) == 27)));
+  if (GET_CODE (op) == REG)
+    {
+      if (TARGET_ABI_OSF)
+       {
+         /* Disallow virtual registers to cope with pathalogical test cases
+            such as compile/930117-1.c in which the virtual reg decomposes
+            to the frame pointer.  Which is a hard reg that is not $27.  */
+         return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER);
+       }
+      else
+       return 1;
+    }
+  if (TARGET_ABI_UNICOSMK)
+    return 0;
+  if (GET_CODE (op) == SYMBOL_REF)
+    return 1;
+
+  return 0;
+}
+
+/* Returns 1 if OP is a symbolic operand, i.e. a symbol_ref or a label_ref,
+   possibly with an offset.  */
+
+int
+symbolic_operand (op, mode)
+      register rtx op;
+      enum machine_mode mode;
+{
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+  if (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == LABEL_REF)
+    return 1;
+  if (GET_CODE (op) == CONST
+      && GET_CODE (XEXP (op,0)) == PLUS
+      && GET_CODE (XEXP (XEXP (op,0), 0)) == SYMBOL_REF
+      && GET_CODE (XEXP (XEXP (op,0), 1)) == CONST_INT)
+    return 1;
+  return 0;
 }
 
 /* Return 1 if OP is a valid Alpha comparison operator.  Here we know which
@@ -1026,12 +1343,12 @@ reg_no_subreg_operand (op, mode)
      register rtx op;
      enum machine_mode mode;
 {
-  if (GET_CODE (op) == SUBREG)
+  if (GET_CODE (op) != REG)
     return 0;
   return register_operand (op, mode);
 }
 
-/* Recognize a addition operation that includes a constant.  Used to
+/* Recognize an addition operation that includes a constant.  Used to
    convince reload to canonize (plus (plus reg c1) c2) during register
    elimination.  */
 
@@ -1050,92 +1367,735 @@ addition_operation (op, mode)
   return 0;
 }
 
+/* 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 (value, c)
+     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 (value, c)
+     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 (value, c)
+     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);
+
+    default:
+      return false;
+    }
+}
+
 /* Return 1 if this function can directly return via $26.  */
 
 int
 direct_return ()
 {
-  return (! TARGET_OPEN_VMS && reload_completed && alpha_sa_size () == 0
+  return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK
+         && reload_completed
+         && alpha_sa_size () == 0
          && get_frame_size () == 0
          && current_function_outgoing_args_size == 0
          && current_function_pretend_args_size == 0);
 }
-\f
-/* REF is an alignable memory location.  Place an aligned SImode
-   reference into *PALIGNED_MEM and the number of bits to shift into
-   *PBITNUM.  SCRATCH is a free register for use in reloading out
-   of range stack slots.  */
 
-void
-get_aligned_mem (ref, paligned_mem, pbitnum)
-     rtx ref;
-     rtx *paligned_mem, *pbitnum;
+/* Return the ADDR_VEC associated with a tablejump insn.  */
+
+rtx
+alpha_tablejump_addr_vec (insn)
+     rtx insn;
 {
-  rtx base;
-  HOST_WIDE_INT offset = 0;
+  rtx tmp;
 
-  if (GET_CODE (ref) != MEM)
-    abort ();
+  tmp = JUMP_LABEL (insn);
+  if (!tmp)
+    return NULL_RTX;
+  tmp = NEXT_INSN (tmp);
+  if (!tmp)
+    return NULL_RTX;
+  if (GET_CODE (tmp) == JUMP_INSN
+      && GET_CODE (PATTERN (tmp)) == ADDR_DIFF_VEC)
+    return PATTERN (tmp);
+  return NULL_RTX;
+}
 
-  if (reload_in_progress
-      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
-    {
-      base = find_replacement (&XEXP (ref, 0));
+/* Return the label of the predicted edge, or CONST0_RTX if we don't know.  */
 
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
-    }
-  else
+rtx
+alpha_tablejump_best_label (insn)
+     rtx insn;
+{
+  rtx jump_table = alpha_tablejump_addr_vec (insn);
+  rtx best_label = NULL_RTX;
+
+  /* ??? Once the CFG doesn't keep getting completely rebuilt, look
+     there for edge frequency counts from profile data.  */
+
+  if (jump_table)
     {
-      base = XEXP (ref, 0);
-    }
+      int n_labels = XVECLEN (jump_table, 1);
+      int best_count = -1;
+      int i, j;
 
-  if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+      for (i = 0; i < n_labels; i++)
+       {
+         int count = 1;
 
-  *paligned_mem = gen_rtx_MEM (SImode, plus_constant (base, offset & ~3));
-  MEM_COPY_ATTRIBUTES (*paligned_mem, ref);
+         for (j = i + 1; j < n_labels; j++)
+           if (XEXP (XVECEXP (jump_table, 1, i), 0)
+               == XEXP (XVECEXP (jump_table, 1, j), 0))
+             count++;
 
-  /* Sadly, we cannot use alias sets here because we may overlap other
-     data in a different alias set.  */
-  MEM_ALIAS_SET (*paligned_mem) = 0;
+         if (count > best_count)
+           best_count = count, best_label = XVECEXP (jump_table, 1, i);
+       }
+    }
 
-  *pbitnum = GEN_INT ((offset & 3) * 8);
+  return best_label ? best_label : const0_rtx;
+}
+\f
+/* Return true if the function DECL will be placed in the default text
+   section.  */
+/* ??? Ideally we'd be able to always move from a SYMBOL_REF back to the
+   decl, as that would allow us to determine if two functions are in the
+   same section, which is what we really want to know.  */
+
+static bool
+decl_in_text_section (decl)
+     tree decl;
+{
+  return (DECL_SECTION_NAME (decl) == NULL_TREE
+         && ! (flag_function_sections
+               || (targetm.have_named_sections
+                   && DECL_ONE_ONLY (decl))));
 }
 
-/* Similar, but just get the address.  Handle the two reload cases.  
-   Add EXTRA_OFFSET to the address we return.  */
+/* If we are referencing a function that is static, make the SYMBOL_REF
+   special.  We use this to see indicate we can branch to this function
+   without setting PV or restoring GP. 
 
-rtx
-get_unaligned_address (ref, extra_offset)
-     rtx ref;
-     int extra_offset;
-{
-  rtx base;
-  HOST_WIDE_INT offset = 0;
+   If this is a variable that is known to be defined locally, add "@v"
+   to the name.  If in addition the variable is to go in .sdata/.sbss,
+   then add "@s" instead.  */
 
-  if (GET_CODE (ref) != MEM)
-    abort ();
+void
+alpha_encode_section_info (decl, first)
+     tree decl;
+     int first ATTRIBUTE_UNUSED;
+{
+  const char *symbol_str;
+  bool is_local, is_small;
 
-  if (reload_in_progress
-      && ! memory_address_p (GET_MODE (ref), XEXP (ref, 0)))
+  if (TREE_CODE (decl) == FUNCTION_DECL)
     {
-      base = find_replacement (&XEXP (ref, 0));
+      /* We mark public functions once they are emitted; otherwise we
+        don't know that they exist in this unit of translation.  */
+      if (TREE_PUBLIC (decl))
+       return;
 
-      if (! memory_address_p (GET_MODE (ref), base))
-       abort ();
-    }
-  else
-    {
-      base = XEXP (ref, 0);
+      /* Do not mark functions that are not in .text; otherwise we
+        don't know that they are near enough for a direct branch.  */
+      if (! decl_in_text_section (decl))
+       return;
+
+      SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
+      return;
     }
 
-  if (GET_CODE (base) == PLUS)
-    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+  /* Early out if we're not going to do anything with this data.  */
+  if (! TARGET_EXPLICIT_RELOCS)
+    return;
+
+  /* Careful not to prod global register variables.  */
+  if (TREE_CODE (decl) != VAR_DECL
+      || GET_CODE (DECL_RTL (decl)) != MEM
+      || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
+    return;
+    
+  symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
+
+  /* A variable is considered "local" if it is defined in this module.  */
+
+  /* Local binding occurs for any non-default visibility.  */
+  if (MODULE_LOCAL_P (decl))
+    is_local = true;
+  /* Otherwise, variables defined outside this object may not be local.  */
+  else if (DECL_EXTERNAL (decl))
+    is_local = false;
+  /* Linkonce and weak data is never local.  */
+  else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
+    is_local = false;
+  /* Static variables are always local.  */
+  else if (! TREE_PUBLIC (decl))
+    is_local = true;
+  /* If PIC, then assume that any global name can be overridden by
+     symbols resolved from other modules.  */
+  else if (flag_pic)
+    is_local = false;
+  /* Uninitialized COMMON variable may be unified with symbols
+     resolved from other modules.  */
+  else if (DECL_COMMON (decl)
+          && (DECL_INITIAL (decl) == NULL
+              || DECL_INITIAL (decl) == error_mark_node))
+    is_local = false;
+  /* Otherwise we're left with initialized (or non-common) global data
+     which is of necessity defined locally.  */
+  else
+    is_local = true;
+
+  /* Determine if DECL will wind up in .sdata/.sbss.  */
+
+  is_small = false;
+  if (DECL_SECTION_NAME (decl))
+    {
+      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+      if (strcmp (section, ".sdata") == 0
+         || strcmp (section, ".sbss") == 0)
+       is_small = true;
+    }
+  else
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+
+      /* If the variable has already been defined in the output file, then it
+        is too late to put it in sdata if it wasn't put there in the first
+        place.  The test is here rather than above, because if it is already
+        in sdata, then it can stay there.  */
+
+      if (TREE_ASM_WRITTEN (decl))
+       ;
+
+      /* If this is an incomplete type with size 0, then we can't put it in
+        sdata because it might be too big when completed.  */
+      else if (size > 0 && size <= g_switch_value)
+       is_small = true;
+    }
+
+  /* Finally, encode this into the symbol string.  */
+  if (is_local)
+    {
+      const char *string;
+      char *newstr;
+      size_t len;
+
+      if (symbol_str[0] == '@')
+       {
+         if (symbol_str[1] == (is_small ? 's' : 'v'))
+           return;
+         symbol_str += 2;
+       }
+
+      len = strlen (symbol_str) + 1;
+      newstr = alloca (len + 2);
+
+      newstr[0] = '@';
+      newstr[1] = (is_small ? 's' : 'v');
+      memcpy (newstr + 2, symbol_str, len);
+         
+      string = ggc_alloc_string (newstr, len + 2 - 1);
+      XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
+    }
+  else if (symbol_str[0] == '@')
+    abort ();
+}
+
+/* legitimate_address_p recognizes an RTL expression that is a valid
+   memory address for an instruction.  The MODE argument is the
+   machine mode for the MEM expression that wants to use this address.
+
+   For Alpha, we have either a constant address or the sum of a
+   register and a constant address, or just a register.  For DImode,
+   any of those forms can be surrounded with an AND that clear the
+   low-order three bits; this is an "unaligned" access.  */
+
+bool
+alpha_legitimate_address_p (mode, x, strict)
+     enum machine_mode mode;
+     rtx x;
+     int strict;
+{
+  /* If this is an ldq_u type address, discard the outer AND.  */
+  if (mode == DImode
+      && GET_CODE (x) == AND
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && INTVAL (XEXP (x, 1)) == -8)
+    x = XEXP (x, 0);
+
+  /* Discard non-paradoxical subregs.  */
+  if (GET_CODE (x) == SUBREG
+      && (GET_MODE_SIZE (GET_MODE (x))
+         < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+    x = SUBREG_REG (x);
+
+  /* Unadorned general registers are valid.  */
+  if (REG_P (x)
+      && (strict
+         ? STRICT_REG_OK_FOR_BASE_P (x)
+         : NONSTRICT_REG_OK_FOR_BASE_P (x)))
+    return true;
+
+  /* Constant addresses (i.e. +/- 32k) are valid.  */
+  if (CONSTANT_ADDRESS_P (x))
+    return true;
+
+  /* Register plus a small constant offset is valid.  */
+  if (GET_CODE (x) == PLUS)
+    {
+      rtx ofs = XEXP (x, 1);
+      x = XEXP (x, 0);
+
+      /* Discard non-paradoxical subregs.  */
+      if (GET_CODE (x) == SUBREG
+          && (GET_MODE_SIZE (GET_MODE (x))
+             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+       x = SUBREG_REG (x);
+
+      if (REG_P (x))
+       {
+         if (! strict
+             && NONSTRICT_REG_OK_FP_BASE_P (x)
+             && GET_CODE (ofs) == CONST_INT)
+           return true;
+         if ((strict
+              ? STRICT_REG_OK_FOR_BASE_P (x)
+              : NONSTRICT_REG_OK_FOR_BASE_P (x))
+             && CONSTANT_ADDRESS_P (ofs))
+           return true;
+       }
+      else if (GET_CODE (x) == ADDRESSOF
+              && GET_CODE (ofs) == CONST_INT)
+       return true;
+    }
+
+  /* If we're managing explicit relocations, LO_SUM is valid, as
+     are small data symbols.  */
+  else if (TARGET_EXPLICIT_RELOCS)
+    {
+      if (small_symbolic_operand (x, Pmode))
+       return true;
+
+      if (GET_CODE (x) == LO_SUM)
+       {
+         rtx ofs = XEXP (x, 1);
+         x = XEXP (x, 0);
+
+         /* Discard non-paradoxical subregs.  */
+         if (GET_CODE (x) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (x))
+                 < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+           x = SUBREG_REG (x);
+
+         /* Must have a valid base register.  */
+         if (! (REG_P (x)
+                && (strict
+                    ? STRICT_REG_OK_FOR_BASE_P (x)
+                    : NONSTRICT_REG_OK_FOR_BASE_P (x))))
+           return false;
+
+         /* The symbol must be local.  */
+         if (local_symbolic_operand (ofs, Pmode))
+           return true;
+       }
+    }
+
+  return false;
+}
+
+/* Try machine-dependent ways of modifying an illegitimate address
+   to be legitimate.  If we find one, return the new, valid address.  */
+
+rtx
+alpha_legitimize_address (x, scratch, mode)
+     rtx x;
+     rtx scratch;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  HOST_WIDE_INT addend;
+
+  /* If the address is (plus reg const_int) and the CONST_INT is not a
+     valid offset, compute the high part of the constant and add it to
+     the register.  Then our address is (plus temp low-part-const).  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST_INT
+      && ! CONSTANT_ADDRESS_P (XEXP (x, 1)))
+    {
+      addend = INTVAL (XEXP (x, 1));
+      x = XEXP (x, 0);
+      goto split_addend;
+    }
+
+  /* If the address is (const (plus FOO const_int)), find the low-order
+     part of the CONST_INT.  Then load FOO plus any high-order part of the
+     CONST_INT into a register.  Our address is (plus reg low-part-const).
+     This is done to reduce the number of GOT entries.  */
+  if (!no_new_pseudos
+      && GET_CODE (x) == CONST
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
+    {
+      addend = INTVAL (XEXP (XEXP (x, 0), 1));
+      x = force_reg (Pmode, XEXP (XEXP (x, 0), 0));
+      goto split_addend;
+    }
+
+  /* If we have a (plus reg const), emit the load as in (2), then add
+     the two registers, and finally generate (plus reg low-part-const) as
+     our address.  */
+  if (!no_new_pseudos
+      && GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && GET_CODE (XEXP (x, 1)) == CONST
+      && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == CONST_INT)
+    {
+      addend = INTVAL (XEXP (XEXP (XEXP (x, 1), 0), 1));
+      x = expand_simple_binop (Pmode, PLUS, XEXP (x, 0),
+                              XEXP (XEXP (XEXP (x, 1), 0), 0),
+                              NULL_RTX, 1, OPTAB_LIB_WIDEN);
+      goto split_addend;
+    }
+
+  /* If this is a local symbol, split the address into HIGH/LO_SUM parts.  */
+  if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode))
+    {
+      if (local_symbolic_operand (x, Pmode))
+       {
+         if (small_symbolic_operand (x, Pmode))
+           return x;
+         else
+           {
+             if (!no_new_pseudos)
+               scratch = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, scratch,
+                                     gen_rtx_HIGH (Pmode, x)));
+             return gen_rtx_LO_SUM (Pmode, scratch, x);
+           }
+       }
+    }
+
+  return NULL;
+
+ split_addend:
+  {
+    HOST_WIDE_INT low, high;
+
+    low = ((addend & 0xffff) ^ 0x8000) - 0x8000;
+    addend -= low;
+    high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000;
+    addend -= high;
+
+    if (addend)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
+    if (high)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
+
+    return plus_constant (x, low);
+  }
+}
+
+/* For TARGET_EXPLICIT_RELOCS, we don't obfuscate a SYMBOL_REF to a
+   small symbolic operand until after reload.  At which point we need
+   to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref))
+   so that sched2 has the proper dependency information.  */
+
+int
+some_small_symbolic_operand (x, mode)
+     rtx x;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return for_each_rtx (&x, some_small_symbolic_operand_1, NULL);
+}
+
+static int
+some_small_symbolic_operand_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
+
+  return small_symbolic_operand (x, Pmode) != 0;
+}
+
+rtx
+split_small_symbolic_operand (x)
+     rtx x;
+{
+  x = copy_insn (x);
+  for_each_rtx (&x, split_small_symbolic_operand_1, NULL);
+  return x;
+}
+
+static int
+split_small_symbolic_operand_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
+
+  if (small_symbolic_operand (x, Pmode))
+    {
+      x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
+      *px = x;
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Try a machine-dependent way of reloading an illegitimate address
+   operand.  If we find one, push the reload and return the new rtx.  */
+   
+rtx
+alpha_legitimize_reload_address (x, mode, opnum, type, ind_levels)
+     rtx x;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int opnum;
+     int type;
+     int ind_levels ATTRIBUTE_UNUSED;
+{
+  /* We must recognize output that we have already generated ourselves.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == PLUS
+      && GET_CODE (XEXP (XEXP (x, 0), 0)) == REG
+      && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    {
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, type);
+      return x;
+    }
+
+  /* We wish to handle large displacements off a base register by
+     splitting the addend across an ldah and the mem insn.  This
+     cuts number of extra insns needed from 3 to 1.  */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == REG
+      && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER
+      && REGNO_OK_FOR_BASE_P (REGNO (XEXP (x, 0)))
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
+      HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000;
+      HOST_WIDE_INT high
+       = (((val - low) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+
+      /* Check for 32-bit overflow.  */
+      if (high + low != val)
+       return NULL_RTX;
+
+      /* Reload the high part into a base reg; leave the low part
+        in the mem directly.  */
+      x = gen_rtx_PLUS (GET_MODE (x),
+                       gen_rtx_PLUS (GET_MODE (x), XEXP (x, 0),
+                                     GEN_INT (high)),
+                       GEN_INT (low));
+
+      push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
+                  BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
+                  opnum, type);
+      return x;
+    }
+
+  return NULL_RTX;
+}
+\f
+/* REF is an alignable memory location.  Place an aligned SImode
+   reference into *PALIGNED_MEM and the number of bits to shift into
+   *PBITNUM.  SCRATCH is a free register for use in reloading out
+   of range stack slots.  */
+
+void
+get_aligned_mem (ref, paligned_mem, pbitnum)
+     rtx ref;
+     rtx *paligned_mem, *pbitnum;
+{
+  rtx base;
+  HOST_WIDE_INT offset = 0;
+
+  if (GET_CODE (ref) != MEM)
+    abort ();
+
+  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 ();
+    }
+  else
+    {
+      base = XEXP (ref, 0);
+    }
+
+  if (GET_CODE (base) == PLUS)
+    offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
+
+  *paligned_mem
+    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
+
+  if (WORDS_BIG_ENDIAN)
+    *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
+                             + (offset & 3) * 8));
+  else
+    *pbitnum = GEN_INT ((offset & 3) * 8);
+}
+
+/* Similar, but just get the address.  Handle the two reload cases.  
+   Add EXTRA_OFFSET to the address we return.  */
+
+rtx
+get_unaligned_address (ref, extra_offset)
+     rtx ref;
+     int extra_offset;
+{
+  rtx base;
+  HOST_WIDE_INT offset = 0;
+
+  if (GET_CODE (ref) != MEM)
+    abort ();
+
+  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 ();
+    }
+  else
+    {
+      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);
 }
 
+/* On the Alpha, all (non-symbolic) constants except zero go into
+   a floating-point register via memory.  Note that we cannot 
+   return anything that is not a subset of CLASS, and that some
+   symbolic constants cannot be dropped to memory.  */
+
+enum reg_class
+alpha_preferred_reload_class(x, class)
+     rtx x;
+     enum reg_class class;
+{
+  /* Zero is present in any register class.  */
+  if (x == CONST0_RTX (GET_MODE (x)))
+    return class;
+
+  /* These sorts of constants we can easily drop to memory.  */
+  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+    {
+      if (class == FLOAT_REGS)
+       return NO_REGS;
+      if (class == ALL_REGS)
+       return GENERAL_REGS;
+      return class;
+    }
+
+  /* All other kinds of constants should not (and in the case of HIGH
+     cannot) be dropped to memory -- instead we use a GENERAL_REGS
+     secondary reload.  */
+  if (CONSTANT_P (x))
+    return (class == ALL_REGS ? GENERAL_REGS : class);
+
+  return class;
+}
+
 /* 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
@@ -1178,7 +2138,8 @@ secondary_reload_class (class, mode, x, in)
              > GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
        return GENERAL_REGS;
 
-      if (in && INTEGRAL_MODE_P (mode) && ! general_operand (x, mode))
+      if (in && INTEGRAL_MODE_P (mode)
+         && ! (memory_operand (x, mode) || x == const0_rtx))
        return GENERAL_REGS;
     }
 
@@ -1225,7 +2186,6 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
         are the only thing we would be able to differentiate anyway,
         there does not seem to be any point in convoluting the early
         out of the alias check.  */
-      /* MEM_ALIAS_SET (x) = alias_set; */
       break;
 
     default:
@@ -1275,15 +2235,29 @@ alpha_emit_set_const (target, mode, c, n)
      HOST_WIDE_INT c;
      int n;
 {
-  rtx pat;
+  rtx result = 0;
+  rtx orig_target = target;
   int i;
 
-  /* Try 1 insn, then 2, then up to N. */
-  for (i = 1; i <= n; i++)
-    if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
-      return pat;
+  /* 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)
+    {
+      target = gen_lowpart (DImode, target);
+      mode = DImode;
+    }
+
+  /* Try 1 insn, then 2, then up to N.  */
+  for (i = 1; i <= n && result == 0; i++)
+    result = alpha_emit_set_const_1 (target, mode, c, i);
 
-  return 0;
+  /* Allow for the case where we changed the mode of TARGET.  */
+  if (result == target)
+    result = orig_target;
+
+  return result;
 }
 
 /* Internal routine for the above to check for N or below insns.  */
@@ -1299,8 +2273,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
   int i, bits;
   /* Use a pseudo if highly optimizing and still generating RTL.  */
   rtx subtarget
-    = (flag_expensive_optimizations && rtx_equal_function_value_matters
-       ? 0 : target);
+    = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target);
   rtx temp;
 
 #if HOST_BITS_PER_WIDE_INT == 64
@@ -1314,7 +2287,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
 
   /* If this is a sign-extended 32-bit constant, we can do this in at most
      three insns, so do it if we have enough insns left.  We always have
-     a sign-extended 32-bit constant when compiling on a narrow machine.   */
+     a sign-extended 32-bit constant when compiling on a narrow machine.  */
 
   if (HOST_BITS_PER_WIDE_INT != 64
       || c >> 31 == -1 || c >> 31 == 0)
@@ -1365,8 +2338,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
      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 && ! rtx_equal_function_value_matters))
+  if (n == 1 || (mode == SImode && no_new_pseudos))
     return 0;
 
   /* Next, see if we can load a related constant and then shift and possibly
@@ -1429,8 +2401,8 @@ alpha_emit_set_const_1 (target, mode, c, n)
 
       /* 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. */
-      
+        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)
        for (; bits > 0; bits--)
@@ -1531,6 +2503,193 @@ alpha_emit_set_long_const (target, c1, c2)
   return target;
 }
 
+/* Expand a move instruction; return true if all work is done.
+   We don't handle non-bwx subword loads here.  */
+
+bool
+alpha_expand_mov (mode, operands)
+     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]);
+
+  /* Allow legitimize_address to perform some simplifications.  */
+  if (mode == Pmode && symbolic_operand (operands[1], mode))
+    {
+      rtx tmp = alpha_legitimize_address (operands[1], operands[0], mode);
+      if (tmp)
+       {
+         operands[1] = tmp;
+         return false;
+       }
+    }
+
+  /* Early out for non-constants and valid constants.  */
+  if (! CONSTANT_P (operands[1]) || input_operand (operands[1], mode))
+    return false;
+
+  /* Split large integers.  */
+  if (GET_CODE (operands[1]) == CONST_INT
+      || GET_CODE (operands[1]) == CONST_DOUBLE)
+    {
+      HOST_WIDE_INT i0, i1;
+      rtx temp = NULL_RTX;
+
+      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;
+       }
+    }
+
+  /* Otherwise we've nothing left but to drop the thing to memory.  */
+  operands[1] = force_const_mem (DImode, 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];
+    }
+  else
+    operands[1] = validize_mem (operands[1]);
+  return false;
+}
+
+/* Expand a non-bwx QImode or HImode move instruction;
+   return true if all work is done.  */
+
+bool
+alpha_expand_mov_nobwx (mode, operands)
+     enum machine_mode mode;
+     rtx *operands;
+{
+  /* If the output is not a register, the input must be.  */
+  if (GET_CODE (operands[0]) == MEM)
+    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 (aligned_memory_operand (operands[1], mode))
+       {
+         if (reload_in_progress)
+           {
+             emit_insn ((mode == QImode
+                         ? gen_reload_inqi_help
+                         : gen_reload_inhi_help)
+                        (operands[0], operands[1],
+                         gen_rtx_REG (SImode, REGNO (operands[0]))));
+           }
+         else
+           {
+             rtx aligned_mem, bitnum;
+             rtx scratch = gen_reg_rtx (SImode);
+
+             get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
+             emit_insn ((mode == QImode
+                         ? gen_aligned_loadqi
+                         : gen_aligned_loadhi)
+                        (operands[0], aligned_mem, bitnum, scratch));
+           }
+       }
+      else
+       {
+         /* Don't pass these as parameters since that makes the generated
+            code depend on parameter evaluation order which will cause
+            bootstrap failures.  */
+
+         rtx temp1 = gen_reg_rtx (DImode);
+         rtx temp2 = gen_reg_rtx (DImode);
+         rtx seq = ((mode == QImode
+                     ? gen_unaligned_loadqi
+                     : gen_unaligned_loadhi)
+                    (operands[0], get_unaligned_address (operands[1], 0),
+                     temp1, temp2));
+
+         alpha_set_memflags (seq, operands[1]);
+         emit_insn (seq);
+       }
+      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 (aligned_memory_operand (operands[0], mode))
+       {
+         rtx aligned_mem, bitnum;
+         rtx temp1 = gen_reg_rtx (SImode);
+         rtx temp2 = gen_reg_rtx (SImode);
+
+         get_aligned_mem (operands[0], &aligned_mem, &bitnum);
+
+         emit_insn (gen_aligned_store (aligned_mem, operands[1], bitnum,
+                                       temp1, temp2));
+       }
+      else
+       {
+         rtx temp1 = gen_reg_rtx (DImode);
+         rtx temp2 = gen_reg_rtx (DImode);
+         rtx temp3 = gen_reg_rtx (DImode);
+         rtx seq = ((mode == QImode
+                     ? gen_unaligned_storeqi
+                     : gen_unaligned_storehi)
+                    (get_unaligned_address (operands[0], 0),
+                     operands[1], temp1, temp2, temp3));
+
+         alpha_set_memflags (seq, operands[0]);
+         emit_insn (seq);
+       }
+      return true;
+    }
+
+  return false;
+}
+
 /* Generate an unsigned DImode to FP conversion.  This is the same code
    optabs would emit if we didn't have TFmode patterns.
 
@@ -1597,8 +2756,7 @@ alpha_emit_floatuns (operands)
   i1 = gen_reg_rtx (DImode);
   f0 = gen_reg_rtx (mode);
 
-  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0,
-                          8, neglab);
+  emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
 
   emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
   emit_jump_insn (gen_jump (donelab));
@@ -1666,7 +2824,7 @@ alpha_emit_conditional_branch (code)
 
     case NE:
     case ORDERED:
-      /* These must be reversed. */
+      /* These must be reversed.  */
       cmp_code = reverse_condition (code), branch_code = EQ;
       break;
 
@@ -1833,7 +2991,7 @@ alpha_emit_setcc (code)
       break;
 
     case GE:  case GT: case GEU:  case GTU:
-      /* These are normally need swapping, but for integer zero we have
+      /* These normally need swapping, but for integer zero we have
         special patterns that recognize swapped operands.  */
       if (!fp_p && op1 == const0_rtx)
        break;
@@ -1878,7 +3036,7 @@ alpha_emit_setcc (code)
    a conditional move (if_then_else CMP ...).
    If both of the operands that set cc0 are non-zero we must emit
    an insn to perform the compare (it can't be done within
-   the conditional move). */
+   the conditional move).  */
 rtx
 alpha_emit_conditional_move (cmp, mode)
      rtx cmp;
@@ -1924,8 +3082,9 @@ alpha_emit_conditional_move (cmp, mode)
          break;
 
        case GE: case GT: case GEU: case GTU:
-         /* These must be swapped.  */
-         if (op1 == CONST0_RTX (cmp_mode))
+         /* These normally need swapping, but for integer zero we have
+            special patterns that recognize swapped operands.  */
+         if (!fp_p && op1 == const0_rtx)
            cmp_code = code, code = NE;
          else
            {
@@ -1952,7 +3111,7 @@ alpha_emit_conditional_move (cmp, mode)
     }
 
   /* We may be able to use a conditional move directly.
-     This avoids emitting spurious compares. */
+     This avoids emitting spurious compares.  */
   if (signed_comparison_operator (cmp, VOIDmode)
       && (!fp_p || local_fast_math)
       && (op0 == CONST0_RTX (cmp_mode) || op1 == CONST0_RTX (cmp_mode)))
@@ -1973,7 +3132,7 @@ alpha_emit_conditional_move (cmp, mode)
       break;
 
     case NE:
-      /* This must be reversed. */
+      /* This must be reversed.  */
       code = reverse_condition (code);
       cmov_code = EQ;
       break;
@@ -2046,41 +3205,46 @@ alpha_split_conditional_move (code, dest, cond, t_rtx, f_rtx)
       else
        subtarget = target;
     }
+  /* Below, we must be careful to use copy_rtx on target and subtarget
+     in intermediate insns, as they may be a subreg rtx, which may not
+     be shared.  */
 
   if (f == 0 && exact_log2 (diff) > 0
       /* On EV6, we've got enough shifters to make non-arithmatic 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. */
+        scarce resource, and on EV4 shift has the same latency as a cmove.  */
       && (diff <= 8 || alpha_cpu == PROCESSOR_EV6))
     {
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-      tmp = gen_rtx_ASHIFT (DImode, subtarget, GEN_INT (exact_log2 (t)));
+      tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget),
+                           GEN_INT (exact_log2 (t)));
       emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
     }
   else if (f == 0 && t == -1)
     {
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-      emit_insn (gen_negdi2 (target, subtarget));
+      emit_insn (gen_negdi2 (target, copy_rtx (subtarget)));
     }
   else if (diff == 1 || diff == 4 || diff == 8)
     {
       rtx add_op;
 
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
       if (diff == 1)
-       emit_insn (gen_adddi3 (target, subtarget, GEN_INT (f)));
+       emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f)));
       else
        {
          add_op = GEN_INT (f);
          if (sext_add_operand (add_op, mode))
            {
-             tmp = gen_rtx_MULT (DImode, subtarget, GEN_INT (diff));
+             tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget),
+                                 GEN_INT (diff));
              tmp = gen_rtx_PLUS (DImode, tmp, add_op);
              emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
            }
@@ -2103,8 +3267,8 @@ alpha_lookup_xfloating_lib_func (code)
 {
   struct xfloating_op
     {
-      enum rtx_code code;
-      const char *func;
+      const enum rtx_code code;
+      const char *const func;
     };
 
   static const struct xfloating_op vms_xfloating_ops[] = 
@@ -2153,7 +3317,7 @@ alpha_lookup_xfloating_lib_func (code)
      knowledge of the G_floating routines.  */
   if (TARGET_FLOAT_VAX)
     {
-      if (TARGET_OPEN_VMS)
+      if (TARGET_ABI_OPEN_VMS)
        {
          if (code == FLOAT_EXTEND)
            return "OTS$CVT_FLOAT_G_X";
@@ -2169,7 +3333,7 @@ alpha_lookup_xfloating_lib_func (code)
        }
     }
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     ops = vms_xfloating_ops;
   else
     ops = osf_xfloating_ops;
@@ -2338,10 +3502,10 @@ alpha_emit_xfloating_compare (code, op0, op1)
   operands[1] = op1;
   out = gen_reg_rtx (DImode);
 
-  /* ??? Strange equiv cause what's actually returned is -1,0,1, not a
-     proper boolean value.  */
-  alpha_emit_xfloating_libcall (func, out, operands, 2, 
-                               gen_rtx_COMPARE (TFmode, op0, op1));
+  /* ??? 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));
 
   return out;
 }
@@ -2397,9 +3561,8 @@ alpha_split_tfmode_pair (operands)
     }
   else if (GET_CODE (operands[1]) == MEM)
     {
-      operands[3] = change_address (operands[1], DImode,
-                                   plus_constant (XEXP (operands[1], 0), 8));
-      operands[2] = change_address (operands[1], DImode, NULL_RTX);
+      operands[3] = adjust_address (operands[1], DImode, 8);
+      operands[2] = adjust_address (operands[1], DImode, 0);
     }
   else if (operands[1] == CONST0_RTX (TFmode))
     operands[2] = operands[3] = const0_rtx;
@@ -2413,9 +3576,8 @@ alpha_split_tfmode_pair (operands)
     }
   else if (GET_CODE (operands[0]) == MEM)
     {
-      operands[1] = change_address (operands[0], DImode,
-                                   plus_constant (XEXP (operands[0], 0), 8));
-      operands[0] = change_address (operands[0], DImode, NULL_RTX);
+      operands[1] = adjust_address (operands[0], DImode, 8);
+      operands[0] = adjust_address (operands[0], DImode, 0);
     }
   else
     abort ();
@@ -2500,7 +3662,7 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
      HOST_WIDE_INT size, ofs;
      int sign;
 {
-  rtx meml, memh, addr, extl, exth, tmp;
+  rtx meml, memh, addr, extl, exth, tmp, mema;
   enum machine_mode mode;
 
   meml = gen_reg_rtx (DImode);
@@ -2509,31 +3671,45 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
   extl = gen_reg_rtx (DImode);
   exth = gen_reg_rtx (DImode);
 
+  mema = XEXP (mem, 0);
+  if (GET_CODE (mema) == LO_SUM)
+    mema = force_reg (Pmode, mema);
+
   /* AND addresses cannot be in any alias set, since they may implicitly
      alias surrounding code.  Ideally we'd have some alias set that 
      covered all types except those with alignment 8 or higher.  */
 
   tmp = change_address (mem, DImode,
                        gen_rtx_AND (DImode, 
-                                    plus_constant (XEXP (mem, 0), ofs),
+                                    plus_constant (mema, ofs),
                                     GEN_INT (-8)));
-  MEM_ALIAS_SET (tmp) = 0;
+  set_mem_alias_set (tmp, 0);
   emit_move_insn (meml, tmp);
 
   tmp = change_address (mem, DImode,
                        gen_rtx_AND (DImode, 
-                                    plus_constant (XEXP (mem, 0),
-                                                   ofs + size - 1),
+                                    plus_constant (mema, ofs + size - 1),
                                     GEN_INT (-8)));
-  MEM_ALIAS_SET (tmp) = 0;
+  set_mem_alias_set (tmp, 0);
   emit_move_insn (memh, tmp);
 
-  if (sign && size == 2)
+  if (WORDS_BIG_ENDIAN && sign && (size == 2 || size == 4))
     {
-      emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs+2));
+      emit_move_insn (addr, plus_constant (mema, -1));
 
-      emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
-      emit_insn (gen_extqh (exth, memh, addr));
+      emit_insn (gen_extqh_be (extl, meml, addr));
+      emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr));
+
+      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8),
+                          addr, 1, OPTAB_WIDEN);
+    }
+  else if (sign && size == 2)
+    {
+      emit_move_insn (addr, plus_constant (mema, ofs+2));
+
+      emit_insn (gen_extxl_le (extl, meml, GEN_INT (64), addr));
+      emit_insn (gen_extqh_le (exth, memh, addr));
 
       /* 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
@@ -2544,27 +3720,55 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
     }
   else
     {
-      emit_move_insn (addr, plus_constant (XEXP (mem, 0), ofs));
-      emit_insn (gen_extxl (extl, meml, GEN_INT (size*8), addr));
-      switch ((int) size)
+      if (WORDS_BIG_ENDIAN)
        {
-       case 2:
-         emit_insn (gen_extwh (exth, memh, addr));
-         mode = HImode;
-         break;
+         emit_move_insn (addr, plus_constant (mema, ofs+size-1));
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_extwh_be (extl, meml, addr));
+             mode = HImode;
+             break;
 
-       case 4:
-         emit_insn (gen_extlh (exth, memh, addr));
-         mode = SImode;
-         break;
+           case 4:
+             emit_insn (gen_extlh_be (extl, meml, addr));
+             mode = SImode;
+             break;
 
-       case 8:
-         emit_insn (gen_extqh (exth, memh, addr));
-         mode = DImode;
-         break;
+           case 8:
+             emit_insn (gen_extqh_be (extl, meml, addr));
+             mode = DImode;
+             break;
 
-       default:
-         abort();
+           default:
+             abort ();
+           }
+         emit_insn (gen_extxl_be (exth, memh, GEN_INT (size*8), addr));
+       }
+      else
+       {
+         emit_move_insn (addr, plus_constant (mema, ofs));
+         emit_insn (gen_extxl_le (extl, meml, GEN_INT (size*8), addr));
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_extwh_le (exth, memh, addr));
+             mode = HImode;
+             break;
+
+           case 4:
+             emit_insn (gen_extlh_le (exth, memh, addr));
+             mode = SImode;
+             break;
+
+           case 8:
+             emit_insn (gen_extqh_le (exth, memh, addr));
+             mode = DImode;
+             break;
+
+           default:
+             abort();
+           }
        }
 
       addr = expand_binop (mode, ior_optab, gen_lowpart (mode, extl),
@@ -2583,73 +3787,123 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
      rtx dst, src;
      HOST_WIDE_INT size, ofs;
 {
-  rtx dstl, dsth, addr, insl, insh, meml, memh;
+  rtx dstl, dsth, addr, insl, insh, meml, memh, dsta;
   
   dstl = gen_reg_rtx (DImode);
   dsth = gen_reg_rtx (DImode);
   insl = gen_reg_rtx (DImode);
   insh = gen_reg_rtx (DImode);
 
+  dsta = XEXP (dst, 0);
+  if (GET_CODE (dsta) == LO_SUM)
+    dsta = force_reg (Pmode, dsta);
+
   /* AND addresses cannot be in any alias set, since they may implicitly
      alias surrounding code.  Ideally we'd have some alias set that 
      covered all types except those with alignment 8 or higher.  */
 
   meml = change_address (dst, DImode,
                         gen_rtx_AND (DImode, 
-                                     plus_constant (XEXP (dst, 0), ofs),
+                                     plus_constant (dsta, ofs),
                                      GEN_INT (-8)));
-  MEM_ALIAS_SET (meml) = 0;
+  set_mem_alias_set (meml, 0);
 
   memh = change_address (dst, DImode,
                         gen_rtx_AND (DImode, 
-                                     plus_constant (XEXP (dst, 0),
-                                                    ofs+size-1),
+                                     plus_constant (dsta, ofs + size - 1),
                                      GEN_INT (-8)));
-  MEM_ALIAS_SET (memh) = 0;
+  set_mem_alias_set (memh, 0);
 
   emit_move_insn (dsth, memh);
   emit_move_insn (dstl, meml);
-  addr = copy_addr_to_reg (plus_constant (XEXP (dst, 0), ofs));
-
-  if (src != const0_rtx)
+  if (WORDS_BIG_ENDIAN)
     {
-      emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
-                           GEN_INT (size*8), addr));
+      addr = copy_addr_to_reg (plus_constant (dsta, ofs+size-1));
+
+      if (src != const0_rtx)
+       {
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_inswl_be (insh, gen_lowpart (HImode,src), addr));
+             break;
+           case 4:
+             emit_insn (gen_insll_be (insh, gen_lowpart (SImode,src), addr));
+             break;
+           case 8:
+             emit_insn (gen_insql_be (insh, gen_lowpart (DImode,src), addr));
+             break;
+           }
+         emit_insn (gen_insxh (insl, gen_lowpart (DImode, src),
+                               GEN_INT (size*8), addr));
+       }
 
       switch ((int) size)
        {
        case 2:
-         emit_insn (gen_inswl (insl, gen_lowpart (HImode, src), addr));
+         emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr));
          break;
        case 4:
-         emit_insn (gen_insll (insl, gen_lowpart (SImode, src), addr));
+         emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffffffff), addr));
          break;
        case 8:
-         emit_insn (gen_insql (insl, src, addr));
+         {
+#if HOST_BITS_PER_WIDE_INT == 32
+           rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+#else
+           rtx msk = constm1_rtx;
+#endif
+           emit_insn (gen_mskxl_be (dsth, dsth, msk, addr));
+         }
          break;
        }
+
+      emit_insn (gen_mskxh (dstl, dstl, GEN_INT (size*8), addr));
     }
+  else
+    {
+      addr = copy_addr_to_reg (plus_constant (dsta, ofs));
 
-  emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+      if (src != const0_rtx)
+       {
+         emit_insn (gen_insxh (insh, gen_lowpart (DImode, src),
+                               GEN_INT (size*8), addr));
 
-  switch ((int) size)
-    {
-    case 2:
-      emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffff), addr));
-      break;
-    case 4:
-      emit_insn (gen_mskxl (dstl, dstl, GEN_INT (0xffffffff), addr));
-      break;
-    case 8:
-      {
+         switch ((int) size)
+           {
+           case 2:
+             emit_insn (gen_inswl_le (insl, gen_lowpart (HImode, src), addr));
+             break;
+           case 4:
+             emit_insn (gen_insll_le (insl, gen_lowpart (SImode, src), addr));
+             break;
+           case 8:
+             emit_insn (gen_insql_le (insl, src, addr));
+             break;
+           }
+       }
+
+      emit_insn (gen_mskxh (dsth, dsth, GEN_INT (size*8), addr));
+
+      switch ((int) size)
+       {
+       case 2:
+         emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffff), addr));
+         break;
+       case 4:
+         emit_insn (gen_mskxl_le (dstl, dstl, GEN_INT (0xffffffff), addr));
+         break;
+       case 8:
+         {
 #if HOST_BITS_PER_WIDE_INT == 32
-       rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
+           rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
 #else
-       rtx msk = immed_double_const (0xffffffffffffffff, 0, DImode);
+           rtx msk = constm1_rtx;
 #endif
-       emit_insn (gen_mskxl (dstl, dstl, msk, addr));
-      }
-      break;
+           emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
+         }
+         break;
+       }
     }
 
   if (src != const0_rtx)
@@ -2657,10 +3911,18 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
       dsth = expand_binop (DImode, ior_optab, insh, dsth, dsth, 0, OPTAB_WIDEN);
       dstl = expand_binop (DImode, ior_optab, insl, dstl, dstl, 0, OPTAB_WIDEN);
     }
-  
-  /* Must store high before low for degenerate case of aligned.  */
-  emit_move_insn (memh, dsth);
-  emit_move_insn (meml, dstl);
+  if (WORDS_BIG_ENDIAN)
+    {
+      emit_move_insn (meml, dstl);
+      emit_move_insn (memh, dsth);
+    }
+  else
+    {
+      /* Must store high before low for degenerate case of aligned.  */
+      emit_move_insn (memh, dsth);
+      emit_move_insn (meml, dstl);
+    }
 }
 
 /* The block move code tries to maximize speed by separating loads and
@@ -2682,9 +3944,13 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
   rtx const im8 = GEN_INT (-8);
   rtx const i64 = GEN_INT (64);
   rtx ext_tmps[MAX_MOVE_WORDS], data_regs[MAX_MOVE_WORDS+1];
-  rtx sreg, areg, tmp;
+  rtx sreg, areg, tmp, smema;
   HOST_WIDE_INT i;
 
+  smema = XEXP (smem, 0);
+  if (GET_CODE (smema) == LO_SUM)
+    smema = force_reg (Pmode, smema);
+
   /* Generate all the tmp registers we need.  */
   for (i = 0; i < words; ++i)
     {
@@ -2694,39 +3960,47 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
   data_regs[words] = gen_reg_rtx (DImode);
 
   if (ofs != 0)
-    smem = change_address (smem, GET_MODE (smem),
-                          plus_constant (XEXP (smem, 0), ofs));
+    smem = adjust_address (smem, GET_MODE (smem), ofs);
   
   /* Load up all of the source data.  */
   for (i = 0; i < words; ++i)
     {
       tmp = change_address (smem, DImode,
                            gen_rtx_AND (DImode,
-                                        plus_constant (XEXP(smem,0), 8*i),
+                                        plus_constant (smema, 8*i),
                                         im8));
-      MEM_ALIAS_SET (tmp) = 0;
+      set_mem_alias_set (tmp, 0);
       emit_move_insn (data_regs[i], tmp);
     }
 
   tmp = change_address (smem, DImode,
                        gen_rtx_AND (DImode,
-                                    plus_constant (XEXP(smem,0), 8*words - 1),
+                                    plus_constant (smema, 8*words - 1),
                                     im8));
-  MEM_ALIAS_SET (tmp) = 0;
+  set_mem_alias_set (tmp, 0);
   emit_move_insn (data_regs[words], tmp);
 
   /* Extract the half-word fragments.  Unfortunately DEC decided to make
      extxh with offset zero a noop instead of zeroing the register, so 
      we must take care of that edge condition ourselves with cmov.  */
 
-  sreg = copy_addr_to_reg (XEXP (smem, 0));
+  sreg = copy_addr_to_reg (smema);
   areg = expand_binop (DImode, and_optab, sreg, GEN_INT (7), NULL, 
                       1, OPTAB_WIDEN);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (sreg, plus_constant (sreg, 7));
   for (i = 0; i < words; ++i)
     {
-      emit_insn (gen_extxl (data_regs[i], data_regs[i], i64, sreg));
-
-      emit_insn (gen_extqh (ext_tmps[i], data_regs[i+1], sreg));
+      if (WORDS_BIG_ENDIAN)
+       {
+         emit_insn (gen_extqh_be (data_regs[i], data_regs[i], sreg));
+         emit_insn (gen_extxl_be (ext_tmps[i], data_regs[i+1], i64, sreg));
+       }
+      else
+       {
+         emit_insn (gen_extxl_le (data_regs[i], data_regs[i], i64, sreg));
+         emit_insn (gen_extqh_le (ext_tmps[i], data_regs[i+1], sreg));
+       }
       emit_insn (gen_rtx_SET (VOIDmode, ext_tmps[i],
                              gen_rtx_IF_THEN_ELSE (DImode,
                                                    gen_rtx_EQ (DImode, areg,
@@ -2756,13 +4030,17 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
 #if HOST_BITS_PER_WIDE_INT == 32
   rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
 #else
-  rtx const im1 = immed_double_const (0xffffffffffffffff, 0, DImode);
+  rtx const im1 = constm1_rtx;
 #endif
   rtx ins_tmps[MAX_MOVE_WORDS];
   rtx st_tmp_1, st_tmp_2, dreg;
-  rtx st_addr_1, st_addr_2;
+  rtx st_addr_1, st_addr_2, dmema;
   HOST_WIDE_INT i;
 
+  dmema = XEXP (dmem, 0);
+  if (GET_CODE (dmema) == LO_SUM)
+    dmema = force_reg (Pmode, dmema);
+
   /* Generate all the tmp registers we need.  */
   if (data_regs != NULL)
     for (i = 0; i < words; ++i)
@@ -2771,35 +4049,40 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
   st_tmp_2 = gen_reg_rtx(DImode);
   
   if (ofs != 0)
-    dmem = change_address (dmem, GET_MODE (dmem),
-                          plus_constant (XEXP (dmem, 0), ofs));
-  
+    dmem = adjust_address (dmem, GET_MODE (dmem), ofs);
 
   st_addr_2 = change_address (dmem, DImode,
                              gen_rtx_AND (DImode,
-                                          plus_constant (XEXP(dmem,0),
-                                                         words*8 - 1),
+                                          plus_constant (dmema, words*8 - 1),
                                       im8));
-  MEM_ALIAS_SET (st_addr_2) = 0;
+  set_mem_alias_set (st_addr_2, 0);
 
   st_addr_1 = change_address (dmem, DImode,
-                             gen_rtx_AND (DImode, 
-                                          XEXP (dmem, 0),
-                                          im8));
-  MEM_ALIAS_SET (st_addr_1) = 0;
+                             gen_rtx_AND (DImode, dmema, im8));
+  set_mem_alias_set (st_addr_1, 0);
 
   /* Load up the destination end bits.  */
   emit_move_insn (st_tmp_2, st_addr_2);
   emit_move_insn (st_tmp_1, st_addr_1);
 
   /* Shift the input data into place.  */
-  dreg = copy_addr_to_reg (XEXP (dmem, 0));
+  dreg = copy_addr_to_reg (dmema);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (dreg, plus_constant (dreg, 7));
   if (data_regs != NULL)
     {
       for (i = words-1; i >= 0; --i)
        {
-         emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg));
-         emit_insn (gen_insql (data_regs[i], data_regs[i], dreg));
+         if (WORDS_BIG_ENDIAN)
+           {
+             emit_insn (gen_insql_be (ins_tmps[i], data_regs[i], dreg));
+             emit_insn (gen_insxh (data_regs[i], data_regs[i], i64, dreg));
+           }
+         else
+           {
+             emit_insn (gen_insxh (ins_tmps[i], data_regs[i], i64, dreg));
+             emit_insn (gen_insql_le (data_regs[i], data_regs[i], dreg));
+           }
        }
       for (i = words-1; i > 0; --i)
        {
@@ -2810,8 +4093,16 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
     }
 
   /* Split and merge the ends with the destination data.  */
-  emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg));
-  emit_insn (gen_mskxl (st_tmp_1, st_tmp_1, im1, dreg));
+  if (WORDS_BIG_ENDIAN)
+    {
+      emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, im1, dreg));
+      emit_insn (gen_mskxh (st_tmp_1, st_tmp_1, i64, dreg));
+    }
+  else
+    {
+      emit_insn (gen_mskxh (st_tmp_2, st_tmp_2, i64, dreg));
+      emit_insn (gen_mskxl_le (st_tmp_1, st_tmp_1, im1, dreg));
+    }
 
   if (data_regs != NULL)
     {
@@ -2822,17 +4113,24 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
     }
 
   /* Store it all.  */
-  emit_move_insn (st_addr_2, st_tmp_2);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (st_addr_1, st_tmp_1);
+  else
+    emit_move_insn (st_addr_2, st_tmp_2);
   for (i = words-1; i > 0; --i)
     {
       rtx tmp = change_address (dmem, DImode,
                                gen_rtx_AND (DImode,
-                                            plus_constant(XEXP (dmem,0), i*8),
+                                            plus_constant(dmema,
+                                            WORDS_BIG_ENDIAN ? i*8-1 : i*8),
                                             im8));
-      MEM_ALIAS_SET (tmp) = 0;
+      set_mem_alias_set (tmp, 0);
       emit_move_insn (tmp, data_regs ? ins_tmps[i-1] : const0_rtx);
     }
-  emit_move_insn (st_addr_1, st_tmp_1);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (st_addr_2, st_tmp_2);
+  else
+    emit_move_insn (st_addr_1, st_tmp_1);
 }
 
 
@@ -2857,7 +4155,7 @@ alpha_expand_block_move (operands)
   rtx orig_dst = operands[0];
   rtx data_regs[2 * MAX_MOVE_WORDS + 16];
   rtx tmp;
-  int i, words, ofs, nregs = 0;
+  unsigned int i, words, ofs, nregs = 0;
   
   if (orig_bytes <= 0)
     return 1;
@@ -2925,7 +4223,7 @@ alpha_expand_block_move (operands)
          if (mode == TImode)
            {
              data_regs[nregs] = gen_lowpart (DImode, tmp);
-             data_regs[nregs+1] = gen_highpart (DImode, tmp);
+             data_regs[nregs + 1] = gen_highpart (DImode, tmp);
              nregs += 2;
            }
          else
@@ -2935,8 +4233,8 @@ alpha_expand_block_move (operands)
        }
 
       /* No appropriate mode; fall back on memory.  */
-      orig_src = change_address (orig_src, GET_MODE (orig_src),
-                                copy_addr_to_reg (XEXP (orig_src, 0)));
+      orig_src = replace_equiv_address (orig_src,
+                                       copy_addr_to_reg (XEXP (orig_src, 0)));
       src_align = GET_MODE_BITSIZE (GET_MODE (tmp));
     }
 
@@ -2946,13 +4244,11 @@ alpha_expand_block_move (operands)
       words = bytes / 8;
 
       for (i = 0; i < words; ++i)
-       data_regs[nregs + i] = gen_reg_rtx(DImode);
+       data_regs[nregs + i] = gen_reg_rtx (DImode);
 
       for (i = 0; i < words; ++i)
        emit_move_insn (data_regs[nregs + i],
-                       change_address (orig_src, DImode,
-                                       plus_constant (XEXP (orig_src, 0), 
-                                                      ofs + i * 8)));
+                       adjust_address (orig_src, DImode, ofs + i * 8));
 
       nregs += words;
       bytes -= words * 8;
@@ -2964,13 +4260,11 @@ alpha_expand_block_move (operands)
       words = bytes / 4;
 
       for (i = 0; i < words; ++i)
-       data_regs[nregs + i] = gen_reg_rtx(SImode);
+       data_regs[nregs + i] = gen_reg_rtx (SImode);
 
       for (i = 0; i < words; ++i)
        emit_move_insn (data_regs[nregs + i],
-                       change_address (orig_src, SImode,
-                                       plus_constant (XEXP (orig_src, 0),
-                                                      ofs + i * 4)));
+                       adjust_address (orig_src, SImode, ofs + i * 4));
 
       nregs += words;
       bytes -= words * 4;
@@ -2982,7 +4276,7 @@ alpha_expand_block_move (operands)
       words = bytes / 8;
 
       for (i = 0; i < words+1; ++i)
-       data_regs[nregs + i] = gen_reg_rtx(DImode);
+       data_regs[nregs + i] = gen_reg_rtx (DImode);
 
       alpha_expand_unaligned_load_words (data_regs + nregs, orig_src,
                                         words, ofs);
@@ -3006,10 +4300,7 @@ alpha_expand_block_move (operands)
        {
          do {
            data_regs[nregs++] = tmp = gen_reg_rtx (HImode);
-           emit_move_insn (tmp,
-                           change_address (orig_src, HImode,
-                                           plus_constant (XEXP (orig_src, 0),
-                                                          ofs)));
+           emit_move_insn (tmp, adjust_address (orig_src, HImode, ofs));
            bytes -= 2;
            ofs += 2;
          } while (bytes >= 2);
@@ -3026,10 +4317,7 @@ alpha_expand_block_move (operands)
   while (bytes > 0)
     {
       data_regs[nregs++] = tmp = gen_reg_rtx (QImode);
-      emit_move_insn (tmp,
-                     change_address (orig_src, QImode,
-                                     plus_constant (XEXP (orig_src, 0),
-                                                    ofs)));
+      emit_move_insn (tmp, adjust_address (orig_src, QImode, ofs));
       bytes -= 1;
       ofs += 1;
     }
@@ -3089,8 +4377,8 @@ alpha_expand_block_move (operands)
 
       /* No appropriate mode; fall back on memory.  We can speed things
         up by recognizing extra alignment information.  */
-      orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
-                                copy_addr_to_reg (XEXP (orig_dst, 0)));
+      orig_dst = replace_equiv_address (orig_dst,
+                                       copy_addr_to_reg (XEXP (orig_dst, 0)));
       dst_align = GET_MODE_BITSIZE (GET_MODE (tmp));
     }
 
@@ -3099,9 +4387,7 @@ alpha_expand_block_move (operands)
     {
       while (i < nregs && GET_MODE (data_regs[i]) == DImode)
        {
-         emit_move_insn (change_address (orig_dst, DImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs)),
+         emit_move_insn (adjust_address (orig_dst, DImode, ofs),
                          data_regs[i]);
          ofs += 8;
          i++;
@@ -3117,13 +4403,9 @@ alpha_expand_block_move (operands)
          tmp = expand_binop (DImode, lshr_optab, data_regs[i], GEN_INT (32),
                              NULL_RTX, 1, OPTAB_WIDEN);
 
-         emit_move_insn (change_address (orig_dst, SImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs)),
+         emit_move_insn (adjust_address (orig_dst, SImode, ofs),
                          gen_lowpart (SImode, data_regs[i]));
-         emit_move_insn (change_address (orig_dst, SImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs + 4)),
+         emit_move_insn (adjust_address (orig_dst, SImode, ofs + 4),
                          gen_lowpart (SImode, tmp));
          ofs += 8;
          i++;
@@ -3131,9 +4413,7 @@ alpha_expand_block_move (operands)
 
       while (i < nregs && GET_MODE (data_regs[i]) == SImode)
        {
-         emit_move_insn (change_address(orig_dst, SImode,
-                                        plus_constant (XEXP (orig_dst, 0),
-                                                       ofs)),
+         emit_move_insn (adjust_address (orig_dst, SImode, ofs),
                          data_regs[i]);
          ofs += 4;
          i++;
@@ -3171,10 +4451,7 @@ alpha_expand_block_move (operands)
   if (dst_align >= 16)
     while (i < nregs && GET_MODE (data_regs[i]) == HImode)
       {
-       emit_move_insn (change_address (orig_dst, HImode,
-                                       plus_constant (XEXP (orig_dst, 0),
-                                                      ofs)),
-                       data_regs[i]);
+       emit_move_insn (adjust_address (orig_dst, HImode, ofs), data_regs[i]);
        i++;
        ofs += 2;
       }
@@ -3188,10 +4465,7 @@ alpha_expand_block_move (operands)
 
   while (i < nregs && GET_MODE (data_regs[i]) == QImode)
     {
-      emit_move_insn (change_address (orig_dst, QImode,
-                                     plus_constant (XEXP (orig_dst, 0),
-                                                    ofs)),
-                     data_regs[i]);
+      emit_move_insn (adjust_address (orig_dst, QImode, ofs), data_regs[i]);
       i++;
       ofs += 1;
     }
@@ -3256,8 +4530,7 @@ alpha_expand_block_clear (operands)
        }
 
       /* No appropriate mode; fall back on memory.  */
-      orig_dst = change_address (orig_dst, GET_MODE (orig_dst),
-                                copy_addr_to_reg (tmp));
+      orig_dst = replace_equiv_address (orig_dst, copy_addr_to_reg (tmp));
       align = GET_MODE_BITSIZE (GET_MODE (XEXP (tmp, 0)));
     }
 
@@ -3278,10 +4551,8 @@ alpha_expand_block_clear (operands)
          rtx mem, tmp;
          HOST_WIDE_INT mask;
 
-         mem = change_address (orig_dst, mode,
-                               plus_constant (XEXP (orig_dst, 0),
-                                              ofs - inv_alignofs));
-         MEM_ALIAS_SET (mem) = 0;
+         mem = adjust_address (orig_dst, mode, ofs - inv_alignofs);
+         set_mem_alias_set (mem, 0);
 
          mask = ~(~(HOST_WIDE_INT)0 << (inv_alignofs * 8));
          if (bytes < alignofs)
@@ -3306,30 +4577,21 @@ alpha_expand_block_clear (operands)
 
       if (TARGET_BWX && (alignofs & 1) && bytes >= 1)
        {
-         emit_move_insn (change_address (orig_dst, QImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs)),
-                         const0_rtx);
+         emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx);
          bytes -= 1;
          ofs += 1;
          alignofs -= 1;
        }
       if (TARGET_BWX && align >= 16 && (alignofs & 3) == 2 && bytes >= 2)
        {
-         emit_move_insn (change_address (orig_dst, HImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs)),
-                         const0_rtx);
+         emit_move_insn (adjust_address (orig_dst, HImode, ofs), const0_rtx);
          bytes -= 2;
          ofs += 2;
          alignofs -= 2;
        }
       if (alignofs == 4 && bytes >= 4)
        {
-         emit_move_insn (change_address (orig_dst, SImode,
-                                         plus_constant (XEXP (orig_dst, 0),
-                                                        ofs)),
-                         const0_rtx);
+         emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx);
          bytes -= 4;
          ofs += 4;
          alignofs = 0;
@@ -3351,10 +4613,8 @@ alpha_expand_block_clear (operands)
       words = bytes / 8;
 
       for (i = 0; i < words; ++i)
-       emit_move_insn (change_address(orig_dst, DImode,
-                                      plus_constant (XEXP (orig_dst, 0),
-                                                     ofs + i * 8)),
-                         const0_rtx);
+       emit_move_insn (adjust_address (orig_dst, DImode, ofs + i * 8),
+                       const0_rtx);
 
       bytes -= words * 8;
       ofs += words * 8;
@@ -3365,22 +4625,25 @@ alpha_expand_block_clear (operands)
 
   if (align >= 32 && bytes > 16)
     {
-      emit_move_insn (change_address (orig_dst, SImode,
-                                     plus_constant (XEXP (orig_dst, 0), ofs)),
-                     const0_rtx);
+      rtx orig_dsta;
+
+      emit_move_insn (adjust_address (orig_dst, SImode, ofs), const0_rtx);
       bytes -= 4;
       ofs += 4;
 
+      orig_dsta = XEXP (orig_dst, 0);
+      if (GET_CODE (orig_dsta) == LO_SUM)
+       orig_dsta = force_reg (Pmode, orig_dsta);
+
       words = bytes / 8;
       for (i = 0; i < words; ++i)
        {
-         rtx mem;
-         mem = change_address (orig_dst, DImode,
-                               gen_rtx_AND (DImode,
-                                            plus_constant (XEXP (orig_dst, 0),
-                                                           ofs + i*8),
-                                            GEN_INT (-8)));
-         MEM_ALIAS_SET (mem) = 0;
+         rtx mem
+           = change_address (orig_dst, DImode,
+                             gen_rtx_AND (DImode,
+                                          plus_constant (orig_dsta, ofs + i*8),
+                                          GEN_INT (-8)));
+         set_mem_alias_set (mem, 0);
          emit_move_insn (mem, const0_rtx);
        }
 
@@ -3400,9 +4663,7 @@ alpha_expand_block_clear (operands)
       words = bytes / 4;
 
       for (i = 0; i < words; ++i)
-       emit_move_insn (change_address (orig_dst, SImode,
-                                       plus_constant (XEXP (orig_dst, 0),
-                                                      ofs + i * 4)),
+       emit_move_insn (adjust_address (orig_dst, SImode, ofs + i * 4),
                        const0_rtx);
 
       bytes -= words * 4;
@@ -3440,9 +4701,8 @@ alpha_expand_block_clear (operands)
          rtx mem, tmp;
          HOST_WIDE_INT mask;
 
-         mem = change_address (orig_dst, DImode,
-                               plus_constant (XEXP (orig_dst, 0), ofs));
-         MEM_ALIAS_SET (mem) = 0;
+         mem = adjust_address (orig_dst, DImode, ofs);
+         set_mem_alias_set (mem, 0);
 
          mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
 
@@ -3457,9 +4717,8 @@ alpha_expand_block_clear (operands)
          rtx mem, tmp;
          HOST_WIDE_INT mask;
 
-         mem = change_address (orig_dst, SImode,
-                               plus_constant (XEXP (orig_dst, 0), ofs));
-         MEM_ALIAS_SET (mem) = 0;
+         mem = adjust_address (orig_dst, SImode, ofs);
+         set_mem_alias_set (mem, 0);
 
          mask = ~(HOST_WIDE_INT)0 << (bytes * 8);
 
@@ -3484,9 +4743,7 @@ alpha_expand_block_clear (operands)
       if (align >= 16)
        {
          do {
-           emit_move_insn (change_address (orig_dst, HImode,
-                                           plus_constant (XEXP (orig_dst, 0),
-                                                          ofs)),
+           emit_move_insn (adjust_address (orig_dst, HImode, ofs),
                            const0_rtx);
            bytes -= 2;
            ofs += 2;
@@ -3502,10 +4759,7 @@ alpha_expand_block_clear (operands)
 
   while (bytes > 0)
     {
-      emit_move_insn (change_address (orig_dst, QImode,
-                                     plus_constant (XEXP (orig_dst, 0),
-                                                    ofs)),
-                     const0_rtx);
+      emit_move_insn (adjust_address (orig_dst, QImode, ofs), const0_rtx);
       bytes -= 1;
       ofs += 1;
     }
@@ -3516,7 +4770,7 @@ alpha_expand_block_clear (operands)
 /* 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.  */
 
-int
+static int
 alpha_adjust_cost (insn, link, dep_insn, cost)
      rtx insn;
      rtx link;
@@ -3657,10 +4911,70 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
       break;
     }
 
-  /* Otherwise, return the default cost. */
+  /* Otherwise, return the default cost.  */
   return cost;
 }
+
+/* Function to initialize the issue rate used by the scheduler.  */
+static int
+alpha_issue_rate ()
+{
+  return (alpha_cpu == PROCESSOR_EV4 ? 2 : 4);
+}
+
+static int
+alpha_variable_issue (dump, verbose, insn, cim)
+     FILE *dump ATTRIBUTE_UNUSED;
+     int verbose ATTRIBUTE_UNUSED;
+     rtx insn;
+     int cim;
+{
+    if (recog_memoized (insn) < 0 || get_attr_type (insn) == TYPE_MULTI)
+      return 0;
+
+    return cim - 1;
+}
+
 \f
+/* Register global variables and machine-specific functions with the
+   garbage collector.  */
+
+#if TARGET_ABI_UNICOSMK
+static void
+alpha_init_machine_status (p)
+     struct function *p;
+{
+  p->machine =
+    (struct machine_function *) xcalloc (1, sizeof (struct machine_function));
+
+  p->machine->first_ciw = NULL_RTX;
+  p->machine->last_ciw = NULL_RTX;
+  p->machine->ciw_count = 0;
+  p->machine->addr_list = NULL_RTX;
+}
+
+static void
+alpha_mark_machine_status (p)
+     struct function *p;
+{
+  struct machine_function *machine = p->machine;
+
+  if (machine)
+    {
+      ggc_mark_rtx (machine->first_ciw);
+      ggc_mark_rtx (machine->addr_list);
+    }
+}
+
+static void
+alpha_free_machine_status (p)
+     struct function *p;
+{
+  free (p->machine);
+  p->machine = NULL;
+}
+#endif /* TARGET_ABI_UNICOSMK */
+
 /* Functions to save and restore alpha_return_addr_rtx.  */
 
 /* Start the ball rolling with RETURN_ADDR_RTX.  */
@@ -3690,10 +5004,6 @@ alpha_ra_ever_killed ()
 {
   rtx top;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
-    return 0;
-#endif
   if (!has_hard_reg_initial_val (Pmode, REG_RA))
     return regs_ever_live[REG_RA];
 
@@ -3705,132 +5015,170 @@ alpha_ra_ever_killed ()
 }
 
 \f
-/* Print an operand.  Recognize special options, documented below.  */
+/* Return the trap mode suffix applicable to the current
+   instruction, or NULL.  */
 
-void
-print_operand (file, x, code)
-    FILE *file;
-    rtx x;
-    int code;
+static const char *
+get_trap_mode_suffix ()
 {
-  int i;
+  enum attr_trap_suffix s = get_attr_trap_suffix (current_output_insn);
 
-  switch (code)
+  switch (s)
     {
-    case '~':
-      /* Print the assembler name of the current function.  */
-      assemble_name (file, alpha_fnname);
-      break;
-
-    case '&':
-      /* Generates fp-rounding mode suffix: nothing for normal, 'c' for
-        chopped, 'm' for minus-infinity, and 'd' for dynamic rounding
-        mode.  alpha_fprm controls which suffix is generated.  */
-      switch (alpha_fprm)
-       {
-       case ALPHA_FPRM_NORM:
-         break;
-       case ALPHA_FPRM_MINF: 
-         fputc ('m', file);
-         break;
-       case ALPHA_FPRM_CHOP:
-         fputc ('c', file);
-         break;
-       case ALPHA_FPRM_DYN:
-         fputc ('d', file);
-         break;
-       default:
-         abort ();
-       }
-      break;
+    case TRAP_SUFFIX_NONE:
+      return NULL;
 
-    case '\'':
-      /* Generates trap-mode suffix for instructions that accept the su
-        suffix only (cmpt et al).  */
+    case TRAP_SUFFIX_SU:
       if (alpha_fptm >= ALPHA_FPTM_SU)
-       fputs ("su", file);
-      break;
+       return "su";
+      return NULL;
+
+    case TRAP_SUFFIX_SUI:
+      if (alpha_fptm >= ALPHA_FPTM_SUI)
+       return "sui";
+      return NULL;
 
-    case '`':
-      /* Generates trap-mode suffix for instructions that accept the
-        v and sv suffix.  The only instruction that needs this is cvtql.  */
+    case TRAP_SUFFIX_V_SV:
       switch (alpha_fptm)
        {
        case ALPHA_FPTM_N:
-         break;
+         return NULL;
        case ALPHA_FPTM_U:
-         fputs ("v", file);
-         break;
+         return "v";
        case ALPHA_FPTM_SU:
        case ALPHA_FPTM_SUI:
-         fputs ("sv", file);
-         break;
+         return "sv";
        }
       break;
 
-    case '(':
-      /* Generates trap-mode suffix for instructions that accept the
-        v, sv, and svi suffix.  The only instruction that needs this
-        is cvttq.  */
+    case TRAP_SUFFIX_V_SV_SVI:
       switch (alpha_fptm)
        {
        case ALPHA_FPTM_N:
-         break;
+         return NULL;
        case ALPHA_FPTM_U:
-         fputs ("v", file);
-         break;
+         return "v";
        case ALPHA_FPTM_SU:
-         fputs ("sv", file);
-         break;
+         return "sv";
        case ALPHA_FPTM_SUI:
-         fputs ("svi", file);
-         break;
+         return "svi";
        }
       break;
 
-    case ')':
-      /* Generates trap-mode suffix for instructions that accept the u, su,
-        and sui suffix.  This is the bulk of the IEEE floating point
-        instructions (addt et al).  */
+    case TRAP_SUFFIX_U_SU_SUI:
       switch (alpha_fptm)
        {
        case ALPHA_FPTM_N:
-         break;
+         return NULL;
        case ALPHA_FPTM_U:
-         fputc ('u', file);
-         break;
+         return "u";
        case ALPHA_FPTM_SU:
-         fputs ("su", file);
-         break;
+         return "su";
        case ALPHA_FPTM_SUI:
-         fputs ("sui", file);
-         break;
+         return "sui";
        }
       break;
+    }
+  abort ();
+}
 
-    case '+':
-      /* Generates trap-mode suffix for instructions that accept the sui
-        suffix (cvtqt and cvtqs).  */
-      switch (alpha_fptm)
+/* Return the rounding mode suffix applicable to the current
+   instruction, or NULL.  */
+
+static const char *
+get_round_mode_suffix ()
+{
+  enum attr_round_suffix s = get_attr_round_suffix (current_output_insn);
+
+  switch (s)
+    {
+    case ROUND_SUFFIX_NONE:
+      return NULL;
+    case ROUND_SUFFIX_NORMAL:
+      switch (alpha_fprm)
        {
-       case ALPHA_FPTM_N:
-       case ALPHA_FPTM_U:
-       case ALPHA_FPTM_SU:     /* cvtqt/cvtqs can't cause underflow */
-         break;
-       case ALPHA_FPTM_SUI:
-         fputs ("sui", file);
-         break;
+       case ALPHA_FPRM_NORM:
+         return NULL;
+       case ALPHA_FPRM_MINF: 
+         return "m";
+       case ALPHA_FPRM_CHOP:
+         return "c";
+       case ALPHA_FPRM_DYN:
+         return "d";
        }
       break;
 
+    case ROUND_SUFFIX_C:
+      return "c";
+    }
+  abort ();
+}
+
+/* Print an operand.  Recognize special options, documented below.  */
+
+void
+print_operand (file, x, code)
+    FILE *file;
+    rtx x;
+    int code;
+{
+  int i;
+
+  switch (code)
+    {
+    case '~':
+      /* Print the assembler name of the current function.  */
+      assemble_name (file, alpha_fnname);
+      break;
+
+    case '/':
+      {
+       const char *trap = get_trap_mode_suffix ();
+       const char *round = get_round_mode_suffix ();
+
+       if (trap || round)
+         fprintf (file, (TARGET_AS_SLASH_BEFORE_SUFFIX ? "/%s%s" : "%s%s"),
+                  (trap ? trap : ""), (round ? round : ""));
+       break;
+      }
+
     case ',':
       /* Generates single precision instruction suffix.  */
-      fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'f' : 's'));
+      fputc ((TARGET_FLOAT_VAX ? 'f' : 's'), file);
       break;
 
     case '-':
       /* Generates double precision instruction suffix.  */
-      fprintf (file, "%c", (TARGET_FLOAT_VAX ? 'g' : 't'));
+      fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file);
+      break;
+
+    case '#':
+      if (alpha_this_literal_sequence_number == 0)
+       alpha_this_literal_sequence_number = alpha_next_sequence_number++;
+      fprintf (file, "%d", alpha_this_literal_sequence_number);
+      break;
+
+    case '*':
+      if (alpha_this_gpdisp_sequence_number == 0)
+       alpha_this_gpdisp_sequence_number = alpha_next_sequence_number++;
+      fprintf (file, "%d", alpha_this_gpdisp_sequence_number);
+      break;
+
+    case 'H':
+      if (GET_CODE (x) == HIGH)
+       output_addr_const (file, XEXP (x, 0));
+      else
+       output_operand_lossage ("invalid %%H value");
+      break;
+
+    case 'J':
+      if (GET_CODE (x) == CONST_INT)
+       {
+         if (INTVAL (x) != 0)
+           fprintf (file, "\t\t!lituse_jsr!%d", (int) INTVAL (x));
+       }
+      else
+       output_operand_lossage ("invalid %%J value");
       break;
 
     case 'r':
@@ -3841,7 +5189,6 @@ print_operand (file, x, code)
        fprintf (file, "$31");
       else
        output_operand_lossage ("invalid %%r value");
-
       break;
 
     case 'R':
@@ -3852,7 +5199,6 @@ print_operand (file, x, code)
        fprintf (file, "$f31");
       else
        output_operand_lossage ("invalid %%R value");
-
       break;
 
     case 'N':
@@ -3968,13 +5314,20 @@ print_operand (file, x, code)
       break;
 
     case 's':
-      /* Write the constant value divided by 8.  */
+      /* Write the constant value divided by 8 for little-endian mode or
+        (56 - value) / 8 for big-endian mode.  */
+
       if (GET_CODE (x) != CONST_INT
-         && (unsigned HOST_WIDE_INT) INTVAL (x) >= 64
-         && (INTVAL (x) & 7) != 8)
+         || (unsigned HOST_WIDE_INT) INTVAL (x) >= (WORDS_BIG_ENDIAN
+                                                    ? 56
+                                                    : 64)  
+         || (INTVAL (x) & 7) != 0)
        output_operand_lossage ("invalid %%s value");
 
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) / 8);
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC,
+              WORDS_BIG_ENDIAN
+              ? (56 - INTVAL (x)) / 8
+              : INTVAL (x) / 8);
       break;
 
     case 'S':
@@ -3988,6 +5341,18 @@ print_operand (file, x, code)
       fprintf (file, HOST_WIDE_INT_PRINT_DEC, (64 - INTVAL (x)) / 8);
       break;
 
+    case 't':
+      {
+        /* On Unicos/Mk systems: use a DEX expression if the symbol
+          clashes with a register name.  */
+       int dex = unicosmk_need_dex (x);
+       if (dex)
+         fprintf (file, "DEX(%d)", dex);
+       else
+         output_addr_const (file, x);
+      }
+      break;
+
     case 'C': case 'D': case 'c': case 'd':
       /* Write out comparison name.  */
       {
@@ -4073,12 +5438,35 @@ print_operand_address (file, addr)
       offset = INTVAL (XEXP (addr, 1));
       addr = XEXP (addr, 0);
     }
+
+  if (GET_CODE (addr) == LO_SUM)
+    {
+      output_addr_const (file, XEXP (addr, 1));
+      if (offset)
+       {
+         fputc ('+', file);
+         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 ();
+
+      fprintf (file, "($%d)\t\t!%s", basereg,
+              (basereg == 29 ? "gprel" : "gprellow"));
+      return;
+    }
+
   if (GET_CODE (addr) == REG)
     basereg = REGNO (addr);
   else if (GET_CODE (addr) == SUBREG
           && GET_CODE (SUBREG_REG (addr)) == REG)
-    basereg = REGNO (SUBREG_REG (addr))
-             + SUBREG_BYTE (addr) / GET_MODE_SIZE (GET_MODE (addr));
+    basereg = subreg_regno (addr);
   else if (GET_CODE (addr) == CONST_INT)
     offset = INTVAL (addr);
   else
@@ -4108,7 +5496,7 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
 {
   rtx temp, temp1, addr;
   /* VMS really uses DImode pointers in memory at this point.  */
-  enum machine_mode mode = TARGET_OPEN_VMS ? Pmode : ptr_mode;
+  enum machine_mode mode = TARGET_ABI_OPEN_VMS ? Pmode : ptr_mode;
 
 #ifdef POINTERS_EXTEND_UNSIGNED
   fnaddr = convert_memory_address (mode, fnaddr);
@@ -4122,7 +5510,7 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
   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. */
+     no existing OS is the stack within 32k of the text segment.  */
   if (0 && jmpofs >= 0)
     {
       /* Compute hint value.  */
@@ -4131,12 +5519,13 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
                           OPTAB_WIDEN);
       temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
                           build_int_2 (2, 0), NULL_RTX, 1);
-      temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
+      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 (temp1, GEN_INT (0xffffc000), NULL_RTX);
+      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);
@@ -4177,33 +5566,108 @@ function_arg (cum, mode, type, named)
   int basereg;
   int num_args;
 
-#ifndef OPEN_VMS
-  if (cum >= 6)
-    return NULL_RTX;
-  num_args = cum;
-
-  /* VOID is passed as a special flag for "last argument".  */
-  if (type == void_type_node)
-    basereg = 16;
-  else if (MUST_PASS_IN_STACK (mode, type))
-    return NULL_RTX;
-  else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named))
-    basereg = 16;
-#else
-  if (mode == VOIDmode)
-    return alpha_arg_info_reg_val (cum);
-
-  num_args = cum.num_args;
-  if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type))
-    return NULL_RTX;
-#endif /* OPEN_VMS */
-  else if (TARGET_FPREGS
-          && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-              || GET_MODE_CLASS (mode) == MODE_FLOAT))
+  /* Set up defaults for FP operands passed in FP registers, and
+     integral operands passed in integer registers.  */
+  if (TARGET_FPREGS
+      && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
+         || GET_MODE_CLASS (mode) == MODE_FLOAT))
     basereg = 32 + 16;
   else
     basereg = 16;
 
+  /* ??? Irritatingly, the definition of CUMULATIVE_ARGS is different for
+     the three platforms, so we can't avoid conditional compilation.  */
+#if TARGET_ABI_OPEN_VMS
+    {
+      if (mode == VOIDmode)
+       return alpha_arg_info_reg_val (cum);
+
+      num_args = cum.num_args;
+      if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type))
+       return NULL_RTX;
+    }
+#else
+#if TARGET_ABI_UNICOSMK
+    {
+      int size;
+
+      /* If this is the last argument, generate the call info word (CIW).  */
+      /* ??? We don't include the caller's line number in the CIW because
+        I don't know how to determine it if debug infos are turned off.  */
+      if (mode == VOIDmode)
+       {
+         int i;
+         HOST_WIDE_INT lo;
+         HOST_WIDE_INT hi;
+         rtx ciw;
+
+         lo = 0;
+
+         for (i = 0; i < cum.num_reg_words && i < 5; i++)
+           if (cum.reg_args_type[i])
+             lo |= (1 << (7 - i));
+
+         if (cum.num_reg_words == 6 && cum.reg_args_type[5])
+           lo |= 7;
+         else
+           lo |= cum.num_reg_words;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+         hi = (cum.num_args << 20) | cum.num_arg_words;
+#else
+         lo = lo | ((HOST_WIDE_INT) cum.num_args << 52)
+           | ((HOST_WIDE_INT) cum.num_arg_words << 32);
+         hi = 0;
+#endif
+         ciw = immed_double_const (lo, hi, DImode);
+
+         return gen_rtx_UNSPEC (DImode, gen_rtvec (1, ciw),
+                                UNSPEC_UMK_LOAD_CIW);
+       }
+
+      size = ALPHA_ARG_SIZE (mode, type, named);
+      num_args = cum.num_reg_words;
+      if (MUST_PASS_IN_STACK (mode, type)
+         || cum.num_reg_words + size > 6 || cum.force_stack)
+       return NULL_RTX;
+      else if (type && TYPE_MODE (type) == BLKmode)
+       {
+         rtx reg1, reg2;
+
+         reg1 = gen_rtx_REG (DImode, num_args + 16);
+         reg1 = gen_rtx_EXPR_LIST (DImode, reg1, const0_rtx);
+
+         /* The argument fits in two registers. Note that we still need to
+            reserve a register for empty structures.  */
+         if (size == 0)
+           return NULL_RTX;
+         else if (size == 1)
+           return gen_rtx_PARALLEL (mode, gen_rtvec (1, reg1));
+         else
+           {
+             reg2 = gen_rtx_REG (DImode, num_args + 17);
+             reg2 = gen_rtx_EXPR_LIST (DImode, reg2, GEN_INT (8));
+             return gen_rtx_PARALLEL (mode, gen_rtvec (2, reg1, reg2));
+           }
+       }
+    }
+#else
+    {
+      if (cum >= 6)
+       return NULL_RTX;
+      num_args = cum;
+
+      /* VOID is passed as a special flag for "last argument".  */
+      if (type == void_type_node)
+       basereg = 16;
+      else if (MUST_PASS_IN_STACK (mode, type))
+       return NULL_RTX;
+      else if (FUNCTION_ARG_PASS_BY_REFERENCE (cum, mode, type, named))
+       basereg = 16;
+    }
+#endif /* TARGET_ABI_UNICOSMK */
+#endif /* TARGET_ABI_OPEN_VMS */
+
   return gen_rtx_REG (mode, num_args + basereg);
 }
 
@@ -4212,7 +5676,7 @@ alpha_build_va_list ()
 {
   tree base, ofs, record, type_decl;
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
     return ptr_type_node;
 
   record = make_lang_type (RECORD_TYPE);
@@ -4249,7 +5713,7 @@ alpha_va_start (stdarg_p, valist, nextarg)
   if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK)
     return;
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
     std_expand_builtin_va_start (stdarg_p, valist, nextarg);
 
   /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base
@@ -4262,28 +5726,41 @@ alpha_va_start (stdarg_p, valist, nextarg)
      in argsize above, but which are not actually stored on the stack.  */
 
   if (NUM_ARGS <= 5 + stdarg_p)
-    offset = 6 * UNITS_PER_WORD;
+    offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD;
   else
     offset = -6 * UNITS_PER_WORD;
 
-  base_field = TYPE_FIELDS (TREE_TYPE (valist));
-  offset_field = TREE_CHAIN (base_field);
+  if (TARGET_ABI_OPEN_VMS)
+    {
+      nextarg = plus_constant (nextarg, offset);
+      nextarg = plus_constant (nextarg, NUM_ARGS * UNITS_PER_WORD);
+      t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
+                make_tree (ptr_type_node, nextarg));
+      TREE_SIDE_EFFECTS (t) = 1;
 
-  base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
-                     valist, base_field);
-  offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
-                       valist, offset_field);
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
+  else
+    {
+      base_field = TYPE_FIELDS (TREE_TYPE (valist));
+      offset_field = TREE_CHAIN (base_field);
 
-  t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
-  t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
-  t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t);
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      base_field = build (COMPONENT_REF, TREE_TYPE (base_field),
+                         valist, base_field);
+      offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
+                           valist, offset_field);
 
-  t = build_int_2 (NUM_ARGS*UNITS_PER_WORD, 0);
-  t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t);
-  TREE_SIDE_EFFECTS (t) = 1;
-  expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+      t = make_tree (ptr_type_node, virtual_incoming_args_rtx);
+      t = build (PLUS_EXPR, ptr_type_node, t, build_int_2 (offset, 0));
+      t = build (MODIFY_EXPR, TREE_TYPE (base_field), base_field, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+      t = build_int_2 (NUM_ARGS * UNITS_PER_WORD, 0);
+      t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field, t);
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
 }
 
 rtx
@@ -4297,7 +5774,7 @@ alpha_va_arg (valist, type)
   tree wide_type, wide_ofs;
   int indirect = 0;
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
     return std_expand_builtin_va_arg (valist, type);
 
   tsize = ((TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT + 7) / 8) * 8;
@@ -4363,10 +5840,11 @@ alpha_va_arg (valist, type)
 /* These variables are used for communication between the following functions.
    They indicate various things about the current function being compiled
    that are used to tell what kind of prologue, epilogue and procedure
-   descriptior to generate. */
+   descriptior to generate.  */
 
 /* Nonzero if we need a stack procedure.  */
-static int vms_is_stack_procedure;
+enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2};
+static enum alpha_procedure_types alpha_procedure_type;
 
 /* Register number (either FP or SP) that is used to unwind the frame.  */
 static int vms_unwind_regno;
@@ -4388,41 +5866,50 @@ alpha_sa_mask (imaskP, fmaskP)
 {
   unsigned long imask = 0;
   unsigned long fmask = 0;
-  int i;
+  unsigned int i;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (!current_function_is_thunk)
-#endif
+  /* Irritatingly, there are two kinds of thunks -- those created with
+     ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go through
+     the regular part of the compiler.  In the ASM_OUTPUT_MI_THUNK case
+     we don't have valid register life info, but assemble_start_function
+     wants to output .frame and .mask directives.  */
+  if (current_function_is_thunk && !no_new_pseudos)
     {
-      if (TARGET_OPEN_VMS && vms_is_stack_procedure)
-       imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+      *imaskP = 0;
+      *fmaskP = 0;
+      return;
+    }
 
-      /* 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)
-         {
-           if (i < 32)
-             imask |= (1L << i);
-           else
-             fmask |= (1L << (i - 32));
-         }
+  if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+    imask |= (1L << HARD_FRAME_POINTER_REGNUM);
 
-      /* We need to restore these for the handler.  */
-      if (current_function_calls_eh_return)
-       {
-         for (i = 0; ; ++i)
-           {
-             unsigned regno = EH_RETURN_DATA_REGNO (i);
-             if (regno == INVALID_REGNUM)
-               break;
-             imask |= 1L << regno;
-           }
-       }
+  /* 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
+       && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
+      {
+       if (i < 32)
+         imask |= (1L << i);
+       else
+         fmask |= (1L << (i - 32));
+      }
 
-      if (imask || fmask || alpha_ra_ever_killed ())
-       imask |= (1L << REG_RA);
-    }
+  /* We need to restore these for the handler.  */
+  if (current_function_calls_eh_return)
+    for (i = 0; ; ++i)
+      {
+       unsigned regno = EH_RETURN_DATA_REGNO (i);
+       if (regno == INVALID_REGNUM)
+         break;
+       imask |= 1L << regno;
+      }
+     
+  /* If any register spilled, then spill the return address also.  */
+  /* ??? This is required by the Digital stack unwind specification
+     and isn't needed if we're doing Dwarf2 unwinding.  */
+  if (imask || fmask || alpha_ra_ever_killed ())
+    imask |= (1L << REG_RA);
 
   *imaskP = imask;
   *fmaskP = fmask;
@@ -4431,38 +5918,73 @@ alpha_sa_mask (imaskP, fmaskP)
 int
 alpha_sa_size ()
 {
+  unsigned long mask[2];
   int sa_size = 0;
-  int i;
+  int i, j;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
-    sa_size = 0;
+  alpha_sa_mask (&mask[0], &mask[1]);
+
+  if (TARGET_ABI_UNICOSMK)
+    {
+      if (mask[0] || mask[1])
+       sa_size = 14;
+    }
   else
-#endif
     {
-      /* 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)
-         sa_size++;
+      for (j = 0; j < 2; ++j)
+       for (i = 0; i < 32; ++i)
+         if ((mask[j] >> i) & 1)
+           sa_size++;
     }
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
+    {
+      /* We might not need to generate a frame if we don't make any calls
+        (including calls to __T3E_MISMATCH if this is a vararg function),
+        don't have any local variables which require stack slots, don't
+        use alloca and have not determined that we need a frame for other
+        reasons.  */
+
+      alpha_procedure_type
+       = (sa_size || get_frame_size() != 0
+          || current_function_outgoing_args_size || current_function_varargs
+          || current_function_stdarg || current_function_calls_alloca
+          || frame_pointer_needed)
+         ? PT_STACK : PT_REGISTER;
+
+      /* Always reserve space for saving callee-saved registers if we
+        need a frame as required by the calling convention.  */
+      if (alpha_procedure_type == PT_STACK)
+        sa_size = 14;
+    }
+  else if (TARGET_ABI_OPEN_VMS)
     {
       /* Start by assuming we can use a register procedure if we don't
         make any calls (REG_RA not used) or need to save any
         registers and a stack procedure if we do.  */
-      vms_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed ();
+      if ((mask[0] >> REG_RA) & 1)
+       alpha_procedure_type = PT_STACK;
+      else if (get_frame_size() != 0)
+       alpha_procedure_type = PT_REGISTER;
+      else
+       alpha_procedure_type = PT_NULL;
+
+      /* Don't reserve space for saving RA yet.  Do that later after we've
+        made the final decision on stack procedure vs register procedure.  */
+      if (alpha_procedure_type == PT_STACK)
+       sa_size--;
 
       /* Decide whether to refer to objects off our PV via FP or PV.
         If we need FP for something else or if we receive a nonlocal
         goto (which expects PV to contain the value), we must use PV.
         Otherwise, start by assuming we can use FP.  */
-      vms_base_regno = (frame_pointer_needed
-                       || current_function_has_nonlocal_label
-                       || vms_is_stack_procedure
-                       || current_function_outgoing_args_size
-                       ? REG_PV : HARD_FRAME_POINTER_REGNUM);
+
+      vms_base_regno
+       = (frame_pointer_needed
+          || current_function_has_nonlocal_label
+          || alpha_procedure_type == PT_STACK
+          || current_function_outgoing_args_size)
+         ? REG_PV : HARD_FRAME_POINTER_REGNUM;
 
       /* If we want to copy PV into FP, we need to find some register
         in which to save FP.  */
@@ -4473,24 +5995,21 @@ alpha_sa_size ()
          if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
            vms_save_fp_regno = i;
 
-      if (vms_save_fp_regno == -1)
-       vms_base_regno = REG_PV, vms_is_stack_procedure = 1;
+      if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
+       vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK;
+      else if (alpha_procedure_type == PT_NULL)
+       vms_base_regno = REG_PV;
 
       /* Stack unwinding should be done via FP unless we use it for PV.  */
       vms_unwind_regno = (vms_base_regno == REG_PV
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
       /* If this is a stack procedure, allow space for saving FP and RA.  */
-      if (vms_is_stack_procedure)
+      if (alpha_procedure_type == PT_STACK)
        sa_size += 2;
     }
   else
     {
-      /* If some registers were saved but not RA, RA must also be saved,
-        so leave space for it.  */
-      if (sa_size != 0 || alpha_ra_ever_killed ())
-       sa_size++;
-
       /* Our size must be even (multiple of 16 bytes).  */
       if (sa_size & 1)
        sa_size++;
@@ -4503,7 +6022,7 @@ int
 alpha_pv_save_size ()
 {
   alpha_sa_size ();
-  return vms_is_stack_procedure ? 8 : 0;
+  return alpha_procedure_type == PT_STACK ? 8 : 0;
 }
 
 int
@@ -4513,16 +6032,25 @@ alpha_using_fp ()
   return vms_unwind_regno == HARD_FRAME_POINTER_REGNUM;
 }
 
-int
-vms_valid_decl_attribute_p (decl, attributes, identifier, args)
-     tree decl ATTRIBUTE_UNUSED;
-     tree attributes ATTRIBUTE_UNUSED;
-     tree identifier;
-     tree args;
+#if TARGET_ABI_OPEN_VMS
+
+const struct attribute_spec vms_attribute_table[] =
 {
-  if (is_attribute_p ("overlaid", identifier))
-    return (args == NULL_TREE);
-  return 0;
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "overlaid",   0, 0, true,  false, false, NULL },
+  { "global",     0, 0, true,  false, false, NULL },
+  { "initialize", 0, 0, true,  false, false, NULL },
+  { NULL,         0, 0, false, false, false, NULL }
+};
+
+#endif
+
+static int
+find_lo_sum (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  return GET_CODE (*px) == LO_SUM;
 }
 
 static int
@@ -4530,17 +6058,15 @@ alpha_does_function_need_gp ()
 {
   rtx insn;
 
-  /* We never need a GP for Windows/NT or VMS.  */
-  if (TARGET_WINDOWS_NT || TARGET_OPEN_VMS)
+  /* The GP being variable is an OSF abi thing.  */
+  if (! TARGET_ABI_OSF)
     return 0;
 
-  if (TARGET_PROFILING_NEEDS_GP && profile_flag)
+  if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
     return 1;
 
-#ifdef ASM_OUTPUT_MI_THUNK
   if (current_function_is_thunk)
     return 1;
-#endif
 
   /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. 
      Even if we are a static function, we still need to do this in case
@@ -4558,6 +6084,9 @@ alpha_does_function_need_gp ()
        enum attr_type type = get_attr_type (insn);
        if (type == TYPE_LDSYM || type == TYPE_JSR)
          return 1;
+       if (TARGET_EXPLICIT_RELOCS
+           && for_each_rtx (&PATTERN (insn), find_lo_sum, NULL) > 0)
+         return 1;
       }
 
   return 0;
@@ -4640,18 +6169,24 @@ alpha_expand_prologue ()
   sa_size = alpha_sa_size ();
 
   frame_size = get_frame_size ();
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
+  else if (TARGET_ABI_UNICOSMK)
+    /* We have to allocate space for the DSIB if we generate a frame.  */
+    frame_size = ALPHA_ROUND (sa_size
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                               + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
                  + ALPHA_ROUND (frame_size
                                 + current_function_pretend_args_size));
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     reg_offset = 8;
   else
     reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
@@ -4659,7 +6194,7 @@ alpha_expand_prologue ()
   alpha_sa_mask (&imask, &fmask);
 
   /* Emit an insn to reload GP, if needed.  */
-  if (!TARGET_OPEN_VMS && !TARGET_WINDOWS_NT)
+  if (TARGET_ABI_OSF)
     {
       alpha_function_needs_gp = alpha_does_function_need_gp ();
       if (alpha_function_needs_gp)
@@ -4670,9 +6205,12 @@ alpha_expand_prologue ()
      the call to mcount ourselves, rather than having the linker do it
      magically in response to -pg.  Since _mcount has special linkage,
      don't represent the call as a call.  */
-  if (TARGET_PROFILING_NEEDS_GP && profile_flag)
+  if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
     emit_insn (gen_prologue_mcount ());
-      
+
+  if (TARGET_ABI_UNICOSMK)
+    unicosmk_gen_dsib (&imask);
+
   /* Adjust the stack by the frame size.  If the frame size is > 4096
      bytes, we need to be sure we probe somewhere in the first and last
      4096 bytes (we can probably get away without the latter test) and
@@ -4689,7 +6227,9 @@ alpha_expand_prologue ()
          int probed = 4096;
 
          do
-           emit_insn (gen_probe_stack (GEN_INT (-probed)));
+           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.  */
@@ -4699,7 +6239,9 @@ alpha_expand_prologue ()
 
       if (frame_size != 0)
        FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
-                                   GEN_INT (-frame_size))));
+                                   GEN_INT (TARGET_ABI_UNICOSMK
+                                            ? -frame_size + 64
+                                            : -frame_size))));
     }
   else
     {
@@ -4716,7 +6258,8 @@ alpha_expand_prologue ()
       rtx seq;
 
       emit_move_insn (count, GEN_INT (blocks));
-      emit_insn (gen_adddi3 (ptr, stack_pointer_rtx, GEN_INT (4096)));
+      emit_insn (gen_adddi3 (ptr, stack_pointer_rtx,
+                            GEN_INT (TARGET_ABI_UNICOSMK ? 4096 - 64 : 4096)));
 
       /* Because of the difficulty in emitting a new basic block this
         late in the compilation, generate the loop as a single insn.  */
@@ -4729,7 +6272,7 @@ alpha_expand_prologue ()
          emit_move_insn (last, const0_rtx);
        }
 
-      if (TARGET_WINDOWS_NT)
+      if (TARGET_ABI_WINDOWS_NT)
        {
          /* For NT stack unwind (done by 'reverse execution'), it's
             not OK to take the result of a loop, even though the value
@@ -4763,75 +6306,109 @@ alpha_expand_prologue ()
         = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
                             gen_rtx_SET (VOIDmode, stack_pointer_rtx,
                               gen_rtx_PLUS (Pmode, stack_pointer_rtx,
-                                            GEN_INT (-frame_size))),
+                                            GEN_INT (TARGET_ABI_UNICOSMK
+                                                     ? -frame_size + 64
+                                                     : -frame_size))),
                             REG_NOTES (seq));
     }
 
-  /* Cope with very large offsets to the register save area.  */
-  sa_reg = stack_pointer_rtx;
-  if (reg_offset + sa_size > 0x8000)
+  if (!TARGET_ABI_UNICOSMK)
     {
-      int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
-      HOST_WIDE_INT bias;
+      /* Cope with very large offsets to the register save area.  */
+      sa_reg = stack_pointer_rtx;
+      if (reg_offset + sa_size > 0x8000)
+       {
+         int low = ((reg_offset & 0xffff) ^ 0x8000) - 0x8000;
+         HOST_WIDE_INT bias;
 
-      if (low + sa_size <= 0x8000)
-       bias = reg_offset - low, reg_offset = low;
-      else 
-       bias = reg_offset, reg_offset = 0;
+         if (low + sa_size <= 0x8000)
+           bias = reg_offset - low, reg_offset = low;
+         else 
+           bias = reg_offset, reg_offset = 0;
 
-      sa_reg = gen_rtx_REG (DImode, 24);
-      FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx, GEN_INT (bias))));
-    }
+         sa_reg = gen_rtx_REG (DImode, 24);
+         FRP (emit_insn (gen_adddi3 (sa_reg, stack_pointer_rtx,
+                                     GEN_INT (bias))));
+       }
     
-  /* Save regs in stack order.  Beginning with VMS PV.  */
-  if (TARGET_OPEN_VMS && vms_is_stack_procedure)
-    {
-      mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
-      MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
-    }
+      /* Save regs in stack order.  Beginning with VMS PV.  */
+      if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+       {
+         mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
+         set_mem_alias_set (mem, alpha_sr_alias_set);
+         FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_PV)));
+       }
 
-  /* Save register RA next.  */
-  if (imask & (1L << REG_RA))
-    {
-      mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
-      MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
-      imask &= ~(1L << REG_RA);
-      reg_offset += 8;
-    }
+      /* Save register RA next.  */
+      if (imask & (1L << REG_RA))
+       {
+         mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+         set_mem_alias_set (mem, alpha_sr_alias_set);
+         FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
+         imask &= ~(1L << REG_RA);
+         reg_offset += 8;
+       }
 
-  /* Now save any other registers required to be saved.  */
-  for (i = 0; i < 32; i++)
-    if (imask & (1L << i))
-      {
-       mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
-       MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-       FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
-       reg_offset += 8;
-      }
+      /* Now save any other registers required to be saved.  */
+      for (i = 0; i < 32; i++)
+       if (imask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+           reg_offset += 8;
+         }
 
-  for (i = 0; i < 32; i++)
-    if (fmask & (1L << i))
-      {
-       mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
-       MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
-       FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
-       reg_offset += 8;
-      }
+      for (i = 0; i < 32; i++)
+       if (fmask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+           reg_offset += 8;
+         }
+    }
+  else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
+    {
+      /* The standard frame on the T3E includes space for saving registers.
+        We just have to use it. We don't have to save the return address and
+        the old frame pointer here - they are saved in the DSIB.  */
+
+      reg_offset = -56;
+      for (i = 9; i < 15; i++)
+       if (imask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
+                                                    reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (mem, gen_rtx_REG (DImode, i)));
+           reg_offset -= 8;
+         }
+      for (i = 2; i < 10; i++)
+       if (fmask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx,
+                                                     reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (mem, gen_rtx_REG (DFmode, i+32)));
+           reg_offset -= 8;
+         }
+    }
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     {
-      if (!vms_is_stack_procedure)
-       /* Register frame procedures fave the fp.  */
-       FRP (emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
-                            hard_frame_pointer_rtx));
+      if (alpha_procedure_type == PT_REGISTER)
+       /* Register frame procedures save the fp.
+          ?? Ought to have a dwarf2 save for this.  */
+       emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
+                       hard_frame_pointer_rtx);
 
-      if (vms_base_regno != REG_PV)
-       FRP (emit_move_insn (gen_rtx_REG (DImode, vms_base_regno),
-                            gen_rtx_REG (DImode, REG_PV)));
+      if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV)
+       emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno),
+                                   gen_rtx_REG (DImode, REG_PV)));
 
-      if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
+      if (alpha_procedure_type != PT_NULL
+         && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
        FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
 
       /* If we have to allocate space for outgoing args, do it now.  */
@@ -4842,7 +6419,7 @@ alpha_expand_prologue ()
                             - (ALPHA_ROUND
                                (current_function_outgoing_args_size)))));
     }
-  else
+  else if (!TARGET_ABI_UNICOSMK)
     {
       /* If we need a frame pointer, set it from the stack pointer.  */
       if (frame_pointer_needed)
@@ -4890,22 +6467,35 @@ alpha_start_function (file, fnname, decl)
   char *entry_label = (char *) alloca (strlen (fnname) + 6);
   int i;
 
+  /* Don't emit an extern directive for functions defined in the same file.  */
+  if (TARGET_ABI_UNICOSMK)
+    {
+      tree name_tree;
+      name_tree = get_identifier (fnname);
+      TREE_ASM_WRITTEN (name_tree) = 1;
+    }
+
   alpha_fnname = fnname;
   sa_size = alpha_sa_size ();
 
   frame_size = get_frame_size ();
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
+  else if (TARGET_ABI_UNICOSMK)
+    frame_size = ALPHA_ROUND (sa_size
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                             + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
                  + ALPHA_ROUND (frame_size
                                 + current_function_pretend_args_size));
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     reg_offset = 8;
   else
     reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
@@ -4922,15 +6512,20 @@ alpha_start_function (file, fnname, decl)
 
   if (write_symbols == SDB_DEBUG)
     {
+#ifdef ASM_OUTPUT_SOURCE_FILENAME
       ASM_OUTPUT_SOURCE_FILENAME (file,
                                  DECL_SOURCE_FILE (current_function_decl));
+#endif
+#ifdef ASM_OUTPUT_SOURCE_LINE
       if (debug_info_level != DINFO_LEVEL_TERSE)
         ASM_OUTPUT_SOURCE_LINE (file,
                                DECL_SOURCE_LINE (current_function_decl));
+#endif
     }
 
   /* Issue function start and label.  */
-  if (TARGET_OPEN_VMS || !flag_inhibit_size_directive)
+  if (TARGET_ABI_OPEN_VMS
+      || (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive))
     {
       fputs ("\t.ent ", file);
       assemble_name (file, fnname);
@@ -4938,8 +6533,9 @@ alpha_start_function (file, fnname, decl)
 
       /* If the function needs GP, we'll write the "..ng" label there.
         Otherwise, do it here.  */
-      if (! TARGET_OPEN_VMS && ! TARGET_WINDOWS_NT
-         && ! alpha_function_needs_gp)
+      if (TARGET_ABI_OSF
+          && ! alpha_function_needs_gp
+         && ! current_function_is_thunk)
        {
          putc ('$', file);
          assemble_name (file, fnname);
@@ -4948,20 +6544,26 @@ alpha_start_function (file, fnname, decl)
     }
 
   strcpy (entry_label, fnname);
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     strcat (entry_label, "..en");
+
+  /* For public functions, the label must be globalized by appending an
+     additional colon.  */
+  if (TARGET_ABI_UNICOSMK && TREE_PUBLIC (decl))
+    strcat (entry_label, ":");
+
   ASM_OUTPUT_LABEL (file, entry_label);
   inside_function = TRUE;
 
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     fprintf (file, "\t.base $%d\n", vms_base_regno);
 
-  if (!TARGET_OPEN_VMS && TARGET_IEEE_CONFORMANT
+  if (!TARGET_ABI_OPEN_VMS && !TARGET_ABI_UNICOSMK && TARGET_IEEE_CONFORMANT
       && !flag_inhibit_size_directive)
     {
       /* Set flags in procedure descriptor to request IEEE-conformant
         math-library routines.  The value we set it to is PDSC_EXC_IEEE
-        (/usr/include/pdsc.h). */
+        (/usr/include/pdsc.h).  */
       fputs ("\t.eflag 48\n", file);
     }
 
@@ -4972,11 +6574,13 @@ alpha_start_function (file, fnname, decl)
   /* Describe our frame.  If the frame size is larger than an integer,
      print it as zero to avoid an assembler error.  We won't be
      properly describing such a frame, but that's the best we can do.  */
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
+    ;
+  else if (TARGET_ABI_OPEN_VMS)
     {
       fprintf (file, "\t.frame $%d,", vms_unwind_regno);
       fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-              frame_size >= (1l << 31) ? 0 : frame_size);
+              frame_size >= ((HOST_WIDE_INT) 1 << 31) ? 0 : frame_size);
       fputs (",$26,", file);
       fprintf (file, HOST_WIDE_INT_PRINT_DEC, reg_offset);
       fputs ("\n", file);
@@ -4992,15 +6596,17 @@ alpha_start_function (file, fnname, decl)
     }
 
   /* Describe which registers were spilled.  */
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
+    ;
+  else if (TARGET_ABI_OPEN_VMS)
     {
       if (imask)
-        /* ??? Does VMS care if mask contains ra?  The old code did'nt
+        /* ??? Does VMS care if mask contains ra?  The old code didn't
            set it, so I don't here.  */
        fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1L << REG_RA));
       if (fmask)
        fprintf (file, "\t.fmask 0x%lx,0\n", fmask);
-      if (!vms_is_stack_procedure)
+      if (alpha_procedure_type == PT_REGISTER)
        fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
     }
   else if (!flag_inhibit_size_directive)
@@ -5026,7 +6632,7 @@ alpha_start_function (file, fnname, decl)
        }
     }
 
-#ifdef OPEN_VMS
+#if TARGET_ABI_OPEN_VMS
   /* Ifdef'ed cause readonly_section and link_section are only
      available then.  */
   readonly_section ();
@@ -5044,7 +6650,9 @@ alpha_start_function (file, fnname, decl)
   ASM_OUTPUT_LABEL (file, fnname);
   fprintf (file, "\t.pdesc ");
   assemble_name (file, fnname);
-  fprintf (file, "..en,%s\n", vms_is_stack_procedure ? "stack" : "reg");
+  fprintf (file, "..en,%s\n",
+          alpha_procedure_type == PT_STACK ? "stack"
+          : alpha_procedure_type == PT_REGISTER ? "reg" : "null");
   alpha_need_linkage (fnname, 1);
   text_section ();
 #endif
@@ -5052,16 +6660,19 @@ alpha_start_function (file, fnname, decl)
 
 /* Emit the .prologue note at the scheduled end of the prologue.  */
 
-void
-output_end_prologue (file)
+static void
+alpha_output_function_end_prologue (file)
      FILE *file;
 {
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
+    ;
+  else if (TARGET_ABI_OPEN_VMS)
     fputs ("\t.prologue\n", file);
-  else if (TARGET_WINDOWS_NT)
+  else if (TARGET_ABI_WINDOWS_NT)
     fputs ("\t.prologue 0\n", file);
   else if (!flag_inhibit_size_directive)
-    fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+    fprintf (file, "\t.prologue %d\n",
+            alpha_function_needs_gp || current_function_is_thunk);
 }
 
 /* Write function epilogue.  */
@@ -5093,26 +6704,37 @@ alpha_expand_epilogue ()
   sa_size = alpha_sa_size ();
 
   frame_size = get_frame_size ();
-  if (TARGET_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
+  else if (TARGET_ABI_UNICOSMK)
+    frame_size = ALPHA_ROUND (sa_size
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                             + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
                  + ALPHA_ROUND (frame_size
                                 + current_function_pretend_args_size));
 
-  if (TARGET_OPEN_VMS)
-    reg_offset = 8;
+  if (TARGET_ABI_OPEN_VMS)
+    {
+       if (alpha_procedure_type == PT_STACK)
+          reg_offset = 8;
+       else
+          reg_offset = 0;
+    }
   else
     reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
 
   alpha_sa_mask (&imask, &fmask);
 
-  fp_is_frame_pointer = ((TARGET_OPEN_VMS && vms_is_stack_procedure)
-                        || (!TARGET_OPEN_VMS && frame_pointer_needed));
+  fp_is_frame_pointer
+    = ((TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+       || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
   fp_offset = 0;
   sa_reg = stack_pointer_rtx;
 
@@ -5121,12 +6743,12 @@ alpha_expand_epilogue ()
   else
     eh_ofs = NULL_RTX;
 
-  if (sa_size)
+  if (!TARGET_ABI_UNICOSMK && sa_size)
     {
       /* If we have a frame pointer, restore SP from it.  */
-      if ((TARGET_OPEN_VMS
+      if ((TARGET_ABI_OPEN_VMS
           && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
-         || (!TARGET_OPEN_VMS && frame_pointer_needed))
+         || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed))
        FRP (emit_move_insn (stack_pointer_rtx, hard_frame_pointer_rtx));
 
       /* Cope with very large offsets to the register save area.  */
@@ -5146,11 +6768,11 @@ alpha_expand_epilogue ()
          FRP (emit_move_insn (sa_reg, sa_reg_exp));
        }
          
-      /* Restore registers in order, excepting a true frame pointer. */
+      /* Restore registers in order, excepting a true frame pointer.  */
 
       mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
       if (! eh_ofs)
-        MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+        set_mem_alias_set (mem, alpha_sr_alias_set);
       FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
 
       reg_offset += 8;
@@ -5164,7 +6786,7 @@ alpha_expand_epilogue ()
            else
              {
                mem = gen_rtx_MEM (DImode, plus_constant(sa_reg, reg_offset));
-               MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+               set_mem_alias_set (mem, alpha_sr_alias_set);
                FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem));
              }
            reg_offset += 8;
@@ -5174,11 +6796,43 @@ alpha_expand_epilogue ()
        if (fmask & (1L << i))
          {
            mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset));
-           MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+           set_mem_alias_set (mem, alpha_sr_alias_set);
            FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem));
            reg_offset += 8;
          }
     }
+  else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
+    {
+      /* Restore callee-saved general-purpose registers.  */
+
+      reg_offset = -56;
+
+      for (i = 9; i < 15; i++)
+       if (imask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
+                                                    reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (gen_rtx_REG (DImode, i), mem));
+           reg_offset -= 8;
+         }
+
+      for (i = 2; i < 10; i++)
+       if (fmask & (1L << i))
+         {
+           mem = gen_rtx_MEM (DFmode, plus_constant(hard_frame_pointer_rtx,
+                                                    reg_offset));
+           set_mem_alias_set (mem, alpha_sr_alias_set);
+           FRP (emit_move_insn (gen_rtx_REG (DFmode, i+32), mem));
+           reg_offset -= 8;
+         }
+
+      /* Restore the return address from the DSIB.  */
+
+      mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx, -8));
+      set_mem_alias_set (mem, alpha_sr_alias_set);
+      FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
+    }
 
   if (frame_size || eh_ofs)
     {
@@ -5194,8 +6848,15 @@ alpha_expand_epilogue ()
       /* If the stack size is large, begin computation into a temporary
         register so as not to interfere with a potential fp restore,
         which must be consecutive with an SP restore.  */
-      if (frame_size < 32768)
+      if (frame_size < 32768
+         && ! (TARGET_ABI_UNICOSMK && current_function_calls_alloca))
        sp_adj2 = GEN_INT (frame_size);
+      else if (TARGET_ABI_UNICOSMK)
+       {
+         sp_adj1 = gen_rtx_REG (DImode, 23);
+         FRP (emit_move_insn (sp_adj1, hard_frame_pointer_rtx));
+         sp_adj2 = const0_rtx;
+       }
       else if (frame_size < 0x40007fffL)
        {
          int low = ((frame_size & 0xffff) ^ 0x8000) - 0x8000;
@@ -5228,14 +6889,22 @@ alpha_expand_epilogue ()
       /* From now on, things must be in order.  So emit blockages.  */
 
       /* Restore the frame pointer.  */
-      if (fp_is_frame_pointer)
+      if (TARGET_ABI_UNICOSMK)
+       {
+         emit_insn (gen_blockage ());
+         mem = gen_rtx_MEM (DImode,
+                            plus_constant (hard_frame_pointer_rtx, -16));
+         set_mem_alias_set (mem, alpha_sr_alias_set);
+         FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
+       }
+      else if (fp_is_frame_pointer)
        {
          emit_insn (gen_blockage ());
          mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, fp_offset));
-         MEM_ALIAS_SET (mem) = alpha_sr_alias_set;
+         set_mem_alias_set (mem, alpha_sr_alias_set);
          FRP (emit_move_insn (hard_frame_pointer_rtx, mem));
        }
-      else if (TARGET_OPEN_VMS)
+      else if (TARGET_ABI_OPEN_VMS)
        {
          emit_insn (gen_blockage ());
          FRP (emit_move_insn (hard_frame_pointer_rtx,
@@ -5244,17 +6913,29 @@ alpha_expand_epilogue ()
 
       /* Restore the stack pointer.  */
       emit_insn (gen_blockage ());
-      FRP (emit_move_insn (stack_pointer_rtx,
-                          gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
+      if (sp_adj2 == const0_rtx)
+       FRP (emit_move_insn (stack_pointer_rtx, sp_adj1));
+      else
+       FRP (emit_move_insn (stack_pointer_rtx,
+                            gen_rtx_PLUS (DImode, sp_adj1, sp_adj2)));
     }
   else 
     {
-      if (TARGET_OPEN_VMS && !vms_is_stack_procedure)
+      if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER)
         {
           emit_insn (gen_blockage ());
           FRP (emit_move_insn (hard_frame_pointer_rtx,
                               gen_rtx_REG (DImode, vms_save_fp_regno)));
         }
+      else if (TARGET_ABI_UNICOSMK && alpha_procedure_type != PT_STACK)
+       {
+         /* Decrement the frame pointer if the function does not have a
+            frame.  */
+
+         emit_insn (gen_blockage ());
+         FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+                                     hard_frame_pointer_rtx, GEN_INT (-1))));
+        }
     }
 }
 
@@ -5267,7 +6948,7 @@ alpha_end_function (file, fnname, decl)
      tree decl ATTRIBUTE_UNUSED;
 {
   /* End the function.  */
-  if (!flag_inhibit_size_directive)
+  if (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive)
     {
       fputs ("\t.end ", file);
       assemble_name (file, fnname);
@@ -5279,11 +6960,93 @@ alpha_end_function (file, fnname, decl)
 
      Don't do this for global functions in object files destined for a
      shared library because the function may be overridden by the application
-     or other libraries.  Similarly, don't do this for weak functions.  */
+     or other libraries.  Similarly, don't do this for weak functions.
+
+     Don't do this for functions not defined in the .text section, as
+     otherwise it's not unlikely that the destination is out of range
+     for a direct branch.  */
 
   if (!DECL_WEAK (current_function_decl)
-      && (!flag_pic || !TREE_PUBLIC (current_function_decl)))
+      && (!flag_pic || !TREE_PUBLIC (current_function_decl))
+      && decl_in_text_section (current_function_decl))
     SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+
+  /* Output jump tables and the static subroutine information block.  */
+  if (TARGET_ABI_UNICOSMK)
+    {
+      unicosmk_output_ssib (file, fnname);
+      unicosmk_output_deferred_case_vectors (file);
+    }
+}
+
+/* Emit a tail call to FUNCTION after adjusting THIS by DELTA. 
+
+   In order to avoid the hordes of differences between generated code
+   with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating
+   lots of code loading up large constants, generate rtl and emit it
+   instead of going straight to text.
+
+   Not sure why this idea hasn't been explored before...  */
+
+void
+alpha_output_mi_thunk_osf (file, thunk_fndecl, delta, function)
+     FILE *file;
+     tree thunk_fndecl ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT delta;
+     tree function;
+{
+  HOST_WIDE_INT hi, lo;
+  rtx this, insn, funexp;
+
+  /* We always require a valid GP.  */
+  emit_insn (gen_prologue_ldgp ());
+  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+
+  /* Find the "this" pointer.  If the function returns a structure,
+     the structure return pointer is in $16.  */
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+    this = gen_rtx_REG (Pmode, 17);
+  else
+    this = gen_rtx_REG (Pmode, 16);
+
+  /* Add DELTA.  When possible we use ldah+lda.  Otherwise load the
+     entire constant for the add.  */
+  lo = ((delta & 0xffff) ^ 0x8000) - 0x8000;
+  hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (hi + lo == delta)
+    {
+      if (hi)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (hi)));
+      if (lo)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (lo)));
+    }
+  else
+    {
+      rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0),
+                                          delta, -(delta < 0));
+      emit_insn (gen_adddi3 (this, this, tmp));
+    }
+
+  /* Generate a tail call to the target function.  */
+  if (! TREE_USED (function))
+    {
+      assemble_external (function);
+      TREE_USED (function) = 1;
+    }
+  funexp = XEXP (DECL_RTL (function), 0);
+  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+  insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
+  SIBLING_CALL_P (insn) = 1;
+
+  /* Run just enough of rest_of_compilation to get the insns emitted.
+     There's not really enough bulk here to make other passes such as
+     instruction scheduling worth while.  Note that use_thunk calls
+     assemble_start_function and assemble_end_function.  */
+  insn = get_insns ();
+  shorten_branches (insn);
+  final_start_function (insn, file, 1);
+  final (insn, file, 1, 0);
+  final_end_function ();
 }
 \f
 /* Debugging support.  */
@@ -5475,7 +7238,7 @@ summarize_insn (x, sum, set)
 
     case CONST_INT:   case CONST_DOUBLE:
     case SYMBOL_REF:  case LABEL_REF:     case CONST:
-    case SCRATCH:
+    case SCRATCH:     case ASM_INPUT:
       break;
 
       /* Handle common unary and binary ops for efficiency.  */
@@ -6118,8 +7881,12 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
   /* Let shorten branches care for assigning alignments to code labels.  */
   shorten_branches (insns);
 
-  align = (FUNCTION_BOUNDARY / BITS_PER_UNIT < max_align
-          ? FUNCTION_BOUNDARY / BITS_PER_UNIT : max_align);
+  if (align_functions < 4)
+    align = 4;
+  else if ((unsigned int) align_functions < max_align)
+    align = align_functions;
+  else
+    align = max_align;
 
   ofs = prev_in_use = 0;
   i = insns;
@@ -6163,18 +7930,23 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
 
       /* If the known alignment is smaller than the recognized insn group,
         realign the output.  */
-      else if (align < len)
+      else if ((int) align < len)
        {
          unsigned int new_log_align = len > 8 ? 4 : 3;
-         rtx where;
+         rtx prev, where;
 
-         where = prev_nonnote_insn (i);
+         where = prev = prev_nonnote_insn (i);
          if (!where || GET_CODE (where) != CODE_LABEL)
            where = i;
 
-         emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
-         align = 1 << new_log_align;
-         ofs = 0;
+         /* Can't realign between a call and its gp reload.  */
+         if (! (TARGET_EXPLICIT_RELOCS
+                && prev && GET_CODE (prev) == CALL_INSN))
+           {
+             emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
+             align = 1 << new_log_align;
+             ofs = 0;
+           }
        }
 
       /* If the group won't fit in the same INT16 as the previous,
@@ -6183,13 +7955,13 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
         can make use of the knowledge of what sorts of instructions
         were issued in the previous group to make sure that all of
         the added nops are really free.  */
-      else if (ofs + len > align)
+      else if (ofs + len > (int) align)
        {
          int nop_count = (align - ofs) / 4;
          rtx where;
 
-         /* Insert nops before labels and branches to truely merge the
-            execution of the nops with the previous instruction group.  */
+         /* Insert nops before labels, branches, and calls to truely merge
+            the execution of the nops with the previous instruction group.  */
          where = prev_nonnote_insn (i);
          if (where)
            {
@@ -6199,7 +7971,7 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
                  if (where2 && GET_CODE (where2) == JUMP_INSN)
                    where = where2;
                }
-             else if (GET_CODE (where) != JUMP_INSN)
+             else if (GET_CODE (where) == INSN)
                where = i;
            }
          else
@@ -6217,7 +7989,7 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
     }
 }
 \f
-/* Machine dependant reorg pass.  */
+/* Machine dependent reorg pass.  */
 
 void
 alpha_reorg (insns)
@@ -6316,8 +8088,8 @@ check_float_value (mode, d, overflow)
 
   return 0;
 }
-
-#if OPEN_VMS
+\f
+#if TARGET_ABI_OPEN_VMS
 
 /* Return the VMS argument type corresponding to MODE.  */
 
@@ -6470,7 +8242,7 @@ alpha_write_one_linkage (node, data)
      splay_tree_node node;
      void *data;
 {
-  const char *name = (const char *) node->key;
+  const char *const name = (const char *) node->key;
   struct alpha_links *links = (struct alpha_links *) node->value;
   FILE *stream = (FILE *) data;
 
@@ -6498,11 +8270,93 @@ void
 alpha_write_linkage (stream)
     FILE *stream;
 {
-  readonly_section ();
-  fprintf (stream, "\t.align 3\n");
-  splay_tree_foreach (alpha_links, alpha_write_one_linkage, stream);
+  if (alpha_links)
+    {
+      readonly_section ();
+      fprintf (stream, "\t.align 3\n");
+      splay_tree_foreach (alpha_links, alpha_write_one_linkage, stream);
+    }
+}
+
+/* Given a decl, a section name, and whether the decl initializer
+   has relocs, choose attributes for the section.  */
+
+#define SECTION_VMS_OVERLAY    SECTION_FORGET
+#define SECTION_VMS_GLOBAL SECTION_MACH_DEP
+#define SECTION_VMS_INITIALIZE (SECTION_VMS_GLOBAL << 1)
+
+static unsigned int
+vms_section_type_flags (decl, name, reloc)
+     tree decl;
+     const char *name;
+     int reloc;
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_OVERLAY;
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("global", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_GLOBAL;
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("initialize", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_INITIALIZE;
+
+  return flags;
+}
+
+/* Switch to an arbitrary section NAME with attributes as specified
+   by FLAGS.  ALIGN specifies any known alignment requirements for
+   the section; 0 if the default should be used.  */
+
+static void
+vms_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  fputc ('\n', asm_out_file);
+  fprintf (asm_out_file, ".section\t%s", name);
+
+  if (flags & SECTION_VMS_OVERLAY)
+    fprintf (asm_out_file, ",OVR");
+  if (flags & SECTION_VMS_GLOBAL)
+    fprintf (asm_out_file, ",GBL");
+  if (flags & SECTION_VMS_INITIALIZE)
+    fprintf (asm_out_file, ",NOMOD");
+  if (flags & SECTION_DEBUG)
+    fprintf (asm_out_file, ",NOWRT");
+
+  fputc ('\n', asm_out_file);
+}
+
+/* Record an element in the table of global constructors.  SYMBOL is
+   a SYMBOL_REF of the function to be called; PRIORITY is a number
+   between 0 and MAX_INIT_PRIORITY.  
+
+   Differs from default_ctors_section_asm_out_constructor in that the
+   width of the .ctors entry is always 64 bits, rather than the 32 bits
+   used by a normal pointer.  */
+
+static void
+vms_asm_out_constructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  ctors_section ();
+  assemble_align (BITS_PER_WORD);
+  assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
 }
 
+static void
+vms_asm_out_destructor (symbol, priority)
+     rtx symbol;
+     int priority ATTRIBUTE_UNUSED;
+{
+  dtors_section ();
+  assemble_align (BITS_PER_WORD);
+  assemble_integer (symbol, UNITS_PER_WORD, BITS_PER_WORD, 1);
+}
 #else
 
 rtx
@@ -6513,4 +8367,801 @@ alpha_need_linkage (name, is_local)
   return NULL_RTX;
 }
 
-#endif /* OPEN_VMS */
+#endif /* TARGET_ABI_OPEN_VMS */
+\f
+#if TARGET_ABI_UNICOSMK
+
+static void unicosmk_output_module_name PARAMS ((FILE *));
+static void unicosmk_output_default_externs PARAMS ((FILE *));
+static void unicosmk_output_dex PARAMS ((FILE *));
+static void unicosmk_output_externs PARAMS ((FILE *));
+static void unicosmk_output_addr_vec PARAMS ((FILE *, rtx));
+static const char *unicosmk_ssib_name PARAMS ((void));
+static int unicosmk_special_name PARAMS ((const char *));
+
+/* Define the offset between two registers, one to be eliminated, and the
+   other its replacement, at the start of a routine.  */
+
+int
+unicosmk_initial_elimination_offset (from, to)
+      int from;
+      int to;
+{
+  int fixed_size;
+  
+  fixed_size = alpha_sa_size();
+  if (fixed_size != 0)
+    fixed_size += 48;
+
+  if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    return -fixed_size; 
+  else if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
+    return 0;
+  else if (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    return (ALPHA_ROUND (current_function_outgoing_args_size)
+           + ALPHA_ROUND (get_frame_size()));
+  else if (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM)
+    return (ALPHA_ROUND (fixed_size)
+           + ALPHA_ROUND (get_frame_size() 
+                          + current_function_outgoing_args_size));
+  else
+    abort ();
+}
+
+/* Output the module name for .ident and .end directives. We have to strip
+   directories and add make sure that the module name starts with a letter
+   or '$'.  */
+
+static void
+unicosmk_output_module_name (file)
+      FILE *file;
+{
+  const char *name;
+
+  /* Strip directories.  */
+
+  name = strrchr (main_input_filename, '/');
+  if (name)
+    ++name;
+  else
+    name = main_input_filename;
+
+  /* CAM only accepts module names that start with a letter or '$'. We
+     prefix the module name with a '$' if necessary.  */
+
+  if (!ISALPHA (*name))
+    fprintf (file, "$%s", name);
+  else
+    fputs (name, file);
+}
+
+/* Output text that to appear at the beginning of an assembler file.  */
+
+void 
+unicosmk_asm_file_start (file)
+      FILE *file;
+{
+  int i;
+
+  fputs ("\t.ident\t", file);
+  unicosmk_output_module_name (file);
+  fputs ("\n\n", file);
+
+  /* The Unicos/Mk assembler uses different register names. Instead of trying
+     to support them, we simply use micro definitions.  */
+
+  /* CAM has different register names: rN for the integer register N and fN
+     for the floating-point register N. Instead of trying to use these in
+     alpha.md, we define the symbols $N and $fN to refer to the appropriate
+     register.  */
+
+  for (i = 0; i < 32; ++i)
+    fprintf (file, "$%d <- r%d\n", i, i);
+
+  for (i = 0; i < 32; ++i)
+    fprintf (file, "$f%d <- f%d\n", i, i);
+
+  putc ('\n', file);
+
+  /* The .align directive fill unused space with zeroes which does not work
+     in code sections. We define the macro 'gcc@code@align' which uses nops
+     instead. Note that it assumes that code sections always have the
+     biggest possible alignment since . refers to the current offset from
+     the beginning of the section.  */
+
+  fputs ("\t.macro gcc@code@align n\n", file);
+  fputs ("gcc@n@bytes = 1 << n\n", file);
+  fputs ("gcc@here = . % gcc@n@bytes\n", file);
+  fputs ("\t.if ne, gcc@here, 0\n", file);
+  fputs ("\t.repeat (gcc@n@bytes - gcc@here) / 4\n", file);
+  fputs ("\tbis r31,r31,r31\n", file);
+  fputs ("\t.endr\n", file);
+  fputs ("\t.endif\n", file);
+  fputs ("\t.endm gcc@code@align\n\n", file);
+
+  /* Output extern declarations which should always be visible.  */
+  unicosmk_output_default_externs (file);
+
+  /* Open a dummy section. We always need to be inside a section for the
+     section-switching code to work correctly.
+     ??? This should be a module id or something like that. I still have to
+     figure out what the rules for those are.  */
+  fputs ("\n\t.psect\t$SG00000,data\n", file);
+}
+
+/* Output text to appear at the end of an assembler file. This includes all
+   pending extern declarations and DEX expressions.  */
+
+void
+unicosmk_asm_file_end (file)
+      FILE *file;
+{
+  fputs ("\t.endp\n\n", file);
+
+  /* Output all pending externs.  */
+
+  unicosmk_output_externs (file);
+
+  /* Output dex definitions used for functions whose names conflict with 
+     register names.  */
+
+  unicosmk_output_dex (file);
+
+  fputs ("\t.end\t", file);
+  unicosmk_output_module_name (file);
+  putc ('\n', file);
+}
+
+/* Output the definition of a common variable.  */
+
+void
+unicosmk_output_common (file, name, size, align)
+      FILE *file;
+      const char *name;
+      int size;
+      int align;
+{
+  tree name_tree;
+  printf ("T3E__: common %s\n", name);
+
+  common_section ();
+  fputs("\t.endp\n\n\t.psect ", file);
+  assemble_name(file, name);
+  fprintf(file, ",%d,common\n", floor_log2 (align / BITS_PER_UNIT));
+  fprintf(file, "\t.byte\t0:%d\n", size);
+
+  /* Mark the symbol as defined in this module.  */
+  name_tree = get_identifier (name);
+  TREE_ASM_WRITTEN (name_tree) = 1;
+}
+
+#define SECTION_PUBLIC SECTION_MACH_DEP
+#define SECTION_MAIN (SECTION_PUBLIC << 1)
+static int current_section_align;
+
+static unsigned int
+unicosmk_section_type_flags (decl, name, reloc)
+     tree decl;
+     const char *name;
+     int reloc ATTRIBUTE_UNUSED;
+{
+  unsigned int flags = default_section_type_flags (decl, name, reloc);
+
+  if (!decl)
+    return flags;
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      current_section_align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+      if (align_functions_log > current_section_align)
+       current_section_align = align_functions_log;
+
+      if (! strcmp (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), "main"))
+       flags |= SECTION_MAIN;
+    }
+  else
+    current_section_align = floor_log2 (DECL_ALIGN (decl) / BITS_PER_UNIT);
+
+  if (TREE_PUBLIC (decl))
+    flags |= SECTION_PUBLIC;
+
+  return flags;
+}
+
+/* Generate a section name for decl and associate it with the
+   declaration.  */
+
+void
+unicosmk_unique_section (decl, reloc)
+      tree decl;
+      int reloc ATTRIBUTE_UNUSED;
+{
+  const char *name;
+  int len;
+
+  if (!decl) 
+    abort ();
+
+  name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
+  STRIP_NAME_ENCODING (name, name);
+  len = strlen (name);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      char *string;
+
+      /* It is essential that we prefix the section name here because 
+        otherwise the section names generated for constructors and 
+        destructors confuse collect2.  */
+
+      string = alloca (len + 6);
+      sprintf (string, "code@%s", name);
+      DECL_SECTION_NAME (decl) = build_string (len + 5, string);
+    }
+  else if (TREE_PUBLIC (decl))
+    DECL_SECTION_NAME (decl) = build_string (len, name);
+  else
+    {
+      char *string;
+
+      string = alloca (len + 6);
+      sprintf (string, "data@%s", name);
+      DECL_SECTION_NAME (decl) = build_string (len + 5, string);
+    }
+}
+
+/* Switch to an arbitrary section NAME with attributes as specified
+   by FLAGS.  ALIGN specifies any known alignment requirements for
+   the section; 0 if the default should be used.  */
+
+static void
+unicosmk_asm_named_section (name, flags)
+     const char *name;
+     unsigned int flags;
+{
+  const char *kind;
+
+  /* Close the previous section.  */
+
+  fputs ("\t.endp\n\n", asm_out_file);
+
+  /* Find out what kind of section we are opening.  */
+
+  if (flags & SECTION_MAIN)
+    fputs ("\t.start\tmain\n", asm_out_file);
+
+  if (flags & SECTION_CODE)
+    kind = "code";
+  else if (flags & SECTION_PUBLIC)
+    kind = "common";
+  else
+    kind = "data";
+
+  if (current_section_align != 0)
+    fprintf (asm_out_file, "\t.psect\t%s,%d,%s\n", name,
+            current_section_align, kind);
+  else
+    fprintf (asm_out_file, "\t.psect\t%s,%s\n", name, kind);
+}
+
+static void
+unicosmk_insert_attributes (decl, attr_ptr)
+     tree decl;
+     tree *attr_ptr ATTRIBUTE_UNUSED;
+{
+  if (DECL_P (decl)
+      && (TREE_PUBLIC (decl) || TREE_CODE (decl) == FUNCTION_DECL))
+    UNIQUE_SECTION (decl, 0);
+}
+
+/* Output an alignment directive. We have to use the macro 'gcc@code@align'
+   in code sections because .align fill unused space with zeroes.  */
+      
+void
+unicosmk_output_align (file, align)
+      FILE *file;
+      int align;
+{
+  if (inside_function)
+    fprintf (file, "\tgcc@code@align\t%d\n", align);
+  else
+    fprintf (file, "\t.align\t%d\n", align);
+}
+
+/* Add a case vector to the current function's list of deferred case
+   vectors. Case vectors have to be put into a separate section because CAM
+   does not allow data definitions in code sections.  */
+
+void
+unicosmk_defer_case_vector (lab, vec)
+      rtx lab;
+      rtx vec;
+{
+  struct machine_function *machine = cfun->machine;
+  
+  vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
+  machine->addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec,
+                                         machine->addr_list); 
+}
+
+/* Output a case vector.  */
+
+static void
+unicosmk_output_addr_vec (file, vec)
+      FILE *file;
+      rtx vec;
+{
+  rtx lab  = XEXP (vec, 0);
+  rtx body = XEXP (vec, 1);
+  int vlen = XVECLEN (body, 0);
+  int idx;
+
+  ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (lab));
+
+  for (idx = 0; idx < vlen; idx++)
+    {
+      ASM_OUTPUT_ADDR_VEC_ELT
+        (file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
+    }
+}
+
+/* Output current function's deferred case vectors.  */
+
+static void
+unicosmk_output_deferred_case_vectors (file)
+      FILE *file;
+{
+  struct machine_function *machine = cfun->machine;
+  rtx t;
+
+  if (machine->addr_list == NULL_RTX)
+    return;
+
+  data_section ();
+  for (t = machine->addr_list; t; t = XEXP (t, 1))
+    unicosmk_output_addr_vec (file, XEXP (t, 0));
+}
+
+/* Set up the dynamic subprogram information block (DSIB) and update the 
+   frame pointer register ($15) for subroutines which have a frame. If the 
+   subroutine doesn't have a frame, simply increment $15.  */
+
+static void
+unicosmk_gen_dsib (imaskP)
+      unsigned long * imaskP;
+{
+  if (alpha_procedure_type == PT_STACK)
+    {
+      const char *ssib_name;
+      rtx mem;
+
+      /* Allocate 64 bytes for the DSIB.  */
+
+      FRP (emit_insn (gen_adddi3 (stack_pointer_rtx, stack_pointer_rtx,
+                                  GEN_INT (-64))));
+      emit_insn (gen_blockage ());
+
+      /* Save the return address.  */
+
+      mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 56));
+      set_mem_alias_set (mem, alpha_sr_alias_set);
+      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
+      (*imaskP) &= ~(1L << REG_RA);
+
+      /* Save the old frame pointer.  */
+
+      mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 48));
+      set_mem_alias_set (mem, alpha_sr_alias_set);
+      FRP (emit_move_insn (mem, hard_frame_pointer_rtx));
+      (*imaskP) &= ~(1L << HARD_FRAME_POINTER_REGNUM);
+
+      emit_insn (gen_blockage ());
+
+      /* Store the SSIB pointer.  */
+
+      ssib_name = ggc_strdup (unicosmk_ssib_name ());
+      mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 32));
+      set_mem_alias_set (mem, alpha_sr_alias_set);
+
+      FRP (emit_move_insn (gen_rtx_REG (DImode, 5),
+                           gen_rtx_SYMBOL_REF (Pmode, ssib_name)));
+      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 5)));
+
+      /* Save the CIW index.  */
+
+      mem = gen_rtx_MEM (DImode, plus_constant (stack_pointer_rtx, 24));
+      set_mem_alias_set (mem, alpha_sr_alias_set);
+      FRP (emit_move_insn (mem, gen_rtx_REG (DImode, 25)));
+
+      emit_insn (gen_blockage ());
+
+      /* Set the new frame pointer.  */
+
+      FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+                                  stack_pointer_rtx, GEN_INT (64))));
+
+    }
+  else
+    {
+      /* Increment the frame pointer register to indicate that we do not
+         have a frame.  */
+
+      FRP (emit_insn (gen_adddi3 (hard_frame_pointer_rtx,
+                                  hard_frame_pointer_rtx, GEN_INT (1))));
+    }
+}
+
+#define SSIB_PREFIX "__SSIB_"
+#define SSIB_PREFIX_LEN 7
+
+/* Generate the name of the SSIB section for the current function.  */
+
+static const char *
+unicosmk_ssib_name ()
+{
+  /* This is ok since CAM won't be able to deal with names longer than that 
+     anyway.  */
+
+  static char name[256];
+
+  rtx x;
+  const char *fnname;
+  int len;
+
+  x = DECL_RTL (cfun->decl);
+  if (GET_CODE (x) != MEM)
+    abort ();
+  x = XEXP (x, 0);
+  if (GET_CODE (x) != SYMBOL_REF)
+    abort ();
+  fnname = XSTR (x, 0);
+  STRIP_NAME_ENCODING (fnname, fnname);
+
+  len = strlen (fnname);
+  if (len + SSIB_PREFIX_LEN > 255)
+    len = 255 - SSIB_PREFIX_LEN;
+
+  strcpy (name, SSIB_PREFIX);
+  strncpy (name + SSIB_PREFIX_LEN, fnname, len);
+  name[len + SSIB_PREFIX_LEN] = 0;
+
+  return name;
+}
+
+/* Output the static subroutine information block for the current
+   function.  */
+
+static void
+unicosmk_output_ssib (file, fnname)
+      FILE *file;
+      const char *fnname;
+{
+  int len;
+  int i;
+  rtx x;
+  rtx ciw;
+  struct machine_function *machine = cfun->machine;
+
+  ssib_section ();
+  fprintf (file, "\t.endp\n\n\t.psect\t%s%s,data\n", user_label_prefix,
+          unicosmk_ssib_name ());
+
+  /* Some required stuff and the function name length.  */
+
+  len = strlen (fnname);
+  fprintf (file, "\t.quad\t^X20008%2.2X28\n", len);
+
+  /* Saved registers
+     ??? We don't do that yet.  */
+
+  fputs ("\t.quad\t0\n", file);
+
+  /* Function address.  */
+
+  fputs ("\t.quad\t", file);
+  assemble_name (file, fnname);
+  putc ('\n', file);
+
+  fputs ("\t.quad\t0\n", file);
+  fputs ("\t.quad\t0\n", file);
+
+  /* Function name.
+     ??? We do it the same way Cray CC does it but this could be
+     simplified.  */
+
+  for( i = 0; i < len; i++ )
+    fprintf (file, "\t.byte\t%d\n", (int)(fnname[i]));
+  if( (len % 8) == 0 )
+    fputs ("\t.quad\t0\n", file);
+  else
+    fprintf (file, "\t.bits\t%d : 0\n", (8 - (len % 8))*8);
+
+  /* All call information words used in the function.  */
+
+  for (x = machine->first_ciw; x; x = XEXP (x, 1))
+    {
+      ciw = XEXP (x, 0);
+      fprintf (file, "\t.quad\t");
+#if HOST_BITS_PER_WIDE_INT == 32
+      fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
+              CONST_DOUBLE_HIGH (ciw), CONST_DOUBLE_LOW (ciw));
+#else
+      fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (ciw));
+#endif
+      fprintf (file, "\n");
+    }
+}
+
+/* Add a call information word (CIW) to the list of the current function's
+   CIWs and return its index.
+
+   X is a CONST_INT or CONST_DOUBLE representing the CIW.  */
+
+rtx
+unicosmk_add_call_info_word (x)
+      rtx x;
+{
+  rtx node;
+  struct machine_function *machine = cfun->machine;
+
+  node = gen_rtx_EXPR_LIST (VOIDmode, x, NULL_RTX);
+  if (machine->first_ciw == NULL_RTX)
+    machine->first_ciw = node;
+  else
+    XEXP (machine->last_ciw, 1) = node;
+
+  machine->last_ciw = node;
+  ++machine->ciw_count;
+
+  return GEN_INT (machine->ciw_count
+                 + strlen (current_function_name)/8 + 5);
+}
+
+static char unicosmk_section_buf[100];
+
+char *
+unicosmk_text_section ()
+{
+  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 ()
+{
+  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
+   extern declarations for those which are referenced but not defined at
+   the end of file.  */
+
+/* List of identifiers for which an extern declaration might have to be
+   emitted.  */
+
+struct unicosmk_extern_list
+{
+  struct unicosmk_extern_list *next;
+  const char *name;
+};
+
+static struct unicosmk_extern_list *unicosmk_extern_head = 0;
+
+/* Output extern declarations which are required for every asm file.  */
+
+static void
+unicosmk_output_default_externs (file)
+       FILE *file;
+{
+  static const char *const externs[] =
+    { "__T3E_MISMATCH" };
+
+  int i;
+  int n;
+
+  n = ARRAY_SIZE (externs);
+
+  for (i = 0; i < n; i++)
+    fprintf (file, "\t.extern\t%s\n", externs[i]);
+}
+
+/* Output extern declarations for global symbols which are have been
+   referenced but not defined.  */
+
+static void
+unicosmk_output_externs (file)
+      FILE *file;
+{
+  struct unicosmk_extern_list *p;
+  const char *real_name;
+  int len;
+  tree name_tree;
+
+  len = strlen (user_label_prefix);
+  for (p = unicosmk_extern_head; p != 0; p = p->next)
+    {
+      /* We have to strip the encoding and possibly remove user_label_prefix 
+        from the identifier in order to handle -fleading-underscore and
+        explicit asm names correctly (cf. gcc.dg/asm-names-1.c).  */
+      STRIP_NAME_ENCODING (real_name, p->name);
+      if (len && p->name[0] == '*'
+         && !memcmp (real_name, user_label_prefix, len))
+       real_name += len;
+       
+      name_tree = get_identifier (real_name);
+      if (! TREE_ASM_WRITTEN (name_tree))
+       {
+         TREE_ASM_WRITTEN (name_tree) = 1;
+         fputs ("\t.extern\t", file);
+         assemble_name (file, p->name);
+         putc ('\n', file);
+       }
+    }
+}
+      
+/* Record an extern.  */
+
+void
+unicosmk_add_extern (name)
+     const char *name;
+{
+  struct unicosmk_extern_list *p;
+
+  p = (struct unicosmk_extern_list *)
+       permalloc (sizeof (struct unicosmk_extern_list));
+  p->next = unicosmk_extern_head;
+  p->name = name;
+  unicosmk_extern_head = p;
+}
+
+/* The Cray assembler generates incorrect code if identifiers which
+   conflict with register names are used as instruction operands. We have
+   to replace such identifiers with DEX expressions.  */
+
+/* Structure to collect identifiers which have been replaced by DEX
+   expressions.  */
+
+struct unicosmk_dex {
+  struct unicosmk_dex *next;
+  const char *name;
+};
+
+/* List of identifiers which have been replaced by DEX expressions. The DEX 
+   number is determined by the position in the list.  */
+
+static struct unicosmk_dex *unicosmk_dex_list = NULL; 
+
+/* The number of elements in the DEX list.  */
+
+static int unicosmk_dex_count = 0;
+
+/* Check if NAME must be replaced by a DEX expression.  */
+
+static int
+unicosmk_special_name (name)
+      const char *name;
+{
+  if (name[0] == '*')
+    ++name;
+
+  if (name[0] == '$')
+    ++name;
+
+  if (name[0] != 'r' && name[0] != 'f' && name[0] != 'R' && name[0] != 'F')
+    return 0;
+
+  switch (name[1])
+    {
+    case '1':  case '2':
+      return (name[2] == '\0' || (ISDIGIT (name[2]) && name[3] == '\0'));
+
+    case '3':
+      return (name[2] == '\0'
+              || ((name[2] == '0' || name[2] == '1') && name[3] == '\0'));
+
+    default:
+      return (ISDIGIT (name[1]) && name[2] == '\0');
+    }
+}
+
+/* Return the DEX number if X must be replaced by a DEX expression and 0
+   otherwise.  */
+
+static int
+unicosmk_need_dex (x)
+      rtx x;
+{
+  struct unicosmk_dex *dex;
+  const char *name;
+  int i;
+  
+  if (GET_CODE (x) != SYMBOL_REF)
+    return 0;
+
+  name = XSTR (x,0);
+  if (! unicosmk_special_name (name))
+    return 0;
+
+  i = unicosmk_dex_count;
+  for (dex = unicosmk_dex_list; dex; dex = dex->next)
+    {
+      if (! strcmp (name, dex->name))
+        return i;
+      --i;
+    }
+      
+  dex = (struct unicosmk_dex *) permalloc (sizeof (struct unicosmk_dex));
+  dex->name = name;
+  dex->next = unicosmk_dex_list;
+  unicosmk_dex_list = dex;
+
+  ++unicosmk_dex_count;
+  return unicosmk_dex_count;
+}
+
+/* Output the DEX definitions for this file.  */
+
+static void
+unicosmk_output_dex (file)
+      FILE *file;
+{
+  struct unicosmk_dex *dex;
+  int i;
+
+  if (unicosmk_dex_list == NULL)
+    return;
+
+  fprintf (file, "\t.dexstart\n");
+
+  i = unicosmk_dex_count;
+  for (dex = unicosmk_dex_list; dex; dex = dex->next)
+    {
+      fprintf (file, "\tDEX (%d) = ", i);
+      assemble_name (file, dex->name);
+      putc ('\n', file);
+      --i;
+    }
+  
+  fprintf (file, "\t.dexend\n");
+}
+
+#else
+
+static void
+unicosmk_output_deferred_case_vectors (file)
+      FILE *file ATTRIBUTE_UNUSED;
+{}
+
+static void
+unicosmk_gen_dsib (imaskP)
+      unsigned long * imaskP ATTRIBUTE_UNUSED;
+{}
+
+static void
+unicosmk_output_ssib (file, fnname)
+      FILE * file ATTRIBUTE_UNUSED;
+      const char * fnname ATTRIBUTE_UNUSED;
+{}
+
+rtx
+unicosmk_add_call_info_word (x)
+     rtx x ATTRIBUTE_UNUSED;
+{
+  return NULL_RTX;
+}
+
+static int
+unicosmk_need_dex (x)
+      rtx x ATTRIBUTE_UNUSED;
+{
+  return 0;
+}
+
+#endif /* TARGET_ABI_UNICOSMK */