Cray T3E port.
authorRichard Henderson <rth@gcc.gnu.org>
Tue, 11 Sep 2001 08:52:39 +0000 (01:52 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Tue, 11 Sep 2001 08:52:39 +0000 (01:52 -0700)
From-SVN: r45539

gcc/ChangeLog
gcc/config.gcc
gcc/config/alpha/alpha-protos.h
gcc/config/alpha/alpha.c
gcc/config/alpha/alpha.h
gcc/config/alpha/alpha.md
gcc/config/alpha/t-unicosmk [new file with mode: 0644]
gcc/config/alpha/unicosmk.h [new file with mode: 0644]
gcc/fixinc/fixincl.x
gcc/fixinc/inclhack.def
gcc/ginclude/stddef.h

index f5f5afb8b83bdce546a2f1da8f52dbeac3e48d8b..7b9891e3f06300ea94e3b677baefea8dfd8f036e 100644 (file)
@@ -1,3 +1,93 @@
+2001-09-11  Richard Henderson  <rth@redhat.com>
+
+       * config/alpha/alpha.c: Tidy formatting.
+       (local_symbolic_operand): Verify mode.
+       (alpha_sa_mask): Ignore unicos for eh_return.
+       (alpha_expand_epilogue): Handle sp_adj2 zero, not NULL.
+       * config/alpha/alpha.md (umk divsi patterns): Remove.
+       (extendsfdf2): Remove unicos check.
+       (tablejump): Merge vms and unicos code; always use direct set
+       plus label_ref use.
+
+2001-09-11  Roman Lechtchinsky  <rl@cs.tu-berlin.de>
+
+       * config.gcc (alpha*-*-unicosmk*): New target.
+
+       * config/alpha/alpha-protos.h (symbolic_operand,
+       unicosmk_add_call_info_word, unicosmk_add_extern,
+       unicosmk_defer_case_vector, unicosmk_unique_section,
+       unicosmk_output_align, unicosmk_text_section, unicosmk_data_section,
+       unicosmk_asm_file_start, unicosmk_asm_file_end,
+       unicosmk_output_common): Declare.
+
+       * config/alpha/alpha.c (NUM_ARGS, override_options, call_operand,
+       direct_return, function_arg, alpha_va_start, alpha_va_arg,
+       alpha_does_function_need_gp, alpha_end_function): Support Cray
+       Unicos/Mk.
+       (alpha_init_machine_status, alpha_mark_machine_status,
+       alpha_free_machine_status, unicosmk_output_deferred_case_vectors,
+       unicosmk_gen_dsib, unicosmk_output_ssib, unicosmk_need_dex,
+       unicosmk_asm_named_section, unicosmk_insert_attributes,
+       unicosmk_section_type_flags, symbolic_operand,
+       unicosmk_output_module_name, unicosmk_output_default_externs,
+       unicosmk_output_dex, unicosmk_output_externs,
+       unicosmk_output_addr_vec, unicosmk_ssib_name,
+       unicosmk_initial_elimination_offset, unicosmk_asm_file_start,
+       unicosmk_asm_file_end, unicosmk_output_common,
+       unicosmk_section_type_flags, unicosmk_unique_section,
+       unicosmk_add_call_info_word, unicosmk_text_section,
+       unicosmk_data_section, unicosmk_extern_list, unicosmk_extern_head,
+       unicosmk_add_extern, unicosmk_dex, unicosmk_dex_list,
+       unicosmk_dex_count, unicosmk_special_name): New.
+       (TARGET_INSERT_ATTRIBUTES, TARGET_SECTION_TYPE_FLAGS): Define for
+       TARGET_ABI_UNICOSMK.
+       (get_aligned_mem, alpha_expand_unaligned_load,
+       alpha_expand_unaligned_store, alpha_expand_unaligned_load_words,
+       alpha_expand_unaligned_store_words): Support big-endian mode.
+       (print_operand): Likewise. New format specifier 't'. Use
+       TARGET_AS_SLASH_BEFORE_SUFFIX.
+       (alpha_is_stack_procedure): Rename from vms_is_stack_procedure.
+       (alpha_pv_save_size): Update with above change.
+       (alpha_sa_mask, alpha_sa_size, alpha_expand_prologue,
+       alpha_start_function, alpha_expand_epilogue): Likewise. Support Cray
+       Unicos/Mk.
+
+       * config/alpha/alpha.h (TARGET_ABI_UNICOSMK): New.
+       (TARGET_ABI_OSF): Exclude TARGET_ABI_UNICOSMK.
+       (TARGET_AS_SLASH_BEFORE_SUFFIX): New.
+       (EXTRA_CONSTRAINT): New constraint 'U'.
+       (PREDICATE_CODES): Add symbolic_operand.
+
+       * config/alpha/alpha.md (UNSPEC_UMK_LAUM, UNSPEC_UMK_LALM,
+       UNSPEC_UMK_LAL, UNSPEC_UMK_LOAD_CIW): New constants.
+       (mulsi3, *mulsi_se, mulvsi3): Disable for TARGET_ABI_UNICOSMK.
+       (integer division and modulus patterns): Split in default and
+       Unicos/Mk versions.
+       (*divmodsi_internal, *divmoddi_internal): Disable for
+       TARGET_ABI_UNICOSMK.
+       (unaligned_extend?idi, unaligned_load?i, unaligned_store?i): Split in 
+       little-endian and big-endian versions.
+       (ext, ins, msk): Likewise.
+       (extv, extzv, insv): Support big-endian mode.
+       (call, call_value, tablejump): Support TARGET_ABI_UNICOSMK.
+       (call_umk, call_value_umk, *call_umk, tablejump_umk,
+       *tablejump_umk_internal, *call_value_umk): New.
+       (*movdi_nofix): Add pattern for loading an address into a register on
+       TARGET_ABI_UNICOSMK.
+       (umk_laum, umk_lal, umk_lalm, *umk_load_ciw): New.
+       (umk_mismatch_args, arg_home_umk): New.
+       (various insns): Don't use mov, fmov, nop, fnop and unop.
+       (realign): Support TARGET_ABI_UNICOSMK.
+
+       * config/alpha/unicosmk.h: New file.
+       * config/alpha/t-unicosmk: New file.
+
+       * fixinc/inclhack.def (unicosmk_restrict): New.
+       * fixinc/fixincl.x: Regenerate.
+
+       * ginclude/stddef.h (size_t): Check for and define __SIZE_T__.
+       (wchar_t): Check for and define __WCHAR_T__.
+
 2001-09-11  Richard Sandiford  <rsandifo@redhat.com>
 
        * combine.c (simplify_shift_const): Treat shifts by the mode
index 2af51faf31c1213162650fa28f0ccfe4b0425032..00ed9b32f55a5016cf3e89e62fd8b5fbd7cdb603 100644 (file)
@@ -398,6 +398,14 @@ a29k-wrs-vxworks*)
 a29k-*-*)                      # Default a29k environment.
        use_collect2=yes
        ;;
+alpha*-*-unicosmk*)
+       use_collect2=yes
+       tm_file="${tm_file} alpha/unicosmk.h"
+       
+       # Don't include t-ieee for now because we don't support that yet
+       # tmake_file="alpha/t-ieee"
+       tmake_file="alpha/t-unicosmk"
+       ;;
 alpha-*-interix)
        tm_file="${tm_file} alpha/alpha32.h interix.h alpha/alpha-interix.h"
 
index be18c633910f832810f11b54b73b756e9ffbe6e5..c8ff11228b700adb77b31e6d4f4ba05af7e41390 100644 (file)
@@ -56,6 +56,7 @@ extern int input_operand PARAMS ((rtx, enum machine_mode));
 extern int current_file_function_operand PARAMS ((rtx, enum machine_mode));
 extern int local_symbolic_operand PARAMS ((rtx, enum machine_mode));
 extern int call_operand PARAMS ((rtx, enum machine_mode));
+extern int symbolic_operand PARAMS ((rtx, enum machine_mode));
 extern int alpha_comparison_operator PARAMS ((rtx, enum machine_mode));
 extern int alpha_zero_comparison_operator PARAMS ((rtx, enum machine_mode));
 extern int alpha_swapped_comparison_operator PARAMS ((rtx, enum machine_mode));
@@ -149,3 +150,23 @@ extern void alpha_start_function PARAMS ((FILE *, const char *, tree));
 extern void alpha_end_function PARAMS ((FILE *, const char *, tree));
 extern void alpha_encode_section_info PARAMS ((tree));
 #endif /* TREE CODE */
+
+#ifdef RTX_CODE
+extern rtx unicosmk_add_call_info_word PARAMS ((rtx));
+#endif
+
+#if TARGET_ABI_UNICOSMK
+#ifdef RTX_CODE
+extern void unicosmk_defer_case_vector PARAMS ((rtx, rtx));
+#endif
+#ifdef TREE_CODE
+extern void unicosmk_unique_section PARAMS ((tree, int));
+#endif
+extern void unicosmk_add_extern PARAMS ((const char *));
+extern void unicosmk_output_align PARAMS ((FILE *, int));
+extern char * unicosmk_text_section PARAMS ((void));
+extern char * unicosmk_data_section PARAMS ((void));
+extern void unicosmk_asm_file_start PARAMS ((FILE *));
+extern void unicosmk_asm_file_end PARAMS ((FILE *));
+extern void unicosmk_output_common PARAMS ((FILE *, const char *, int, int));
+#endif /* TARGET_ABI_UNICOSMK */
index aba367294d7a7bd1a40581e1f8b901ed3b030eff..8ee718f29fd1554b233d32fa776ee3da08493ac9 100644 (file)
@@ -153,8 +153,22 @@ static int alpha_issue_rate
 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.  */
-#if TARGET_ABI_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
@@ -176,6 +190,17 @@ static void vms_asm_out_destructor PARAMS ((rtx, int));
 # 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_FUNCTION_END_PROLOGUE
 #define TARGET_ASM_FUNCTION_END_PROLOGUE alpha_output_function_end_prologue
 
@@ -218,20 +243,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)
@@ -308,6 +363,12 @@ override_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)
     {
@@ -402,6 +463,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.  */
@@ -774,10 +844,13 @@ current_file_function_operand (op, mode)
 int
 local_symbolic_operand (op, mode)
      rtx op;
-     enum machine_mode mode ATTRIBUTE_UNUSED;
+     enum machine_mode mode;
 {
   const char *str;
 
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
   if (GET_CODE (op) == LABEL_REF)
     return 1;
 
@@ -813,6 +886,8 @@ call_operand (op, mode)
   if (mode != Pmode)
     return 0;
 
+  if (TARGET_ABI_UNICOSMK)
+    return GET_CODE (op) == REG;
   if (GET_CODE (op) == SYMBOL_REF)
     return 1;
   if (GET_CODE (op) == REG)
@@ -826,6 +901,26 @@ call_operand (op, mode)
   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
    comparisons are valid in which insn.  */
 
@@ -1140,7 +1235,7 @@ addition_operation (op, mode)
 int
 direct_return ()
 {
-  return (! TARGET_ABI_OPEN_VMS
+  return (! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK
          && reload_completed
          && alpha_sa_size () == 0
          && get_frame_size () == 0
@@ -1582,7 +1677,11 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
      data in a different alias set.  */
   set_mem_alias_set (*paligned_mem, 0);
 
-  *pbitnum = GEN_INT ((offset & 3) * 8);
+  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.  
@@ -1912,7 +2011,7 @@ 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. */
-      
+
       if ((bits = (MIN (HOST_BITS_PER_WIDE_INT, GET_MODE_SIZE (mode) * 8)
                   - floor_log2 (~ c) - 2)) > 0)
        for (; bits > 0; bits--)
@@ -3197,12 +3296,23 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
   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 (mema, -1));
+
+      emit_insn (gen_extqh_be (extl, meml, addr));
+      emit_insn (gen_extxl_be (exth, memh, GEN_INT (64), addr));
+
+      addr = expand_binop (DImode, ior_optab, extl, exth, tgt, 1, OPTAB_WIDEN);
+      addr = expand_binop (DImode, ashr_optab, addr, GEN_INT (64 - size*8),
+                          addr, 1, OPTAB_WIDEN);
+    }
+  else if (sign && size == 2)
     {
       emit_move_insn (addr, plus_constant (mema, ofs+2));
 
-      emit_insn (gen_extxl (extl, meml, GEN_INT (64), addr));
-      emit_insn (gen_extqh (exth, memh, addr));
+      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
@@ -3213,27 +3323,55 @@ alpha_expand_unaligned_load (tgt, mem, size, ofs, sign)
     }
   else
     {
-      emit_move_insn (addr, plus_constant (mema, 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),
@@ -3281,47 +3419,94 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
 
   emit_move_insn (dsth, memh);
   emit_move_insn (dstl, meml);
-  addr = copy_addr_to_reg (plus_constant (dsta, 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 = immed_double_const (0xffffffffffffffff, 0, DImode);
+#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 = immed_double_const (0xffffffffffffffff, 0, DImode);
 #endif
-       emit_insn (gen_mskxl (dstl, dstl, msk, addr));
-      }
-      break;
+           emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
+         }
+         break;
+       }
     }
 
   if (src != const0_rtx)
@@ -3329,10 +3514,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
@@ -3397,11 +3590,20 @@ alpha_expand_unaligned_load_words (out_regs, smem, words, ofs)
   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,
@@ -3468,12 +3670,22 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
 
   /* Shift the input data into place.  */
   dreg = copy_addr_to_reg (dmema);
+  if (WORDS_BIG_ENDIAN)
+    emit_move_insn (dreg, plus_constant (dreg, 7));
   if (data_regs != NULL)
     {
       for (i = words-1; i >= 0; --i)
        {
-         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)
        {
@@ -3484,8 +3696,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)
     {
@@ -3496,17 +3716,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(dmema, i*8),
+                                            plus_constant(dmema,
+                                            WORDS_BIG_ENDIAN ? i*8-1 : i*8),
                                             im8));
       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);
 }
 
 
@@ -4312,6 +4539,45 @@ alpha_variable_issue (dump, verbose, insn, cim)
 }
 
 \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.  */
@@ -4478,8 +4744,8 @@ print_operand (file, x, code)
        const char *round = get_round_mode_suffix ();
 
        if (trap || round)
-         fprintf (file, "%s%s", (trap ? trap : ""), (round ? round : ""));
-
+         fprintf (file, (TARGET_AS_SLASH_BEFORE_SUFFIX ? "/%s%s" : "%s%s"),
+                  (trap ? trap : ""), (round ? round : ""));
        break;
       }
 
@@ -4648,13 +4914,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':
@@ -4668,6 +4941,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.  */
       {
@@ -4878,32 +5163,106 @@ function_arg (cum, mode, type, named)
   int basereg;
   int num_args;
 
+  /* 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);
+    {
+      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;
+      num_args = cum.num_args;
+      if (num_args >= 6 || MUST_PASS_IN_STACK (mode, type))
+       return NULL_RTX;
+    }
 #else
-  if (cum >= 6)
-    return NULL_RTX;
-  num_args = cum;
+#if TARGET_ABI_UNICOSMK
+    {
+      int size;
 
-  /* 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;
+      /* 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 | (cum.num_args << 52) | (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 */
-  else if (TARGET_FPREGS
-          && (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
-              || GET_MODE_CLASS (mode) == MODE_FLOAT))
-    basereg = 32 + 16;
-  else
-    basereg = 16;
 
   return gen_rtx_REG (mode, num_args + basereg);
 }
@@ -4913,7 +5272,7 @@ alpha_build_va_list ()
 {
   tree base, ofs, record, type_decl;
 
-  if (TARGET_ABI_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
     return ptr_type_node;
 
   record = make_lang_type (RECORD_TYPE);
@@ -4950,7 +5309,7 @@ alpha_va_start (stdarg_p, valist, nextarg)
   if (TREE_CODE (TREE_TYPE (valist)) == ERROR_MARK)
     return;
 
-  if (TARGET_ABI_OPEN_VMS)
+  if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
     std_expand_builtin_va_start (stdarg_p, valist, nextarg);
 
   /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base
@@ -4998,7 +5357,7 @@ alpha_va_arg (valist, type)
   tree wide_type, wide_ofs;
   int indirect = 0;
 
-  if (TARGET_ABI_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;
@@ -5067,7 +5426,7 @@ alpha_va_arg (valist, type)
    descriptior to generate. */
 
 /* Nonzero if we need a stack procedure.  */
-static int vms_is_stack_procedure;
+static int alpha_is_stack_procedure;
 
 /* Register number (either FP or SP) that is used to unwind the frame.  */
 static int vms_unwind_regno;
@@ -5095,13 +5454,14 @@ alpha_sa_mask (imaskP, fmaskP)
   if (!current_function_is_thunk)
 #endif
     {
-      if (TARGET_ABI_OPEN_VMS && vms_is_stack_procedure)
+      if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
        imask |= (1L << HARD_FRAME_POINTER_REGNUM);
 
       /* One for every register we have to save.  */
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        if (! fixed_regs[i] && ! call_used_regs[i]
-           && regs_ever_live[i] && i != REG_RA)
+           && regs_ever_live[i] && i != REG_RA
+           && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
          {
            if (i < 32)
              imask |= (1L << i);
@@ -5120,9 +5480,15 @@ alpha_sa_mask (imaskP, fmaskP)
              imask |= 1L << regno;
            }
        }
-
-      if (imask || fmask || alpha_ra_ever_killed ())
-       imask |= (1L << REG_RA);
+     
+      if (!TARGET_ABI_UNICOSMK)
+       {
+         /* 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;
@@ -5141,19 +5507,55 @@ alpha_sa_size ()
   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++;
+      if (TARGET_ABI_UNICOSMK)
+       {
+         for (i = 9; i < 15 && sa_size == 0; i++)
+           if (! fixed_regs[i] && ! call_used_regs[i]
+               && regs_ever_live[i])
+             sa_size = 14;
+         for (i = 32 + 2; i < 32 + 10 && sa_size == 0; i++)
+           if (! fixed_regs[i] && ! call_used_regs[i]
+               && regs_ever_live[i])
+             sa_size = 14;
+       }
+      else
+       {
+         /* 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++;
+       }
     }
 
-  if (TARGET_ABI_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_is_stack_procedure = sa_size != 0
+                               || alpha_ra_ever_killed ()
+                               || get_frame_size() != 0
+                               || current_function_outgoing_args_size
+                               || current_function_varargs
+                               || current_function_stdarg
+                               || current_function_calls_alloca
+                               || frame_pointer_needed;
+
+      /* Always reserve space for saving callee-saved registers if we
+        need a frame as required by the calling convention.  */
+      if (alpha_is_stack_procedure)
+        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 ();
+      alpha_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed ();
 
       /* 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
@@ -5161,7 +5563,7 @@ alpha_sa_size ()
         Otherwise, start by assuming we can use FP.  */
       vms_base_regno = (frame_pointer_needed
                        || current_function_has_nonlocal_label
-                       || vms_is_stack_procedure
+                       || alpha_is_stack_procedure
                        || current_function_outgoing_args_size
                        ? REG_PV : HARD_FRAME_POINTER_REGNUM);
 
@@ -5175,21 +5577,21 @@ alpha_sa_size ()
            vms_save_fp_regno = i;
 
       if (vms_save_fp_regno == -1)
-       vms_base_regno = REG_PV, vms_is_stack_procedure = 1;
+       vms_base_regno = REG_PV, alpha_is_stack_procedure = 1;
 
       /* 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_is_stack_procedure)
        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 ())
+      if (!TARGET_ABI_UNICOSMK && (sa_size != 0 || alpha_ra_ever_killed ()))
        sa_size++;
 
       /* Our size must be even (multiple of 16 bytes).  */
@@ -5204,7 +5606,7 @@ int
 alpha_pv_save_size ()
 {
   alpha_sa_size ();
-  return vms_is_stack_procedure ? 8 : 0;
+  return alpha_is_stack_procedure ? 8 : 0;
 }
 
 int
@@ -5243,8 +5645,8 @@ alpha_does_function_need_gp ()
 {
   rtx insn;
 
-  /* We never need a GP for Windows/NT or VMS.  */
-  if (TARGET_ABI_WINDOWS_NT || TARGET_ABI_OPEN_VMS)
+  /* The GP being variable is an OSF abi thing.  */
+  if (! TARGET_ABI_OSF)
     return 0;
 
   if (TARGET_PROFILING_NEEDS_GP && profile_flag)
@@ -5358,9 +5760,15 @@ alpha_expand_prologue ()
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_is_stack_procedure ? 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_is_stack_procedure ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                               + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
@@ -5388,7 +5796,10 @@ alpha_expand_prologue ()
      don't represent the call as a call.  */
   if (TARGET_PROFILING_NEEDS_GP && profile_flag)
     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
@@ -5405,7 +5816,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.  */
@@ -5415,7 +5828,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
     {
@@ -5432,7 +5847,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.  */
@@ -5479,66 +5895,98 @@ 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_ABI_OPEN_VMS && vms_is_stack_procedure)
-    {
-      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 regs in stack order.  Beginning with VMS PV.  */
+      if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+       {
+         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));
-      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;
-    }
+      /* 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));
-       set_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));
-       set_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_is_stack_procedure)
+    {
+      /* 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_ABI_OPEN_VMS)
     {
-      if (!vms_is_stack_procedure)
+      if (!alpha_is_stack_procedure)
        /* 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),
@@ -5559,7 +6007,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)
@@ -5607,15 +6055,28 @@ 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_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_is_stack_procedure ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
+  else if (TARGET_ABI_UNICOSMK)
+    frame_size = ALPHA_ROUND (sa_size
+                             + (alpha_is_stack_procedure ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                             + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
@@ -5639,15 +6100,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_ABI_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);
@@ -5666,13 +6132,19 @@ alpha_start_function (file, fnname, decl)
   strcpy (entry_label, fnname);
   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_ABI_OPEN_VMS)
     fprintf (file, "\t.base $%d\n", vms_base_regno);
 
-  if (!TARGET_ABI_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
@@ -5688,7 +6160,9 @@ 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_ABI_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,
@@ -5708,15 +6182,17 @@ alpha_start_function (file, fnname, decl)
     }
 
   /* Describe which registers were spilled.  */
-  if (TARGET_ABI_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_is_stack_procedure)
        fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
     }
   else if (!flag_inhibit_size_directive)
@@ -5760,7 +6236,7 @@ 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_is_stack_procedure ? "stack" : "reg");
   alpha_need_linkage (fnname, 1);
   text_section ();
 #endif
@@ -5772,7 +6248,9 @@ static void
 alpha_output_function_end_prologue (file)
      FILE *file;
 {
-  if (TARGET_ABI_OPEN_VMS)
+  if (TARGET_ABI_UNICOSMK)
+    ;
+  else if (TARGET_ABI_OPEN_VMS)
     fputs ("\t.prologue\n", file);
   else if (TARGET_ABI_WINDOWS_NT)
     fputs ("\t.prologue 0\n", file);
@@ -5811,9 +6289,14 @@ alpha_expand_epilogue ()
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (vms_is_stack_procedure ? 8 : 0)
+                             + (alpha_is_stack_procedure ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
+  else if (TARGET_ABI_UNICOSMK)
+    frame_size = ALPHA_ROUND (sa_size
+                             + (alpha_is_stack_procedure ? 48 : 0))
+                + ALPHA_ROUND (frame_size
+                             + current_function_outgoing_args_size);
   else
     frame_size = (ALPHA_ROUND (current_function_outgoing_args_size)
                  + sa_size
@@ -5827,7 +6310,7 @@ alpha_expand_epilogue ()
 
   alpha_sa_mask (&imask, &fmask);
 
-  fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && vms_is_stack_procedure)
+  fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
                         || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
   fp_offset = 0;
   sa_reg = stack_pointer_rtx;
@@ -5837,7 +6320,7 @@ 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_ABI_OPEN_VMS
@@ -5895,6 +6378,38 @@ alpha_expand_epilogue ()
            reg_offset += 8;
          }
     }
+  else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+    {
+      /* 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)
     {
@@ -5910,8 +6425,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;
@@ -5944,7 +6466,15 @@ 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));
@@ -5960,17 +6490,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_ABI_OPEN_VMS && !vms_is_stack_procedure)
+      if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure)
         {
           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_is_stack_procedure)
+       {
+         /* 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))));
+        }
     }
 }
 
@@ -5983,7 +6525,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);
@@ -6000,6 +6542,13 @@ alpha_end_function (file, fnname, decl)
   if (!DECL_WEAK (current_function_decl)
       && (!flag_pic || !TREE_PUBLIC (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);
+    }
 }
 \f
 /* Debugging support.  */
@@ -7032,7 +7581,7 @@ check_float_value (mode, d, overflow)
 
   return 0;
 }
-
+\f
 #if TARGET_ABI_OPEN_VMS
 
 /* Return the VMS argument type corresponding to MODE.  */
@@ -7296,3 +7845,801 @@ alpha_need_linkage (name, is_local)
 }
 
 #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));
+
+
+/* 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_is_stack_procedure)
+    {
+      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;
+  char *ssib_name;
+  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 *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 */
index 220eb6235a7af0589182965ca3b6330d8eb1c873..3b030b27002885e03ff145660256daacd746a88d 100644 (file)
@@ -179,11 +179,17 @@ extern enum alpha_fp_trap_mode alpha_fptm;
 /* These are for target os support and cannot be changed at runtime.  */
 #define TARGET_ABI_WINDOWS_NT 0
 #define TARGET_ABI_OPEN_VMS 0
-#define TARGET_ABI_OSF (!TARGET_ABI_WINDOWS_NT && !TARGET_ABI_OPEN_VMS)
+#define TARGET_ABI_UNICOSMK 0
+#define TARGET_ABI_OSF (!TARGET_ABI_WINDOWS_NT \
+                       && !TARGET_ABI_OPEN_VMS \
+                       && !TARGET_ABI_UNICOSMK)
 
 #ifndef TARGET_AS_CAN_SUBTRACT_LABELS
 #define TARGET_AS_CAN_SUBTRACT_LABELS TARGET_GAS
 #endif
+#ifndef TARGET_AS_SLASH_BEFORE_SUFFIX
+#define TARGET_AS_SLASH_BEFORE_SUFFIX TARGET_GAS
+#endif
 #ifndef TARGET_CAN_FAULT_IN_PROLOGUE
 #define TARGET_CAN_FAULT_IN_PROLOGUE 0
 #endif
@@ -792,7 +798,9 @@ enum reg_class { NO_REGS, PV_REG, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
    `R' is a SYMBOL_REF that has SYMBOL_REF_FLAG set or is the current
    function.
 
-   'S' is a 6-bit constant (valid for a shift insn).  */
+   'S' is a 6-bit constant (valid for a shift insn).  
+
+   'U' is a symbolic operand.  */
 
 #define EXTRA_CONSTRAINT(OP, C)                                \
   ((C) == 'Q' ? normal_memory_operand (OP, VOIDmode)                   \
@@ -800,6 +808,8 @@ enum reg_class { NO_REGS, PV_REG, GENERAL_REGS, FLOAT_REGS, ALL_REGS,
    : (C) == 'S' ? (GET_CODE (OP) == CONST_INT                          \
                   && (unsigned HOST_WIDE_INT) INTVAL (OP) < 64)        \
    : (C) == 'T' ? GET_CODE (OP) == HIGH                                        \
+   : (TARGET_ABI_UNICOSMK && (C) == 'U')                               \
+               ? symbolic_operand (OP, VOIDmode)                       \
    : 0)
 
 /* Given an rtx X being reloaded into a reg required to be
@@ -2174,7 +2184,8 @@ do {                                                                      \
   {"hard_int_register_operand", {SUBREG, REG}},                                \
   {"reg_not_elim_operand", {SUBREG, REG}},                             \
   {"reg_no_subreg_operand", {REG}},                                    \
-  {"addition_operation", {PLUS}},
+  {"addition_operation", {PLUS}},                                      \
+  {"symbolic_operand", {SYMBOL_REF, LABEL_REF, CONST}},
 \f
 /* Define the `__builtin_va_list' type for the ABI.  */
 #define BUILD_VA_LIST_TYPE(VALIST) \
index 3cce9794b24f291a3a994336f4527832028b3ffa..34280f7f772d60e66b85e74bcd4bb0c52fc05c17 100644 (file)
    (UNSPEC_MSKXH       3)
    (UNSPEC_CVTQL       4)
    (UNSPEC_NT_LDA      5)
+   (UNSPEC_UMK_LAUM    6)
+   (UNSPEC_UMK_LALM    7)
+   (UNSPEC_UMK_LAL     8)
+   (UNSPEC_UMK_LOAD_CIW        9)
   ])
 
 ;; UNSPEC_VOLATILE:
    (UNSPECV_LDGP2      10)
    (UNSPECV_FORCE_MOV  11)
   ])
+
+;; Where necessary, the suffixes _le and _be are used to distinguish between
+;; little-endian and big-endian patterns.
+;;
+;; Note that the Unicos/Mk assembler does not support the following
+;; opcodes: mov, fmov, nop, fnop, unop.
 \f
 ;; Processor type -- this attribute must exactly match the processor_type
 ;; enumeration in alpha.h.
@@ -904,11 +914,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   ""
   "subqv %r1,%2,%0")
 
+;; The Unicos/Mk assembler doesn't support mull.
+
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
                 (match_operand:SI 2 "reg_or_8bit_operand" "rI")))]
-  ""
+  "!TARGET_ABI_UNICOSMK"
   "mull %r1,%2,%0"
   [(set_attr "type" "imul")
    (set_attr "opsize" "si")])
@@ -918,7 +930,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
        (sign_extend:DI
          (mult:SI (match_operand:SI 1 "reg_or_0_operand" "%rJ")
                   (match_operand:SI 2 "reg_or_8bit_operand" "rI"))))]
-  ""
+  "!TARGET_ABI_UNICOSMK"
   "mull %r1,%2,%0"
   [(set_attr "type" "imul")
    (set_attr "opsize" "si")])
@@ -932,7 +944,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                (sign_extend:DI (mult:SI (match_dup 1)
                                         (match_dup 2))))
            (const_int 0))]
-  ""
+  "!TARGET_ABI_UNICOSMK"
   "mullv %r1,%2,%0"
   [(set_attr "type" "imul")
    (set_attr "opsize" "si")])
@@ -984,14 +996,17 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   [(set_attr "type" "imul")
    (set_attr "opsize" "udi")])
 \f
-;; The divide and remainder operations always take their inputs from
-;; r24 and r25, put their output in r27, and clobber r23 and r28.
-
-;; ??? Force sign-extension here because some versions of OSF/1 don't
-;; do the right thing if the inputs are not properly sign-extended.
-;; But Linux, for instance, does not have this problem.  Is it worth
-;; the complication here to eliminate the sign extension?
-;; Interix/NT has the same sign-extension problem.
+;; The divide and remainder operations take their inputs from r24 and
+;; r25, put their output in r27, and clobber r23 and r28 on all
+;; systems except Unicos/Mk. On Unicos, the standard library provides
+;; subroutines which use the standard calling convention and work on
+;; DImode operands.
+
+;; ??? Force sign-extension here because some versions of OSF/1 and
+;; Interix/NT don't do the right thing if the inputs are not properly
+;; sign-extended.  But Linux, for instance, does not have this
+;; problem.  Is it worth the complication here to eliminate the sign
+;; extension?
 
 (define_expand "divsi3"
   [(set (reg:DI 24)
@@ -1004,7 +1019,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:SI 0 "nonimmediate_operand" "")
        (subreg:SI (reg:DI 27) 0))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "udivsi3"
@@ -1018,7 +1033,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:SI 0 "nonimmediate_operand" "")
        (subreg:SI (reg:DI 27) 0))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "modsi3"
@@ -1032,7 +1047,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:SI 0 "nonimmediate_operand" "")
        (subreg:SI (reg:DI 27) 0))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "umodsi3"
@@ -1046,7 +1061,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:SI 0 "nonimmediate_operand" "")
        (subreg:SI (reg:DI 27) 0))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "divdi3"
@@ -1059,7 +1074,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:DI 0 "nonimmediate_operand" "")
        (reg:DI 27))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "udivdi3"
@@ -1072,10 +1087,23 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:DI 0 "nonimmediate_operand" "")
        (reg:DI 27))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
 (define_expand "moddi3"
+  [(use (match_operand:DI 0 "nonimmediate_operand" ""))
+   (use (match_operand:DI 1 "input_operand" ""))
+   (use (match_operand:DI 2 "input_operand" ""))]
+  "!TARGET_ABI_OPEN_VMS"
+{
+  if (TARGET_ABI_UNICOSMK)
+    emit_insn (gen_moddi3_umk (operands[0], operands[1], operands[2]));
+  else
+    emit_insn (gen_moddi3_dft (operands[0], operands[1], operands[2]));
+  DONE;
+})
+
+(define_expand "moddi3_dft"
   [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
    (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
    (parallel [(set (reg:DI 27)
@@ -1085,10 +1113,48 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:DI 0 "nonimmediate_operand" "")
        (reg:DI 27))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
+;; On Unicos/Mk, we do as the system's C compiler does:
+;; compute the quotient, multiply and subtract.
+
+(define_expand "moddi3_umk"
+  [(use (match_operand:DI 0 "nonimmediate_operand" ""))
+   (use (match_operand:DI 1 "input_operand" ""))
+   (use (match_operand:DI 2 "input_operand" ""))]
+  "TARGET_ABI_UNICOSMK"
+{
+  rtx mul, div, tmp;
+
+  mul = gen_reg_rtx (DImode);
+  tmp = gen_reg_rtx (DImode);
+  operands[1] = force_reg (DImode, operands[1]);
+  operands[2] = force_reg (DImode, operands[2]);
+
+  div = expand_binop (DImode, sdiv_optab, operands[1], operands[2],
+                     NULL_RTX, 0, OPTAB_LIB);
+  div = force_reg (DImode, div);
+  emit_insn (gen_muldi3 (mul, operands[2], div));
+  emit_insn (gen_subdi3 (tmp, operands[1], mul));
+  emit_move_insn (operands[0], tmp);
+  DONE;
+})
+
 (define_expand "umoddi3"
+  [(use (match_operand:DI 0 "nonimmediate_operand" ""))
+   (use (match_operand:DI 1 "input_operand" ""))
+   (use (match_operand:DI 2 "input_operand" ""))]
+  "! TARGET_ABI_OPEN_VMS"
+{
+  if (TARGET_ABI_UNICOSMK)
+    emit_insn (gen_umoddi3_umk (operands[0], operands[1], operands[2]));
+  else
+    emit_insn (gen_umoddi3_dft (operands[0], operands[1], operands[2]));
+  DONE;
+})
+
+(define_expand "umoddi3_dft"
   [(set (reg:DI 24) (match_operand:DI 1 "input_operand" ""))
    (set (reg:DI 25) (match_operand:DI 2 "input_operand" ""))
    (parallel [(set (reg:DI 27)
@@ -1098,9 +1164,31 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
              (clobber (reg:DI 28))])
    (set (match_operand:DI 0 "nonimmediate_operand" "")
        (reg:DI 27))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "")
 
+(define_expand "umoddi3_umk"
+  [(use (match_operand:DI 0 "nonimmediate_operand" ""))
+   (use (match_operand:DI 1 "input_operand" ""))
+   (use (match_operand:DI 2 "input_operand" ""))]
+  "TARGET_ABI_UNICOSMK"
+{
+  rtx mul, div, tmp;
+
+  mul = gen_reg_rtx (DImode);
+  tmp = gen_reg_rtx (DImode);
+  operands[1] = force_reg (DImode, operands[1]);
+  operands[2] = force_reg (DImode, operands[2]);
+
+  div = expand_binop (DImode, udiv_optab, operands[1], operands[2],
+                     NULL_RTX, 1, OPTAB_LIB);
+  div = force_reg (DImode, div);
+  emit_insn (gen_muldi3 (mul, operands[2], div));
+  emit_insn (gen_subdi3 (tmp, operands[1], mul));
+  emit_move_insn (operands[0], tmp);
+  DONE;
+})
+
 ;; Lengths of 8 for ldq $t12,__divq($gp); jsr $t9,($t12),__divq as
 ;; expanded by the assembler.
 
@@ -1121,7 +1209,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                        [(reg:DI 24) (reg:DI 25)])))
    (clobber (reg:DI 23))
    (clobber (reg:DI 28))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "%E0 $24,$25,$27"
   [(set_attr "type" "jsr")
    (set_attr "length" "8")])
@@ -1143,7 +1231,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                        [(reg:DI 24) (reg:DI 25)]))
    (clobber (reg:DI 23))
    (clobber (reg:DI 28))]
-  "! TARGET_ABI_OPEN_VMS"
+  "! TARGET_ABI_OPEN_VMS && ! TARGET_ABI_UNICOSMK"
   "%E0 $24,$25,$27"
   [(set_attr "type" "jsr")
    (set_attr "length" "8")])
@@ -1655,6 +1743,18 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 ;;
 ;; Operand 1 is the address + 1 (+2 for HI), operand 0 is the result.
 (define_expand "unaligned_extendqidi"
+  [(use (match_operand:QI 0 "register_operand" ""))
+   (use (match_operand:DI 1 "address_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_extendqidi_be (operands[0], operands[1]));
+  else
+    emit_insn (gen_unaligned_extendqidi_le (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "unaligned_extendqidi_le"
   [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
    (set (match_dup 3)
        (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -1))
@@ -1667,14 +1767,51 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                              (const_int 3)))))
    (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
        (ashiftrt:DI (match_dup 4) (const_int 56)))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+{
+  operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (DImode);
+})
+
+(define_expand "unaligned_extendqidi_be"
+  [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+   (set (match_dup 3) (plus:DI (match_dup 2) (const_int -1)))
+   (set (match_dup 4)
+       (mem:DI (and:DI (match_dup 3)
+                       (const_int -8))))
+   (set (match_dup 5) (plus:DI (match_dup 2) (const_int -2)))
+   (set (match_dup 6)
+       (ashift:DI (match_dup 4)
+                  (ashift:DI
+                    (and:DI
+                      (plus:DI (match_dup 5) (const_int 1))
+                      (const_int 7))
+                    (const_int 3))))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (ashiftrt:DI (match_dup 6) (const_int 56)))]
+  "WORDS_BIG_ENDIAN"
 {
   operands[2] = gen_reg_rtx (DImode);
   operands[3] = gen_reg_rtx (DImode);
   operands[4] = gen_reg_rtx (DImode);
+  operands[5] = gen_reg_rtx (DImode);
+  operands[6] = gen_reg_rtx (DImode);
 })
 
 (define_expand "unaligned_extendhidi"
+  [(use (match_operand:QI 0 "register_operand" ""))
+   (use (match_operand:DI 1 "address_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_extendhidi_be (operands[0], operands[1]));
+  else
+    emit_insn (gen_unaligned_extendhidi_le (operands[0], operands[1]));
+  DONE;
+})
+
+(define_expand "unaligned_extendhidi_le"
   [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
    (set (match_dup 3)
        (mem:DI (and:DI (plus:DI (match_dup 2) (const_int -2))
@@ -1687,13 +1824,36 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                              (const_int 3)))))
    (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
        (ashiftrt:DI (match_dup 4) (const_int 48)))]
-  ""
+  "! WORDS_BIG_ENDIAN"
 {
   operands[2] = gen_reg_rtx (DImode);
   operands[3] = gen_reg_rtx (DImode);
   operands[4] = gen_reg_rtx (DImode);
 })
 
+(define_expand "unaligned_extendhidi_be"
+  [(set (match_dup 2) (match_operand:DI 1 "address_operand" ""))
+   (set (match_dup 3) (plus:DI (match_dup 2) (const_int -2)))
+   (set (match_dup 4)
+       (mem:DI (and:DI (match_dup 3)
+                       (const_int -8))))
+   (set (match_dup 5) (plus:DI (match_dup 2) (const_int -3)))
+   (set (match_dup 6)
+       (ashift:DI (match_dup 4)
+                  (ashift:DI
+                    (and:DI (match_dup 5) (const_int 7))
+                    (const_int 8))))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (ashiftrt:DI (match_dup 6) (const_int 48)))]
+  "WORDS_BIG_ENDIAN"
+{
+  operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+  operands[4] = gen_reg_rtx (DImode);
+  operands[5] = gen_reg_rtx (DImode);
+  operands[6] = gen_reg_rtx (DImode);
+})
+
 (define_insn "*extxl_const"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -1703,13 +1863,26 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   "ext%M2l %r1,%s3,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "extxl"
+(define_insn "extxl_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                         (match_operand:DI 2 "mode_width_operand" "n")
                         (ashift:DI (match_operand:DI 3 "reg_or_8bit_operand" "rI")
                                    (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "ext%M2l %r1,%3,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "extxl_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (zero_extract:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                        (match_operand:DI 2 "mode_width_operand" "n")
+                        (minus:DI
+                          (const_int 56)
+                          (ashift:DI
+                            (match_operand:DI 3 "reg_or_8bit_operand" "rI")
+                            (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
   "ext%M2l %r1,%3,%0"
   [(set_attr "type" "shift")])
 
@@ -1717,26 +1890,50 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 ;; in shifts larger than a word size.  So capture these patterns that it
 ;; should have turned into zero_extracts.
 
-(define_insn "*extxl_1"
+(define_insn "*extxl_1_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (and:DI (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
                  (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                             (const_int 3)))
             (match_operand:DI 3 "mode_mask_operand" "n")))]
-  ""
+  "! WORDS_BIG_ENDIAN"
   "ext%U3l %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "*extql_2"
+(define_insn "*extxl_1_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (and:DI (lshiftrt:DI
+                 (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                 (minus:DI (const_int 56)
+                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                              (const_int 3))))
+               (match_operand:DI 3 "mode_mask_operand" "n")))]
+  "WORDS_BIG_ENDIAN"
+  "ext%U3l %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "*extql_2_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (lshiftrt:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
          (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                     (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
   "extql %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "extqh"
+(define_insn "*extql_2_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (lshiftrt:DI
+         (match_operand:DI 1 "reg_or_0_operand" "rJ")
+         (minus:DI (const_int 56)
+                   (ashift:DI
+                     (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                     (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
+  "extql %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "extqh_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -1746,11 +1943,25 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                      (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                      (const_int 7))
                     (const_int 3)))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
   "extqh %r1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "extlh"
+(define_insn "extqh_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI
+         (match_operand:DI 1 "reg_or_0_operand" "rJ")
+         (ashift:DI
+           (and:DI
+             (plus:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                      (const_int 1))
+             (const_int 7))
+           (const_int 3))))]
+  "WORDS_BIG_ENDIAN"
+  "extqh %r1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "extlh_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -1761,11 +1972,28 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                      (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                      (const_int 7))
                     (const_int 3)))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "extlh %r1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "extlh_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (and:DI
+         (ashift:DI
+           (match_operand:DI 1 "reg_or_0_operand" "rJ")
+           (ashift:DI
+             (and:DI
+               (plus:DI
+                 (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                 (const_int 1))
+               (const_int 7))
+             (const_int 3)))
+         (const_int 2147483647)))]
+  "WORDS_BIG_ENDIAN"
   "extlh %r1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "extwh"
+(define_insn "extwh_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI
         (and:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
@@ -1776,7 +2004,23 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                      (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                      (const_int 7))
                     (const_int 3)))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "extwh %r1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "extwh_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (and:DI
+         (ashift:DI (match_operand:DI 1 "reg_or_0_operand" "rJ")
+                    (ashift:DI
+                      (and:DI
+                        (plus:DI
+                          (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                          (const_int 1))
+                        (const_int 7))
+                      (const_int 3)))
+         (const_int 65535)))]
+  "WORDS_BIG_ENDIAN"
   "extwh %r1,%2,%0"
   [(set_attr "type" "shift")])
 
@@ -1830,39 +2074,79 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   "insll %1,%s2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "insbl"
+(define_insn "insbl_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                              (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "insbl %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "insbl_be"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" "r"))
+        (minus:DI (const_int 56)
+          (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                     (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
   "insbl %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "inswl"
+(define_insn "inswl_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                              (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
   "inswl %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "insll"
+(define_insn "inswl_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" "r"))
+         (minus:DI (const_int 56)
+           (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                      (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
+  "inswl %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "insll_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                              (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
   "insll %1,%2,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "insql"
+(define_insn "insll_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+         (minus:DI (const_int 56)
+           (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                      (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
+  "insll %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "insql_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (ashift:DI (match_operand:DI 1 "register_operand" "r")
                   (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
                              (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "insql %1,%2,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "insql_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (ashift:DI (match_operand:DI 1 "register_operand" "r")
+         (minus:DI (const_int 56)
+           (ashift:DI (match_operand:DI 2 "reg_or_8bit_operand" "rI")
+                      (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
   "insql %1,%2,%0"
   [(set_attr "type" "shift")])
 
@@ -1913,7 +2197,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   "ins%M2h %1,%3,%0"
   [(set_attr "type" "shift")])
 
-(define_insn "mskxl"
+(define_insn "mskxl_le"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (and:DI (not:DI (ashift:DI
                         (match_operand:DI 2 "mode_mask_operand" "n")
@@ -1921,7 +2205,20 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                          (match_operand:DI 3 "reg_or_8bit_operand" "rI")
                          (const_int 3))))
                (match_operand:DI 1 "reg_or_0_operand" "rJ")))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "msk%U2l %r1,%3,%0"
+  [(set_attr "type" "shift")])
+
+(define_insn "mskxl_be"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (and:DI (not:DI (ashift:DI
+                         (match_operand:DI 2 "mode_mask_operand" "n")
+                         (minus:DI (const_int 56)
+                           (ashift:DI
+                             (match_operand:DI 3 "reg_or_8bit_operand" "rI")
+                             (const_int 3)))))
+               (match_operand:DI 1 "reg_or_0_operand" "rJ")))]
+  "WORDS_BIG_ENDIAN"
   "msk%U2l %r1,%3,%0"
   [(set_attr "type" "shift")])
 
@@ -2328,6 +2625,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     operands[1] = force_reg (SFmode, operands[1]);
 })
 
+;; The Unicos/Mk assembler doesn't support cvtst, but we've already
+;; asserted that alpha_fptm == ALPHA_FPTM_N.
+
 (define_insn "*extendsfdf2_ieee"
   [(set (match_operand:DF 0 "register_operand" "=&f")
        (float_extend:DF (match_operand:SF 1 "register_operand" "f")))]
@@ -2341,7 +2641,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f,m,f")))]
   "TARGET_FP && alpha_fptm < ALPHA_FPTM_SU"
   "@
-   fmov %1,%0
+   cpys %1,%1,%0
    ld%, %0,%1
    st%- %1,%0"
   [(set_attr "type" "fcpys,fld,fst")])
@@ -4164,6 +4464,16 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 ;; Here are the CALL and unconditional branch insns.  Calls on NT and OSF
 ;; work differently, so we have different patterns for each.
 
+;; On Unicos/Mk a call information word (CIW) must be generated for each
+;; call. The CIW contains information about arguments passed in registers
+;; and is stored in the caller's SSIB. Its offset relative to the beginning
+;; of the SSIB is passed in $25. Handling this properly is quite complicated
+;; in the presence of inlining since the CIWs for calls performed by the
+;; inlined function must be stored in the SSIB of the function it is inlined
+;; into as well. We encode the CIW in an unspec and append it to the list
+;; of the CIWs for the current function only when the instruction for loading
+;; $25 is generated.
+
 (define_expand "call"
   [(use (match_operand:DI 0 "" ""))
    (use (match_operand 1 "" ""))
@@ -4175,6 +4485,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     emit_call_insn (gen_call_nt (operands[0], operands[1]));
   else if (TARGET_ABI_OPEN_VMS)
     emit_call_insn (gen_call_vms (operands[0], operands[2]));
+  else if (TARGET_ABI_UNICOSMK)
+    emit_call_insn (gen_call_umk (operands[0], operands[2]));
   else
     emit_call_insn (gen_call_osf (operands[0], operands[1]));
   DONE;
@@ -4225,6 +4537,30 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     operands[0] = force_reg (DImode, operands[0]);
 })
 
+;; Calls on Unicos/Mk are always indirect.
+;; op 0: symbol ref for called function
+;; op 1: CIW for $25 represented by an unspec
+
+(define_expand "call_umk"
+   [(parallel [(call (mem:DI (match_operand 0 "" ""))
+                    (match_operand 1 "" ""))
+              (use (reg:DI 25))
+              (clobber (reg:DI 26))])]
+   ""
+{
+  if (GET_CODE (operands[0]) != MEM)
+    abort ();
+
+  /* Always load the address of the called function into a register;
+     load the CIW in $25.  */
+
+  operands[0] = XEXP (operands[0], 0);
+  if (GET_CODE (operands[0]) != REG)
+    operands[0] = force_reg (DImode, operands[0]);
+
+  emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]);
+})
+
 ;;
 ;; call openvms/alpha
 ;; op 0: symbol ref for called function
@@ -4279,6 +4615,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   else if (TARGET_ABI_OPEN_VMS)
     emit_call_insn (gen_call_value_vms (operands[0], operands[1],
                                        operands[3]));
+  else if (TARGET_ABI_UNICOSMK)
+    emit_call_insn (gen_call_value_umk (operands[0], operands[1],
+                                       operands[3]));
   else
     emit_call_insn (gen_call_value_osf (operands[0], operands[1],
                                        operands[2]));
@@ -4369,6 +4708,24 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     }
 })
 
+(define_expand "call_value_umk"
+  [(parallel [(set (match_operand 0 "" "")
+                  (call (mem:DI (match_operand 1 "" ""))
+                        (match_operand 2 "" "")))
+             (use (reg:DI 25))
+             (clobber (reg:DI 26))])]
+  ""
+{
+  if (GET_CODE (operands[1]) != MEM)
+    abort ();
+
+  operands[1] = XEXP (operands[1], 0);
+  if (GET_CODE (operands[1]) != REG)
+    operands[1] = force_reg (DImode, operands[1]);
+
+  emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]);
+})
+
 (define_insn "*call_osf_1_er_noreturn"
   [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,i"))
         (match_operand 1 "" ""))
@@ -4455,6 +4812,15 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   [(set_attr "type" "jsr")
    (set_attr "length" "12,16")])
 
+(define_insn "*call_umk_1"
+  [(call (mem:DI (match_operand:DI 0 "call_operand" "r"))
+        (match_operand 1 "" ""))
+   (use (reg:DI 25))
+   (clobber (reg:DI 26))]
+  "TARGET_ABI_UNICOSMK"
+  "jsr $26,(%0)"
+  [(set_attr "type" "jsr")])
+
 ;; Call subroutine returning any type.
 
 (define_expand "untyped_call"
@@ -4517,58 +4883,30 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   [(set_attr "type" "ibr")])
 
 (define_expand "tablejump"
-  [(use (match_operand:SI 0 "register_operand" ""))
-   (use (match_operand:SI 1 "" ""))]
+  [(parallel [(set (pc)
+                  (match_operand 0 "register_operand" ""))
+             (use (label_ref:DI (match_operand 1 "" "")))])]
   ""
 {
   if (TARGET_ABI_WINDOWS_NT)
-    emit_jump_insn (gen_tablejump_nt (operands[0], operands[1]));
-  else if (TARGET_ABI_OPEN_VMS)
-    emit_jump_insn (gen_tablejump_vms (operands[0], operands[1]));
-  else
-    emit_jump_insn (gen_tablejump_osf (operands[0], operands[1]));
-
-  DONE;
+    {
+      rtx dest = gen_reg_rtx (DImode);
+      emit_insn (gen_extendsidi2 (dest, operands[0]));
+      operands[0] = dest;
+    }
+  else if (TARGET_ABI_OSF)
+    {
+      rtx dest = gen_reg_rtx (DImode);
+      emit_insn (gen_extendsidi2 (dest, operands[0]));
+      emit_insn (gen_adddi3 (dest, gen_rtx_REG (DImode, 29), dest));   
+      operands[0] = dest;
+    }
 })
 
-(define_expand "tablejump_osf"
-  [(set (match_dup 3)
-       (sign_extend:DI (match_operand:SI 0 "register_operand" "")))
-   (set (match_dup 3)
-       (plus:DI (reg:DI 29) (match_dup 3)))
-   (parallel [(set (pc)
-                  (match_dup 3))
-             (use (label_ref (match_operand 1 "" "")))])]
-  ""
-  { operands[3] = gen_reg_rtx (DImode); })
-
-(define_expand "tablejump_nt"
-  [(set (match_dup 3)
-       (sign_extend:DI (match_operand:SI 0 "register_operand" "")))
-   (parallel [(set (pc)
-                  (match_dup 3))
-             (use (label_ref (match_operand 1 "" "")))])]
-  ""
-  { operands[3] = gen_reg_rtx (DImode); })
-
-;;
-;; tablejump, openVMS way
-;; op 0: offset
-;; op 1: label preceding jump-table
-;;
-(define_expand "tablejump_vms"
-  [(set (match_dup 2)
-      (match_operand:DI 0 "register_operand" ""))
-        (set (pc)
-       (plus:DI (match_dup 2)
-               (label_ref (match_operand 1 "" ""))))]
-  ""
-  { operands[2] = gen_reg_rtx (DImode); })
-
 (define_insn "*tablejump_osf_nt_internal"
   [(set (pc)
        (match_operand:DI 0 "register_operand" "r"))
-   (use (label_ref (match_operand 1 "" "")))]
+   (use (label_ref:DI (match_operand 1 "" "")))]
   "(TARGET_ABI_OSF || TARGET_ABI_WINDOWS_NT)
    && alpha_tablejump_addr_vec (insn)"
 {
@@ -4577,16 +4915,11 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 }
   [(set_attr "type" "ibr")])
 
-;;
-;; op 0 is table offset
-;; op 1 is table label
-;;
-
-(define_insn "*tablejump_vms_internal"
+(define_insn "*tablejump_internal"
   [(set (pc)
-       (plus (match_operand:DI 0 "register_operand" "r")
-             (label_ref (match_operand 1 "" ""))))]
-  "TARGET_ABI_OPEN_VMS"
+       (match_operand:DI 0 "register_operand" "r"))
+   (use (label_ref (match_operand 1 "" "")))]
+  ""
   "jmp $31,(%0),0"
   [(set_attr "type" "ibr")])
 
@@ -4613,9 +4946,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], SFmode)
        || reg_or_fp0_operand (operands[1], SFmode))"
   "@
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%, %0,%1
-   mov %r1,%0
+   bis $31,%r1,%0
    ldl %0,%1
    st%, %R1,%0
    stl %r1,%0"
@@ -4628,9 +4961,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], SFmode)
        || reg_or_fp0_operand (operands[1], SFmode))"
   "@
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%, %0,%1
-   mov %r1,%0
+   bis $31,%r1,%0
    ldl %0,%1
    st%, %R1,%0
    stl %r1,%0
@@ -4645,7 +4978,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], SFmode)
        || reg_or_fp0_operand (operands[1], SFmode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    ldl %0,%1
    stl %r1,%0"
   [(set_attr "type" "ilog,ild,ist")])
@@ -4657,9 +4990,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], DFmode)
        || reg_or_fp0_operand (operands[1], DFmode))"
   "@
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%- %0,%1
-   mov %r1,%0
+   bis $31,%r1,%0
    ldq %0,%1
    st%- %R1,%0
    stq %r1,%0"
@@ -4672,9 +5005,9 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], DFmode)
        || reg_or_fp0_operand (operands[1], DFmode))"
   "@
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%- %0,%1
-   mov %r1,%0
+   bis $31,%r1,%0
    ldq %0,%1
    st%- %R1,%0
    stq %r1,%0
@@ -4689,7 +5022,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], DFmode)
        || reg_or_fp0_operand (operands[1], DFmode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    ldq %0,%1
    stq %r1,%0"
   [(set_attr "type" "ilog,ild,ist")])
@@ -4749,16 +5082,16 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 (define_insn "*movsi_nofix"
   [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,m,*f,*f,m")
        (match_operand:SI 1 "input_operand" "rJ,K,L,m,rJ,*fJ,m,*f"))]
-  "TARGET_ABI_OSF && ! TARGET_FIX
+  "(TARGET_ABI_OSF || TARGET_ABI_UNICOSMK) && ! TARGET_FIX
    && (register_operand (operands[0], SImode)
        || reg_or_0_operand (operands[1], SImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%1($31)
    ldah %0,%h1($31)
    ldl %0,%1
    stl %r1,%0
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%, %0,%1
    st%, %R1,%0"
   [(set_attr "type" "ilog,iadd,iadd,ild,ist,fcpys,fld,fst")])
@@ -4770,12 +5103,12 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], SImode)
        || reg_or_0_operand (operands[1], SImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%1($31)
    ldah %0,%h1($31)
    ldl %0,%1
    stl %r1,%0
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%, %0,%1
    st%, %R1,%0
    ftois %1,%0
@@ -4789,13 +5122,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     && (register_operand (operands[0], SImode)
         || reg_or_0_operand (operands[1], SImode))"
   "@
-   mov %1,%0
+   bis $31,%1,%0
    lda %0,%1
    ldah %0,%h1
    lda %0,%1
    ldl %0,%1
    stl %r1,%0
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ld%, %0,%1
    st%, %R1,%0"
   [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
@@ -4807,7 +5140,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%L1($31)"
   [(set_attr "type" "ilog,iadd")])
 
@@ -4818,7 +5151,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], HImode)
        || reg_or_0_operand (operands[1], HImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%L1($31)
    ldwu %0,%1
    stw %r1,%0"
@@ -4831,7 +5164,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%L1($31)"
   [(set_attr "type" "ilog,iadd")])
 
@@ -4842,7 +5175,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], QImode)
        || reg_or_0_operand (operands[1], QImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%L1($31)
    ldbu %0,%1
    stb %r1,%0"
@@ -4879,6 +5212,87 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
     FAIL;
 })
 
+;; Split the load of an address into a four-insn sequence on Unicos/Mk.
+;; Always generate a REG_EQUAL note for the last instruction to facilitate
+;; optimisations. If the symbolic operand is a label_ref, generate REG_LABEL
+;; notes and update LABEL_NUSES because this is not done automatically.
+;; Labels may be incorrectly deleted if we don't do this.
+;;
+;; Describing what the individual instructions do correctly is too complicated
+;; so use UNSPECs for each of the three parts of an address.
+
+(define_split
+  [(set (match_operand:DI 0 "register_operand" "")
+       (match_operand:DI 1 "symbolic_operand" ""))]
+  "TARGET_ABI_UNICOSMK && reload_completed"
+  [(const_int 0)]
+{
+  rtx insn1, insn2, insn3;
+
+  insn1 = emit_insn (gen_umk_laum (operands[0], operands[1]));
+  emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT (32)));
+  insn2 = emit_insn (gen_umk_lalm (operands[0], operands[0], operands[1]));
+  insn3 = emit_insn (gen_umk_lal (operands[0], operands[0], operands[1]));
+  REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_EQUAL, operands[1],
+                                        REG_NOTES (insn3));
+  if (GET_CODE (operands[1]) == LABEL_REF)
+    {
+      rtx label;
+
+      label = XEXP (operands[1], 0);
+      REG_NOTES (insn1) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+                                            REG_NOTES (insn1));
+      REG_NOTES (insn2) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+                                            REG_NOTES (insn2));
+      REG_NOTES (insn3) = gen_rtx_EXPR_LIST (REG_LABEL, label,
+                                            REG_NOTES (insn3));
+      LABEL_NUSES (label) += 3;
+    }
+  DONE;
+})
+
+;; Instructions for loading the three parts of an address on Unicos/Mk.
+
+(define_insn "umk_laum"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI [(match_operand:DI 1 "symbolic_operand" "")]
+                  UNSPEC_UMK_LAUM))]
+  "TARGET_ABI_UNICOSMK"
+  "laum %r0,%t1($31)"
+  [(set_attr "type" "iadd")])
+
+(define_insn "umk_lalm"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (plus:DI (match_operand:DI 1 "register_operand" "r")
+                (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
+                           UNSPEC_UMK_LALM)))] 
+  "TARGET_ABI_UNICOSMK"
+  "lalm %r0,%t2(%r1)"
+  [(set_attr "type" "iadd")])
+
+(define_insn "umk_lal"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (plus:DI (match_operand:DI 1 "register_operand" "r")
+                (unspec:DI [(match_operand:DI 2 "symbolic_operand" "")]
+                           UNSPEC_UMK_LAL)))]
+  "TARGET_ABI_UNICOSMK"
+  "lal %r0,%t2(%r1)"
+  [(set_attr "type" "iadd")])
+
+;; Add a new call information word to the current function's list of CIWs
+;; and load its index into $25. Doing it here ensures that the CIW will be
+;; associated with the correct function even in the presence of inlining.
+
+(define_insn "*umk_load_ciw"
+  [(set (reg:DI 25)
+       (unspec:DI [(match_operand 0 "" "")] UNSPEC_UMK_LOAD_CIW))]
+  "TARGET_ABI_UNICOSMK"
+{
+  operands[0] = unicosmk_add_call_info_word (operands[0]);
+  return "lda $25,%0";
+}
+  [(set_attr "type" "iadd")])
+
 (define_insn "*movdi_er_low"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (lo_sum:DI (match_operand:DI 1 "register_operand" "r")
@@ -4906,23 +5320,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    stt %R1,%0"
   [(set_attr "type" "ilog,iadd,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
 
+;; The 'U' constraint matches symbolic operands on Unicos/Mk. Those should
+;; have been split up by the rules above but we shouldn't reject the
+;; possibility of them getting through.
+
 (define_insn "*movdi_nofix"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,m,*f,*f,Q")
-       (match_operand:DI 1 "input_operand" "rJ,K,L,s,m,rJ,*fJ,Q,*f"))]
-  "! TARGET_EXPLICIT_RELOCS && ! TARGET_FIX
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q")
+       (match_operand:DI 1 "input_operand" "rJ,K,L,U,s,m,rJ,*fJ,Q,*f"))]
+  "! TARGET_FIX
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%1($31)
    ldah %0,%h1($31)
+   laum %0,%t1($31)\;sll %0,32,%0\;lalm %0,%t1(%0)\;lal %0,%t1(%0)
    lda %0,%1
    ldq%A1 %0,%1
    stq%A0 %r1,%0
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ldt %0,%1
    stt %R1,%0"
-  [(set_attr "type" "ilog,iadd,iadd,ldsym,ild,ist,fcpys,fld,fst")])
+  [(set_attr "type" "ilog,iadd,iadd,ldsym,ldsym,ild,ist,fcpys,fld,fst")
+   (set_attr "length" "*,*,*,16,*,*,*,*,*,*")])
 
 (define_insn "*movdi_er_fix"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,*f,*f,Q,r,*f")
@@ -4953,13 +5373,13 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
   "@
-   mov %r1,%0
+   bis $31,%r1,%0
    lda %0,%1($31)
    ldah %0,%h1($31)
    lda %0,%1
    ldq%A1 %0,%1
    stq%A0 %r1,%0
-   fmov %R1,%0
+   cpys %R1,%R1,%0
    ldt %0,%1
    stt %R1,%0
    ftoit %1,%0
@@ -5041,12 +5461,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   "")
 
 ;; Similar for unaligned loads, where we use the sequence from the
-;; Alpha Architecture manual.
+;; Alpha Architecture manual. We have to distinguish between little-endian
+;; and big-endian systems as the sequences are different.
 ;;
 ;; Operand 1 is the address.  Operands 2 and 3 are temporaries, where
 ;; operand 3 can overlap the input and output registers.
 
 (define_expand "unaligned_loadqi"
+  [(use (match_operand:QI 0 "register_operand" ""))
+   (use (match_operand:DI 1 "address_operand" ""))
+   (use (match_operand:DI 2 "register_operand" ""))
+   (use (match_operand:DI 3 "register_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_loadqi_be (operands[0], operands[1],
+                                       operands[2], operands[3]));
+  else
+    emit_insn (gen_unaligned_loadqi_le (operands[0], operands[1],
+                                       operands[2], operands[3]));
+  DONE;
+})
+
+(define_expand "unaligned_loadqi_le"
   [(set (match_operand:DI 2 "register_operand" "")
        (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
                        (const_int -8))))
@@ -5056,10 +5493,41 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
        (zero_extract:DI (match_dup 2)
                         (const_int 8)
                         (ashift:DI (match_dup 3) (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "")
+
+(define_expand "unaligned_loadqi_be"
+  [(set (match_operand:DI 2 "register_operand" "")
+       (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+                       (const_int -8))))
+   (set (match_operand:DI 3 "register_operand" "")
+       (match_dup 1))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (zero_extract:DI (match_dup 2)
+                        (const_int 8)
+                        (minus:DI
+                          (const_int 56)
+                          (ashift:DI (match_dup 3) (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
   "")
 
 (define_expand "unaligned_loadhi"
+  [(use (match_operand:QI 0 "register_operand" ""))
+   (use (match_operand:DI 1 "address_operand" ""))
+   (use (match_operand:DI 2 "register_operand" ""))
+   (use (match_operand:DI 3 "register_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_loadhi_be (operands[0], operands[1],
+                                       operands[2], operands[3]));
+  else
+    emit_insn (gen_unaligned_loadhi_le (operands[0], operands[1],
+                                       operands[2], operands[3]));
+  DONE;
+})
+
+(define_expand "unaligned_loadhi_le"
   [(set (match_operand:DI 2 "register_operand" "")
        (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
                        (const_int -8))))
@@ -5069,7 +5537,22 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
        (zero_extract:DI (match_dup 2)
                         (const_int 16)
                         (ashift:DI (match_dup 3) (const_int 3))))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "")
+
+(define_expand "unaligned_loadhi_be"
+  [(set (match_operand:DI 2 "register_operand" "")
+       (mem:DI (and:DI (match_operand:DI 1 "address_operand" "")
+                       (const_int -8))))
+   (set (match_operand:DI 3 "register_operand" "")
+       (plus:DI (match_dup 1) (const_int 1)))
+   (set (subreg:DI (match_operand:QI 0 "register_operand" "") 0)
+       (zero_extract:DI (match_dup 2)
+                        (const_int 16)
+                        (minus:DI
+                          (const_int 56)
+                          (ashift:DI (match_dup 3) (const_int 3)))))]
+  "WORDS_BIG_ENDIAN"
   "")
 
 ;; Storing an aligned byte or word requires two temporaries.  Operand 0 is the
@@ -5102,6 +5585,25 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 ;; operand 2 can be that register.
 
 (define_expand "unaligned_storeqi"
+  [(use (match_operand:DI 0 "address_operand" ""))
+   (use (match_operand:QI 1 "register_operand" ""))
+   (use (match_operand:DI 2 "register_operand" ""))
+   (use (match_operand:DI 3 "register_operand" ""))
+   (use (match_operand:DI 4 "register_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_storeqi_be (operands[0], operands[1],
+                                        operands[2], operands[3],
+                                        operands[4]));
+  else
+    emit_insn (gen_unaligned_storeqi_le (operands[0], operands[1],
+                                        operands[2], operands[3],
+                                        operands[4]));
+  DONE;
+})
+
+(define_expand "unaligned_storeqi_le"
   [(set (match_operand:DI 3 "register_operand" "")
        (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
                        (const_int -8))))
@@ -5117,10 +5619,50 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
    (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
        (match_dup 4))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "")
+
+(define_expand "unaligned_storeqi_be"
+  [(set (match_operand:DI 3 "register_operand" "")
+       (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+                       (const_int -8))))
+   (set (match_operand:DI 2 "register_operand" "")
+       (match_dup 0))
+   (set (match_dup 3)
+       (and:DI (not:DI (ashift:DI (const_int 255)
+                         (minus:DI (const_int 56)
+                                   (ashift:DI (match_dup 2) (const_int 3)))))
+               (match_dup 3)))
+   (set (match_operand:DI 4 "register_operand" "")
+       (ashift:DI (zero_extend:DI (match_operand:QI 1 "register_operand" ""))
+                  (minus:DI (const_int 56)
+                    (ashift:DI (match_dup 2) (const_int 3)))))
+   (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+   (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+       (match_dup 4))]
+  "WORDS_BIG_ENDIAN"
   "")
 
 (define_expand "unaligned_storehi"
+  [(use (match_operand:DI 0 "address_operand" ""))
+   (use (match_operand:HI 1 "register_operand" ""))
+   (use (match_operand:DI 2 "register_operand" ""))
+   (use (match_operand:DI 3 "register_operand" ""))
+   (use (match_operand:DI 4 "register_operand" ""))]
+  ""
+{
+  if (WORDS_BIG_ENDIAN)
+    emit_insn (gen_unaligned_storehi_be (operands[0], operands[1],
+                                        operands[2], operands[3],
+                                        operands[4]));
+  else
+    emit_insn (gen_unaligned_storehi_le (operands[0], operands[1],
+                                        operands[2], operands[3],
+                                        operands[4]));
+  DONE;
+})
+
+(define_expand "unaligned_storehi_le"
   [(set (match_operand:DI 3 "register_operand" "")
        (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
                        (const_int -8))))
@@ -5136,7 +5678,29 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
    (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
    (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
        (match_dup 4))]
-  ""
+  "! WORDS_BIG_ENDIAN"
+  "")
+
+(define_expand "unaligned_storehi_be"
+  [(set (match_operand:DI 3 "register_operand" "")
+       (mem:DI (and:DI (match_operand:DI 0 "address_operand" "")
+                       (const_int -8))))
+   (set (match_operand:DI 2 "register_operand" "")
+       (plus:DI (match_dup 0) (const_int 1)))
+   (set (match_dup 3)
+       (and:DI (not:DI (ashift:DI
+                         (const_int 65535)
+                         (minus:DI (const_int 56)
+                                   (ashift:DI (match_dup 2) (const_int 3)))))
+               (match_dup 3)))
+   (set (match_operand:DI 4 "register_operand" "")
+       (ashift:DI (zero_extend:DI (match_operand:HI 1 "register_operand" ""))
+                  (minus:DI (const_int 56)
+                            (ashift:DI (match_dup 2) (const_int 3)))))
+   (set (match_dup 4) (ior:DI (match_dup 4) (match_dup 3)))
+   (set (mem:DI (and:DI (match_dup 0) (const_int -8)))
+       (match_dup 4))]
+  "WORDS_BIG_ENDIAN"
   "")
 \f
 ;; Here are the define_expand's for QI and HI moves that use the above
@@ -5356,6 +5920,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 {
   rtx aligned_mem, bitnum;
   get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
   emit_insn (gen_aligned_loadqi (operands[0], aligned_mem, bitnum,
                                 operands[2]));
   DONE;
@@ -5370,6 +5935,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 {
   rtx aligned_mem, bitnum;
   get_aligned_mem (operands[1], &aligned_mem, &bitnum);
+
   emit_insn (gen_aligned_loadhi (operands[0], aligned_mem, bitnum,
                                 operands[2]));
   DONE;
@@ -5414,6 +5980,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
                         (match_operand:DI 3 "immediate_operand" "")))]
   ""
 {
+  int ofs;
+
   /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries.  */
   if (INTVAL (operands[3]) % 8 != 0
       || (INTVAL (operands[2]) != 16
@@ -5426,9 +5994,21 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   if (GET_CODE (operands[1]) != MEM)
     FAIL;
 
+  /* The bit number is relative to the mode of operand 1 which is
+     usually QImode (this might actually be a bug in expmed.c). Note 
+     that the bit number is negative in big-endian mode in this case.
+     We have to convert that to the offset.  */
+  if (WORDS_BIG_ENDIAN)
+    ofs = GET_MODE_BITSIZE (GET_MODE (operands[1]))
+          - INTVAL (operands[2]) - INTVAL (operands[3]);
+  else
+    ofs = INTVAL (operands[3]);
+
+  ofs = ofs / 8;
+
   alpha_expand_unaligned_load (operands[0], operands[1],
                               INTVAL (operands[2]) / 8,
-                              INTVAL (operands[3]) / 8, 1);
+                              ofs, 1);
   DONE;
 })
 
@@ -5449,13 +6029,27 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 
   if (GET_CODE (operands[1]) == MEM)
     {
+      int ofs;
+
       /* Fail 8 bit fields, falling back on a simple byte load.  */
       if (INTVAL (operands[2]) == 8)
        FAIL;
 
+      /* The bit number is relative to the mode of operand 1 which is
+        usually QImode (this might actually be a bug in expmed.c). Note 
+        that the bit number is negative in big-endian mode in this case.
+        We have to convert that to the offset.  */
+      if (WORDS_BIG_ENDIAN)
+       ofs = GET_MODE_BITSIZE (GET_MODE (operands[1]))
+             - INTVAL (operands[2]) - INTVAL (operands[3]);
+      else
+       ofs = INTVAL (operands[3]);
+
+      ofs = ofs / 8;
+
       alpha_expand_unaligned_load (operands[0], operands[1],
                                   INTVAL (operands[2]) / 8,
-                                  INTVAL (operands[3]) / 8, 0);
+                                  ofs, 0);
       DONE;
     }
 })
@@ -5467,6 +6061,8 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
        (match_operand:DI 3 "register_operand" ""))]
   ""
 {
+  int ofs;
+
   /* We can do 16, 32 and 64 bit fields, if aligned on byte boundaries.  */
   if (INTVAL (operands[2]) % 8 != 0
       || (INTVAL (operands[1]) != 16
@@ -5479,9 +6075,20 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   if (GET_CODE (operands[0]) != MEM)
     FAIL;
 
+  /* The bit number is relative to the mode of operand 1 which is
+     usually QImode (this might actually be a bug in expmed.c). Note 
+     that the bit number is negative in big-endian mode in this case.
+     We have to convert that to the offset.  */
+  if (WORDS_BIG_ENDIAN)
+    ofs = GET_MODE_BITSIZE (GET_MODE (operands[0]))
+          - INTVAL (operands[1]) - INTVAL (operands[2]);
+  else
+    ofs = INTVAL (operands[2]);
+
+  ofs = ofs / 8;
+
   alpha_expand_unaligned_store (operands[0], operands[3],
-                               INTVAL (operands[1]) / 8,
-                               INTVAL (operands[2]) / 8);
+                               INTVAL (operands[1]) / 8, ofs);
   DONE;
 })
 
@@ -5675,7 +6282,7 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
         (match_operand:DI 1 "register_operand" "r"))
    (clobber (mem:BLK (match_operand:DI 2 "register_operand" "=r")))]
   ""
-  "mov %1,%0")
+  "bis $31,%1,%0")
 
 (define_expand "epilogue"
   [(return)]
@@ -5836,6 +6443,58 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
   [(set_attr "length" "16")
    (set_attr "type" "multi")])
 
+;; Load the CIW into r2 for calling __T3E_MISMATCH
+
+(define_expand "umk_mismatch_args"
+  [(set:DI (match_dup 1) (mem:DI (plus:DI (reg:DI 15) (const_int -16))))
+   (set:DI (match_dup 2) (mem:DI (plus:DI (match_dup 1) (const_int -32))))
+   (set:DI (reg:DI 1) (match_operand:DI 0 "const_int_operand" ""))
+   (set:DI (match_dup 3) (plus:DI (mult:DI (reg:DI 25)
+                                          (const_int 8))
+                                 (match_dup 2)))
+   (set:DI (reg:DI 2) (mem:DI (match_dup 3)))]
+  "TARGET_ABI_UNICOSMK"
+{
+  operands[1] = gen_reg_rtx (DImode);
+  operands[2] = gen_reg_rtx (DImode);
+  operands[3] = gen_reg_rtx (DImode);
+})
+
+(define_insn "arg_home_umk"
+  [(unspec [(const_int 0)] UNSPEC_ARG_HOME)
+   (use (reg:DI 1))
+   (use (reg:DI 2))
+   (use (reg:DI 16))
+   (use (reg:DI 17))
+   (use (reg:DI 18))
+   (use (reg:DI 19))
+   (use (reg:DI 20))
+   (use (reg:DI 21))
+   (use (reg:DI 48))
+   (use (reg:DI 49))
+   (use (reg:DI 50))
+   (use (reg:DI 51))
+   (use (reg:DI 52))
+   (use (reg:DI 53))
+   (clobber (mem:BLK (const_int 0)))
+   (parallel [
+   (clobber (reg:DI 22))
+   (clobber (reg:DI 23))
+   (clobber (reg:DI 24))
+   (clobber (reg:DI 0))
+   (clobber (reg:DI 1))
+   (clobber (reg:DI 2))
+   (clobber (reg:DI 3))
+   (clobber (reg:DI 4))
+   (clobber (reg:DI 5))
+   (clobber (reg:DI 6))
+   (clobber (reg:DI 7))
+   (clobber (reg:DI 8))])]
+  "TARGET_ABI_UNICOSMK"
+  "laum $4,__T3E_MISMATCH($31)\;sll $4,32,$4\;lalm $4,__T3E_MISMATCH($4)\;lal $4,__T3E_MISMATCH($4)\;jsr $3,($4)"
+  [(set_attr "length" "16")
+   (set_attr "type" "multi")])
+
 ;; Close the trap shadow of preceeding instructions.  This is generated
 ;; by alpha_reorg.
 
@@ -5847,33 +6506,51 @@ fadd,fmul,fcpys,fdiv,fsqrt,misc,mvi,ftoi,itof,multi"
 
 ;; No-op instructions used by machine-dependant reorg to preserve
 ;; alignment for instruction issue.
+;; The Unicos/Mk assembler does not support these opcodes.
 
 (define_insn "nop"
   [(const_int 0)]
   ""
-  "nop"
+  "bis $31,$31,$31"
   [(set_attr "type" "ilog")])
 
 (define_insn "fnop"
   [(const_int 1)]
   "TARGET_FP"
-  "fnop"
+  "cpys $f31,$f31,$f31"
   [(set_attr "type" "fcpys")])
 
 (define_insn "unop"
   [(const_int 2)]
   ""
-  "unop")
+  "ldq_u $31,($31)")
+
+;; On Unicos/Mk we use a macro for aligning code.
 
 (define_insn "realign"
   [(unspec_volatile [(match_operand 0 "immediate_operand" "i")]
                    UNSPECV_REALIGN)]
   ""
-  ".align %0 #realign")
+{
+  if (TARGET_ABI_UNICOSMK)
+    return "gcc@code@align %0";
+  else
+    return ".align %0 #realign";
+})
 
 ;; The call patterns are at the end of the file because their
 ;; wildcard operand0 interferes with nice recognition.
 
+(define_insn "*call_value_umk"
+  [(set (match_operand 0 "" "")
+       (call (mem:DI (match_operand:DI 1 "call_operand" "r"))
+             (match_operand 2 "" "")))
+   (use (reg:DI 25))
+   (clobber (reg:DI 26))]
+  "TARGET_ABI_UNICOSMK"
+  "jsr $26,(%1)"
+  [(set_attr "type" "jsr")])
+
 (define_insn "*call_value_osf_1_er"
   [(set (match_operand 0 "" "")
        (call (mem:DI (match_operand:DI 1 "call_operand" "c,R,i"))
diff --git a/gcc/config/alpha/t-unicosmk b/gcc/config/alpha/t-unicosmk
new file mode 100644 (file)
index 0000000..9c52b98
--- /dev/null
@@ -0,0 +1,2 @@
+# This file is empty for now.
+
diff --git a/gcc/config/alpha/unicosmk.h b/gcc/config/alpha/unicosmk.h
new file mode 100644 (file)
index 0000000..6ecc3d2
--- /dev/null
@@ -0,0 +1,667 @@
+/* Definitions of target machine for GNU compiler, for DEC Alpha on Cray
+   T3E running Unicos/Mk.
+   Copyright (C) 2001
+   Free Software Foundation, Inc.
+   Contributed by Roman Lechtchinsky (rl@cs.tu-berlin.de)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+#undef TARGET_ABI_UNICOSMK
+#define TARGET_ABI_UNICOSMK 1
+
+/* CAM requires a slash before floating-pointing instruction suffixes.  */
+
+#undef TARGET_AS_SLASH_BEFORE_SUFFIX
+#define TARGET_AS_SLASH_BEFORE_SUFFIX 1
+
+/* The following defines are necessary for the standard headers to work
+   correctly.  */
+
+#undef CPP_PREDEFINES
+#define CPP_PREDEFINES "-D__unix=1 -D_UNICOS=205 -D_CRAY=1 -D_CRAYT3E=1 -D_CRAYMPP=1 -D_CRAYIEEE=1 -D_ADDR64=1 -D_LD64=1 -D__UNICOSMK__ -D__INT_MAX__=9223372036854775807 -D__SHRT_MAX__=2147483647"
+
+/* Disable software floating point emulation because it requires a 16-bit
+   type which we do not have.  */
+
+#ifndef __GNUC__
+#undef REAL_ARITHMETIC
+#endif
+
+#define SHORT_TYPE_SIZE 32
+
+#undef INT_TYPE_SIZE
+#define INT_TYPE_SIZE 64
+
+/* This is consistent with the definition Cray CC uses. */
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE 64
+
+/*
+#define SIZE_TYPE "unsigned int"
+#define PTRDIFF_TYPE "int"
+*/
+
+/* Alphas are operated in big endian mode on the Cray T3E.  */
+
+#undef BITS_BIG_ENDIAN
+#undef BYTES_BIG_ENDIAN
+#undef WORDS_BIG_ENDIAN
+#define BITS_BIG_ENDIAN 0
+#define BYTES_BIG_ENDIAN 1
+#define WORDS_BIG_ENDIAN 1
+
+
+/* Every structure's size must be a multiple of this.  */
+
+#undef STRUCTURE_SIZE_BOUNDARY
+#define STRUCTURE_SIZE_BOUNDARY 64
+
+/* Allocation boundary (in *bits*) for the code of a function. Functions
+   should be cache-aligned on the T3E.  */
+
+#undef FUNCTION_BOUNDARY
+#define FUNCTION_BOUNDARY 256
+
+/* No data type wants to be aligned rounder than this.  */
+
+#undef BIGGEST_ALIGNMENT
+#define BIGGEST_ALIGNMENT 256
+
+/* Include the frame pointer in fixed_regs and call_used_regs as it can't be 
+   used as a general-purpose register even in frameless functions.
+   ??? The global_regs hack is needed for now because -O2 sometimes tries to 
+   eliminate $15 increments/decrements in frameless functions.  */
+
+#undef CONDITIONAL_REGISTER_USAGE
+#define CONDITIONAL_REGISTER_USAGE     \
+  do {                                 \
+    fixed_regs[15] = 1;                        \
+    call_used_regs[15] = 1;            \
+    global_regs[15] = 1;               \
+  } while(0)
+\f
+/* The stack frame grows downward.  */
+
+#define FRAME_GROWS_DOWNWARD
+
+/* Define the offset between two registers, one to be eliminated, and the
+   other its replacement, at the start of a routine. This is somewhat
+   complicated on the T3E which is why we use a function.  */
+
+extern int unicosmk_initial_elimination_offset PARAMS ((int, int));
+
+#undef INITIAL_ELIMINATION_OFFSET
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)                   \
+  do {                                                                 \
+    (OFFSET) = unicosmk_initial_elimination_offset ((FROM), (TO));     \
+  } while (0)
+
+
+/* Define this if stack space is still allocated for a parameter passed
+   in a register. On the T3E, stack space is preallocated for all outgoing
+   arguments, including those passed in registers. To avoid problems, we
+   assume that at least 48 bytes (i.e. enough space for all arguments passed
+   in registers) are allocated.  */
+
+#define REG_PARM_STACK_SPACE(DECL) 48
+#define OUTGOING_REG_PARM_STACK_SPACE
+
+/* If an argument can't be passed in registers even though not all argument
+   registers have been used yet, it is passed on the stack in the space 
+   preallocated for these registers.  */
+
+#define STACK_PARMS_IN_REG_PARM_AREA
+
+/* This evaluates to nonzero if we do not know how to pass TYPE solely in
+   registers. This is the case for all arguments that do not fit in two
+   registers.  */
+
+#define MUST_PASS_IN_STACK(MODE,TYPE)                                  \
+  ((TYPE) != 0                                                         \
+   && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST                     \
+       || (TREE_ADDRESSABLE (TYPE) || ALPHA_ARG_SIZE (MODE, TYPE, 0) > 2)))
+
+/* Define a data type for recording info about an argument list
+   during the scan of that argument list.  This data type should
+   hold all necessary information about the function itself
+   and about the args processed so far, enough to enable macros
+   such as FUNCTION_ARG to determine where the next arg should go.
+
+   On Unicos/Mk, this is a structure that contains various information for
+   the static subroutine information block (SSIB) and the call information
+   word (CIW).  */
+
+typedef struct {
+
+  /* The overall number of arguments.  */
+  int num_args;
+
+  /* The overall size of the arguments in words.  */
+  int num_arg_words;
+
+  /* The number of words passed in registers.  */
+  int num_reg_words;
+
+  /* If an argument must be passed in the stack, all subsequent arguments
+     must be passed there, too. This flag indicates whether this is the
+     case.  */
+  int force_stack;
+
+  /* This array indicates whether a word is passed in an integer register or
+     a floating point one.  */
+
+  /* For each of the 6 register arguments, the corresponding flag in this
+     array indicates whether the argument is passed in an integer or a
+     floating point register.  */
+  int reg_args_type[6];
+
+} unicosmk_arg_info;
+
+#undef CUMULATIVE_ARGS
+#define CUMULATIVE_ARGS unicosmk_arg_info
+
+/* Initialize a variable CUM of type CUMULATIVE_ARGS for a call to a
+   function whose data type is FNTYPE.  For a library call, FNTYPE is 0.  */
+
+#undef INIT_CUMULATIVE_ARGS
+#define INIT_CUMULATIVE_ARGS(CUM,FNTYPE,LIBNAME,INDIRECT)      \
+  do { (CUM).num_args = 0;                                     \
+       (CUM).num_arg_words = 0;                                        \
+       (CUM).num_reg_words = 0;                                        \
+       (CUM).force_stack = 0;                                  \
+  } while(0)
+
+/* Update the data in CUM to advance over an argument of mode MODE and data
+   type TYPE. (TYPE is null for libcalls where that information may not be
+   available.)
+
+   On Unicos/Mk, at most 6 words can be passed in registers. Structures
+   which fit in two words are passed in registers, larger structures are
+   passed on stack.  */
+
+#undef FUNCTION_ARG_ADVANCE
+#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)           \
+do {                                                           \
+  int size;                                                    \
+                                                               \
+  size = ALPHA_ARG_SIZE (MODE, TYPE, NAMED);                   \
+                                                                \
+  if (size > 2 || MUST_PASS_IN_STACK (MODE, TYPE)              \
+      || (CUM).num_reg_words + size > 6)                       \
+    (CUM).force_stack = 1;                                     \
+                                                                \
+  if (! (CUM).force_stack)                                     \
+    {                                                          \
+      int i;                                                   \
+      int isfloat;                                             \
+      isfloat = (GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT   \
+              || GET_MODE_CLASS (MODE) == MODE_FLOAT);         \
+      for (i = 0; i < size; i++)                               \
+        {                                                      \
+          (CUM).reg_args_type[(CUM).num_reg_words] = isfloat;  \
+          ++(CUM).num_reg_words;                               \
+        }                                                      \
+    }                                                          \
+  (CUM).num_arg_words += size;                                 \
+  ++(CUM).num_args;                                            \
+} while(0)
+
+/* We want the default definition for this.
+   ??? In fact, we should delete the definition from alpha.h as it
+   corresponds to the default definition for little-endian machines.  */
+
+#undef FUNCTION_ARG_PADDING
+
+/* An argument is passed either entirely in registers or entirely on stack. */
+#undef FUNCTION_ARG_PARTIAL_NREGS
+/* #define FUNCTION_ARG_PARTIAL_NREGS(CUM,MODE,TYPE,NAMED) 0 */
+
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments.
+
+   On Unicos/Mk, the standard subroutine __T3E_MISMATCH stores all register
+   arguments on the stack. Unfortunately, it doesn't always store the first
+   one (i.e. the one that arrives in $16 or $f16). This is not a problem
+   with stdargs as we always have at least one named argument there. This is
+   not always the case when varargs.h is used, however. In such cases, we
+   have to store the first argument ourselves. We use the information from
+   the CIW to determine whether the first argument arrives in $16 or $f16.  */
+
+#undef SETUP_INCOMING_VARARGS
+#define SETUP_INCOMING_VARARGS(CUM,MODE,TYPE,PRETEND_SIZE,NO_RTL)      \
+{ if ((CUM).num_reg_words < 6)                                         \
+    {                                                                  \
+      if (! (NO_RTL))                                                  \
+        {                                                              \
+         int start;                                                    \
+                                                                       \
+         start = (CUM).num_reg_words;                                  \
+         if (!current_function_varargs || start == 0)                  \
+           ++start;                                                    \
+                                                                       \
+          emit_insn (gen_umk_mismatch_args (GEN_INT (start)));         \
+         if (current_function_varargs && (CUM).num_reg_words == 0)     \
+           {                                                           \
+             rtx tmp;                                                  \
+             rtx int_label, end_label;                                 \
+                                                                       \
+             tmp = gen_reg_rtx (DImode);                               \
+             emit_move_insn (tmp,                                      \
+                             gen_rtx_ZERO_EXTRACT (DImode,             \
+                                                   gen_rtx_REG (DImode, 2),\
+                                                   (GEN_INT (1)),      \
+                                                   (GEN_INT (7))));    \
+             int_label = gen_label_rtx ();                             \
+             end_label = gen_label_rtx ();                             \
+             emit_insn (gen_cmpdi (tmp, GEN_INT (0)));                 \
+             emit_jump_insn (gen_beq (int_label));                     \
+             emit_move_insn (gen_rtx_MEM (DFmode, virtual_incoming_args_rtx),\
+                             gen_rtx_REG (DFmode, 48));                \
+             emit_jump (end_label);                                    \
+             emit_label (int_label);                                   \
+             emit_move_insn (gen_rtx_MEM (DImode, virtual_incoming_args_rtx),\
+                             gen_rtx_REG (DImode, 16));                \
+             emit_label (end_label);                                   \
+           }                                                           \
+         emit_insn (gen_arg_home_umk ());                              \
+        }                                                              \
+                                                                       \
+      PRETEND_SIZE = 0;                                                        \
+    }                                                                  \
+}
+
+/* This ensures that $15 increments/decrements in leaf functions won't get
+   eliminated.  */
+
+#undef EPILOGUE_USES
+#define EPILOGUE_USES(REGNO)  ((REGNO) == 26 || (REGNO) == 15)
+
+/* Machine-specific function data.  */
+
+struct machine_function
+{
+  /* List of call information words for calls from this function.  */
+  struct rtx_def *first_ciw;
+  struct rtx_def *last_ciw;
+  int ciw_count;
+
+  /* List of deferred case vectors.  */
+  struct rtx_def *addr_list;
+};
+
+/* Would have worked, only the stack doesn't seem to be executable
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE)                      \
+do { fprintf (FILE, "\tbr $1,0\n");                    \
+     fprintf (FILE, "\tldq $0,12($1)\n");              \
+     fprintf (FILE, "\tldq $1,20($1)\n");              \
+     fprintf (FILE, "\tjmp $31,(r0)\n");               \
+     fprintf (FILE, "\tbis $31,$31,$31\n");            \
+     fprintf (FILE, "\tbis $31,$31,$31\n");            \
+} while (0) */
+
+/* We don't support nested functions (yet).  */
+
+#undef TRAMPOLINE_TEMPLATE
+#define TRAMPOLINE_TEMPLATE(FILE) abort ()
+\f
+/* Specify the machine mode that this machine uses for the index in the
+   tablejump instruction. On Unicos/Mk, we don't support relative case
+   vectors yet, thus the entries should be absolute addresses. */ 
+
+#undef CASE_VECTOR_MODE
+#define CASE_VECTOR_MODE DImode
+
+#undef CASE_VECTOR_PC_RELATIVE
+
+/* Define this as 1 if `char' should by default be signed; else as 0.  */
+/* #define DEFAULT_SIGNED_CHAR 1 */
+
+/* The Cray assembler is really weird with respect to sections. It has only
+   named sections and you can't reopen a section once it has been closed.
+   This means that we have to generate unique names whenever we want to
+   reenter the text or the data section. The following is a rather bad hack
+   as TEXT_SECTION_ASM_OP and DATA_SECTION_ASM_OP are supposed to be
+   constants.  */
+
+#undef TEXT_SECTION_ASM_OP
+#define TEXT_SECTION_ASM_OP unicosmk_text_section ()
+
+#undef DATA_SECTION_ASM_OP
+#define DATA_SECTION_ASM_OP unicosmk_data_section ()
+
+/* There are ni read-only sections on Unicos/Mk.  */
+
+#undef READONLY_DATA_SECTION
+#define READONLY_DATA_SECTION data_section
+
+/* Define extra sections for common data and SSIBs (static subroutine
+   information blocks). The actual section header is output by the callers
+   of these functions.  */
+
+#undef EXTRA_SECTIONS
+#undef EXTRA_SECTION_FUNCTIONS
+
+#define EXTRA_SECTIONS in_common, in_ssib
+#define EXTRA_SECTION_FUNCTIONS        \
+COMMON_SECTION                 \
+SSIB_SECTION   
+
+#define COMMON_SECTION         \
+void                           \
+common_section ()              \
+{                              \
+  in_section = in_common;      \
+}
+
+#define SSIB_SECTION           \
+void                           \
+ssib_section ()                        \
+{                              \
+  in_section = in_ssib;                \
+}
+
+/* A C expression which evaluates to true if declshould be placed into a
+   unique section for some target-specific reason. On Unicos/Mk, functions
+   and public variables are always placed in unique sections.  */ 
+
+/*
+#define UNIQUE_SECTION_P(DECL) (TREE_PUBLIC (DECL)             \
+                               || TREE_CODE (DECL) == FUNCTION_DECL)
+*/
+#define UNIQUE_SECTION(DECL, RELOC) unicosmk_unique_section (DECL, RELOC)
+
+/* This outputs text to go at the start of an assembler file.  */
+
+#undef ASM_FILE_START
+#define ASM_FILE_START(FILE)   unicosmk_asm_file_start (FILE)
+
+/* This outputs text to go at the end of an assembler file.  */
+
+#undef ASM_FILE_END
+#define ASM_FILE_END(FILE)     unicosmk_asm_file_end (FILE)
+
+/* We take care of that in ASM_FILE_START. */
+
+#undef ASM_OUTPUT_SOURCE_FILENAME
+
+/* There is no directive for declaring a label as global. Instead, an 
+   additional colon must be appended when the label is defined.  */
+
+#undef ASM_GLOBALIZE_LABEL
+#define ASM_GLOBALIZE_LABEL(FILE,NAME)
+
+/* This is how to output a label for a jump table.  Arguments are the same as
+   for ASM_OUTPUT_INTERNAL_LABEL, except the insn for the jump table is
+   passed.  */
+
+#undef ASM_OUTPUT_CASE_LABEL
+#define ASM_OUTPUT_CASE_LABEL(FILE,PREFIX,NUM,TABLEINSN)       \
+  ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM)
+
+/* This is how to output an assembler line defining a `double' constant.  */
+
+#undef ASM_OUTPUT_DOUBLE
+#ifdef REAL_ARITHMETIC
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE)                  \
+  do { long t[2];                                      \
+       REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t);       \
+       fprintf (FILE, "\t.quad ^X%lx%08lx\n",          \
+               t[0] & 0xffffffff, t[1] & 0xffffffff);  \
+  } while (0)
+#else
+#define ASM_OUTPUT_DOUBLE(FILE,VALUE)                  \
+  do { long t[2];                                      \
+       REAL_VALUE_TO_TARGET_DOUBLE ((VALUE), t);       \
+       fprintf (FILE, "\t.quad ^X%x\n", t[0]);         \
+  } while(0)
+#endif
+
+/* This is how to output an assembler line defining a `long double'
+   constant. `long double'  and `double' are the same on the Cray T3E.  */
+#undef ASM_OUTPUT_LONG_DOUBLE
+#define ASM_OUTPUT_LONG_DOUBLE(FILE,VALUE)             \
+  ASM_OUTPUT_DOUBLE (FILE,VALUE)
+
+/* This is how to output an assembler line defining a `float' constant.
+   ??? Somehow, REAL_VALUE_TO_TARGET_SINGLE gets confused and returns the
+   value in the upper bits of the int.  */
+
+#undef ASM_OUTPUT_FLOAT
+#ifdef REAL_ARITHMETIC
+#define ASM_OUTPUT_FLOAT(FILE,VALUE)                   \
+  do { long t;                                         \
+       REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t);       \
+       fprintf (FILE, "\t.long ^X%x\n", t & 0xffffffff);\
+  } while (0)
+#else
+#define ASM_OUTPUT_FLOAT(FILE,VALUE)                   \
+  do { long t;                                         \
+       REAL_VALUE_TO_TARGET_SINGLE ((VALUE), t);       \
+       fprintf (FILE, "\t.long ^X%x\n", (t >> 32) & 0xffffffff);\
+  } while(0)
+#endif
+
+/* CAM has some restrictions with respect to string literals. It won't
+   accept lines with more that 256 characters which means that we have
+   to split long strings. Moreover, it only accepts escape sequences of
+   the form \nnn in the range 0 to 127. We generate .byte directives for
+   escapes characters greater than 127. And finally, ` must be escaped.  */
+
+#undef ASM_OUTPUT_ASCII
+#define ASM_OUTPUT_ASCII(MYFILE, MYSTRING, MYLENGTH) \
+  do {                                                                       \
+    FILE *_hide_asm_out_file = (MYFILE);                                     \
+    const unsigned char *_hide_p = (const unsigned char *) (MYSTRING);       \
+    int _hide_thissize = (MYLENGTH);                                         \
+    int _size_so_far = 0;                                                    \
+    {                                                                        \
+      FILE *asm_out_file = _hide_asm_out_file;                               \
+      const unsigned char *p = _hide_p;                                              \
+      int thissize = _hide_thissize;                                         \
+      int in_ascii = 0;                                                              \
+      int i;                                                                 \
+                                                                             \
+      for (i = 0; i < thissize; i++)                                         \
+       {                                                                     \
+         register int c = p[i];                                              \
+                                                                             \
+         if (c > 127)                                                        \
+           {                                                                 \
+             if (in_ascii)                                                   \
+               {                                                             \
+                 fprintf (asm_out_file, "\"\n");                             \
+                 in_ascii = 0;                                               \
+               }                                                             \
+                                                                             \
+             fprintf (asm_out_file, "\t.byte\t%d\n", c);                     \
+           }                                                                 \
+         else                                                                \
+           {                                                                 \
+             if (! in_ascii)                                                 \
+               {                                                             \
+                 fprintf (asm_out_file, "\t.ascii\t\"");                     \
+                 in_ascii = 1;                                               \
+                 _size_so_far = 0;                                           \
+               }                                                             \
+             else if (_size_so_far >= 64)                                    \
+               {                                                             \
+                 fprintf (asm_out_file, "\"\n\t.ascii\t\"");                 \
+                 _size_so_far = 0;                                           \
+               }                                                             \
+                                                                             \
+             if (c == '\"' || c == '\\' || c == '`')                         \
+               putc ('\\', asm_out_file);                                    \
+             if (c >= ' ')                                                   \
+               putc (c, asm_out_file);                                       \
+             else                                                            \
+               fprintf (asm_out_file, "\\%.3o", c);                          \
+             ++ _size_so_far;                                                \
+           }                                                                 \
+       }                                                                     \
+      if (in_ascii)                                                          \
+       fprintf (asm_out_file, "\"\n");                                       \
+    }                                                                        \
+  } while(0)
+
+/* This is how to output an element of a case-vector that is absolute.  */
+
+#undef ASM_OUTPUT_ADDR_VEC_ELT
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE)   \
+  fprintf (FILE, "\t.quad $L%d\n", (VALUE))
+
+/* This is how to output an element of a case-vector that is relative.
+   (Unicos/Mk does not use such vectors yet).  */
+
+#undef ASM_OUTPUT_ADDR_DIFF_ELT
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) abort ()
+
+/* We can't output case vectors in the same section as the function code
+   because CAM doesn't allow data definitions in code sections. Thus, we
+   simply record the case vectors and put them in a separate section after
+   the function.  */
+
+#define ASM_OUTPUT_ADDR_VEC(LAB,VEC) \
+  unicosmk_defer_case_vector ((LAB),(VEC))
+
+#define ASM_OUTPUT_ADDR_DIFF_VEC(LAB,VEC) abort ()
+
+/* This is how to output an assembler line that says to advance the location
+   counter to a multiple of 2**LOG bytes. Annoyingly, CAM always uses zeroes
+   to fill the unused space which does not work in code sections. We have to 
+   be careful not to use the .align directive in code sections.  */
+
+#undef ASM_OUTPUT_ALIGN
+#define ASM_OUTPUT_ALIGN(STREAM,LOG) unicosmk_output_align (STREAM, LOG)
+
+/* This is how to advance the location counter by SIZE bytes.  */
+
+#undef ASM_OUTPUT_SKIP
+#define ASM_OUTPUT_SKIP(STREAM,SIZE)                   \
+  fprintf ((STREAM), "\t.byte\t0:%d\n", (SIZE));
+
+/* This says how to output an assembler line to define a global common
+   symbol. We need the alignment information because it has to be supplied
+   in the section header.  */ 
+
+#undef ASM_OUTPUT_COMMON
+#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN)     \
+  unicosmk_output_common ((FILE), (NAME), (SIZE), (ALIGN))
+
+/* This says how to output an assembler line to define a local symbol.  */
+
+#undef ASM_OUTPUT_LOCAL
+#define ASM_OUTPUT_ALIGNED_LOCAL(FILE, NAME, SIZE, ALIGN) \
+  do { data_section ();                                        \
+       fprintf (FILE, "\t.align\t%d\n", floor_log2 ((ALIGN) / BITS_PER_UNIT));\
+       ASM_OUTPUT_LABEL ((FILE), (NAME));              \
+       fprintf (FILE, "\t.byte 0:%d\n", SIZE);         \
+  } while (0)
+
+/* CAM does not allow us to declare a symbol as external first and then
+   define it in the same file later. Thus, we keep a list of all external
+   references, remove all symbols defined locally from it and output it at
+   the end of the asm file.  */
+   
+#define ASM_OUTPUT_EXTERNAL(FILE,DECL,NAME) \
+  unicosmk_add_extern ((NAME))
+
+#define ASM_OUTPUT_EXTERNAL_LIBCALL(STREAM,SYMREF)     \
+  unicosmk_add_extern (XSTR ((SYMREF), 0))
+
+/* This is how to declare an object. We don't have to output anything if
+   it is a global variable because those go into unique `common' sections
+   and the section name is globally visible. For local variables, we simply
+   output the label. In any case, we have to record that no extern
+   declaration should be generated for the symbol.  */
+
+#define ASM_DECLARE_OBJECT_NAME(STREAM,NAME,DECL)      \
+  do { tree name_tree;                                 \
+       name_tree = get_identifier ((NAME));            \
+       TREE_ASM_WRITTEN (name_tree) = 1;               \
+       if (!TREE_PUBLIC (DECL))                                \
+        {                                              \
+          assemble_name (STREAM, NAME);                \
+          fputs (":\n", STREAM);                       \
+         }                                             \
+  } while(0)
+
+/*
+#define ASM_OUTPUT_SECTION_NAME(STREAM, DECL, NAME, RELOC)     \
+  unicosmk_output_section_name ((STREAM), (DECL), (NAME), (RELOC))
+*/
+
+/* Switch into a generic section.  */
+#define TARGET_ASM_NAMED_SECTION unicosmk_asm_named_section
+
+#undef ASM_OUTPUT_MAX_SKIP_ALIGN
+#define ASM_OUTPUT_MAX_SKIP_ALIGN(STREAM,POWER,MAXSKIP)
+\f
+/* We have to define these because we do not use the floating-point
+   emulation. Unfortunately, atof does not accept hex literals.  */ 
+
+#ifndef REAL_ARITHMETIC
+#define REAL_VALUE_ATOF(x,s) atof(x)
+#define REAL_VALUE_HTOF(x,s) atof(x)
+#endif
+
+#undef NM_FLAGS
+
+#undef OBJECT_FORMAT_COFF
+
+/* We cannot generate debugging information on Unicos/Mk.  */
+
+#undef SDB_DEBUGGING_INFO
+#undef MIPS_DEBUGGING_INFO
+#undef DBX_DEBUGGING_INFO
+#undef DWARF_DEBUGGING_INFO
+#undef DWARF2_DEBUGGING_INFO
+#undef DWARF2_UNWIND_INFO
+#undef INCOMING_RETURN_ADDR_RTX
+
+
+/* We use the functions provided by the system library for integer
+   division.  */
+
+#undef UDIVDI3_LIBCALL
+#undef DIVDI3_LIBCALL
+#define UDIVDI3_LIBCALL        "$uldiv"
+#define DIVDI3_LIBCALL "$sldiv"
+
+#undef ASM_OUTPUT_SOURCE_LINE
+
+/* We don't need a start file.  */
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC ""
+
+/* These are the libraries we have to link with.
+   ??? The Craylibs directory should be autoconfed.  */
+#undef LIB_SPEC
+#define LIB_SPEC "-L/opt/ctl/craylibs/craylibs -lu -lm -lc -lsma"
+
+#undef BUILD_VA_LIST_TYPE
+#undef EXPAND_BUILTIN_VA_START
+#undef EXPAND_BUILTIN_VA_ARG
+
+#define EH_FRAME_IN_DATA_SECTION 1
index 873e481c42181bc57a1b3c515342d5f542fcf3b1..79b3e7e67fdd2dd25e44f5cb18058c3eba56d358 100644 (file)
@@ -5,7 +5,7 @@
  * files which are fixed to work correctly with ANSI C and placed in a
  * directory that GNU C will search.
  *
- * This file contains 143 fixup descriptions.
+ * This file contains 144 fixup descriptions.
  *
  * See README for more information.
  *
@@ -1954,7 +1954,7 @@ tSCC zHpux10_Cpp_Pow_InlineName[] =
  *  File name selection pattern
  */
 tSCC zHpux10_Cpp_Pow_InlineList[] =
-  "|math.h|";
+  "|fixinc-test-limits.h|math.h|";
 /*
  *  Machine/OS name selection pattern
  */
@@ -5105,6 +5105,43 @@ static const char* apzUndefine_NullPatch[] = {
 ]+)([\r]*)\n",
     (char*)NULL };
 
+/* * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ *  Description of Unicosmk_Restrict fix
+ */
+tSCC zUnicosmk_RestrictName[] =
+     "unicosmk_restrict";
+
+/*
+ *  File name selection pattern
+ */
+tSCC zUnicosmk_RestrictList[] =
+  "|stdio.h|stdlib.h|wchar.h|";
+/*
+ *  Machine/OS name selection pattern
+ */
+tSCC* apzUnicosmk_RestrictMachs[] = {
+        "*-*-unicosmk*",
+        (const char*)NULL };
+
+/*
+ *  content selection pattern - do fix if pattern found
+ */
+tSCC zUnicosmk_RestrictSelect0[] =
+       "(\\*[ \t]*)restrict([ \t]+)";
+
+#define    UNICOSMK_RESTRICT_TEST_CT  1
+static tTestDesc aUnicosmk_RestrictTests[] = {
+  { TT_EGREP,    zUnicosmk_RestrictSelect0, (regex_t*)NULL }, };
+
+/*
+ *  Fix Command Arguments for Unicosmk_Restrict
+ */
+static const char* apzUnicosmk_RestrictPatch[] = {
+    "format",
+    "%1__restrict__%2",
+    (char*)NULL };
+
 /* * * * * * * * * * * * * * * * * * * * * * * * * *
  *
  *  Description of Uw7_Byteorder_Fix fix
@@ -5577,9 +5614,9 @@ static const char* apzX11_SprintfPatch[] = {
  *
  *  List of all fixes
  */
-#define REGEX_COUNT          150
+#define REGEX_COUNT          151
 #define MACH_LIST_SIZE_LIMIT 279
-#define FIX_COUNT            143
+#define FIX_COUNT            144
 
 /*
  *  Enumerate the fixes
@@ -5717,6 +5754,7 @@ typedef enum {
     ULTRIX_STATIC_FIXIDX,
     ULTRIX_STRINGS_FIXIDX,
     UNDEFINE_NULL_FIXIDX,
+    UNICOSMK_RESTRICT_FIXIDX,
     UW7_BYTEORDER_FIX_FIXIDX,
     VA_I960_MACRO_FIXIDX,
     VOID_NULL_FIXIDX,
@@ -6391,6 +6429,11 @@ tFixDesc fixDescList[ FIX_COUNT ] = {
      UNDEFINE_NULL_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
      aUndefine_NullTests,   apzUndefine_NullPatch, 0 },
 
+  {  zUnicosmk_RestrictName,    zUnicosmk_RestrictList,
+     apzUnicosmk_RestrictMachs,
+     UNICOSMK_RESTRICT_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
+     aUnicosmk_RestrictTests,   apzUnicosmk_RestrictPatch, 0 },
+
   {  zUw7_Byteorder_FixName,    zUw7_Byteorder_FixList,
      apzUw7_Byteorder_FixMachs,
      UW7_BYTEORDER_FIX_TEST_CT, FD_MACH_ONLY | FD_SUBROUTINE,
index aedf09713d385d3b0885d49629c61673069f240a..40194e2fd08bf0c018622f3d73f7f4e3eaaee7c8 100644 (file)
@@ -3102,6 +3102,23 @@ fix = {
     test_text = "#define NULL 0UL\r\n#define NULL\t((void*)0)\n";
 };
 
+/*
+ * On Cray Unicos/Mk some standard headers use the C99 keyword "restrict"
+ * which must be replaced by __restrict__ for GCC.
+ */
+fix = {
+    hackname = unicosmk_restrict;
+    files    = stdio.h;
+    files    = stdlib.h;
+    files    = wchar.h;
+    mach     = "*-*-unicosmk*";
+    select   = "(\\*[ \t]*)restrict([ \t]+)";
+
+    c_fix     = format;
+    c_fix_arg = "%1__restrict__%2";
+
+    test_text = "void f (char * restrict x);";
+};
 
 /*
  * If arpa/inet.h prototypes are incompatible with the ones we just
index 7e5075ad898431490a755fe2e381927ee4d2e2c6..cce87e5b6ed82eceff3cc60fcee6593758181096 100644 (file)
@@ -165,6 +165,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
    or if we want this type in particular.  */
 #if defined (_STDDEF_H) || defined (__need_size_t)
 #ifndef __size_t__     /* BeOS */
+#ifndef __SIZE_T__     /* Cray Unicos/Mk */
 #ifndef _SIZE_T        /* in case <sys/types.h> has defined it. */
 #ifndef _SYS_SIZE_T_H
 #ifndef _T_SIZE_
@@ -179,6 +180,7 @@ typedef __PTRDIFF_TYPE__ ptrdiff_t;
 #ifndef _SIZET_
 #ifndef __size_t
 #define __size_t__     /* BeOS */
+#define __SIZE_T__     /* Cray Unicos/Mk */
 #define _SIZE_T
 #define _SYS_SIZE_T_H
 #define _T_SIZE_
@@ -214,6 +216,7 @@ typedef long ssize_t;
 #endif /* _T_SIZE_ */
 #endif /* _SYS_SIZE_T_H */
 #endif /* _SIZE_T */
+#endif /* __SIZE_T__ */
 #endif /* __size_t__ */
 #undef __need_size_t
 #endif /* _STDDEF_H or __need_size_t.  */
@@ -228,6 +231,7 @@ typedef long ssize_t;
    or if we want this type in particular.  */
 #if defined (_STDDEF_H) || defined (__need_wchar_t)
 #ifndef __wchar_t__    /* BeOS */
+#ifndef __WCHAR_T__    /* Cray Unicos/Mk */
 #ifndef _WCHAR_T
 #ifndef _T_WCHAR_
 #ifndef _T_WCHAR
@@ -242,6 +246,7 @@ typedef long ssize_t;
 #ifndef __INT_WCHAR_T_H
 #ifndef _GCC_WCHAR_T
 #define __wchar_t__    /* BeOS */
+#define __WCHAR_T__    /* Cray Unicos/Mk */
 #define _WCHAR_T
 #define _T_WCHAR_
 #define _T_WCHAR
@@ -300,6 +305,7 @@ typedef __WCHAR_TYPE__ wchar_t;
 #endif
 #endif
 #endif
+#endif /* __WCHAR_T__ */
 #endif /* __wchar_t__ */
 #undef __need_wchar_t
 #endif /* _STDDEF_H or __need_wchar_t.  */