]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/config/alpha/alpha.c
flags.h (g_switch_value): Change to an unsigned HOST_WIDE_INT.
[gcc.git] / gcc / config / alpha / alpha.c
index a4ca0df7c6c0f70d99f7c3e26d9bc41a6be4b929..76f399e3c6e15119f1d5eb7ef5893763b50ec392 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used for code generation on the DEC Alpha.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001 Free Software Foundation, Inc. 
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc. 
    Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
 
 This file is part of GNU CC.
@@ -23,6 +23,8 @@ Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tree.h"
 #include "regs.h"
@@ -46,9 +48,9 @@ Boston, MA 02111-1307, USA.  */
 #include "tm_p.h"
 #include "target.h"
 #include "target-def.h"
-
-/* External data.  */
-extern int rtx_equal_function_value_matters;
+#include "debug.h"
+#include "langhooks.h"
+#include <splay-tree.h>
 
 /* Specify which cpu to schedule for.  */
 
@@ -70,6 +72,10 @@ enum alpha_fp_rounding_mode alpha_fprm;
 
 enum alpha_fp_trap_mode alpha_fptm;
 
+/* Specify bit size of immediate TLS offsets.  */
+
+int alpha_tls_size = 32;
+
 /* Strings decoded into the above options.  */
 
 const char *alpha_cpu_string;  /* -mcpu= */
@@ -78,13 +84,14 @@ const char *alpha_tp_string;        /* -mtrap-precision=[p|s|i] */
 const char *alpha_fprm_string; /* -mfp-rounding-mode=[n|m|c|d] */
 const char *alpha_fptm_string; /* -mfp-trap-mode=[n|u|su|sui] */
 const char *alpha_mlat_string; /* -mmemory-latency= */
+const char *alpha_tls_size_string; /* -mtls-size=[16|32|64] */
 
 /* Save information from a "cmpxx" operation until the branch or scc is
    emitted.  */
 
 struct alpha_compare alpha_compare;
 
-/* Non-zero if inside of a function, because the Alpha asm can't
+/* Nonzero if inside of a function, because the Alpha asm can't
    handle .files inside of functions.  */
 
 static int inside_function = FALSE;
@@ -99,25 +106,92 @@ static int alpha_function_needs_gp;
 
 /* The alias set for prologue/epilogue register save/restore.  */
 
-static int alpha_sr_alias_set;
+static GTY(()) int alpha_sr_alias_set;
 
 /* The assembler name of the current function.  */
 
 static const char *alpha_fnname;
 
 /* The next explicit relocation sequence number.  */
+extern GTY(()) int alpha_next_sequence_number;
 int alpha_next_sequence_number = 1;
 
 /* The literal and gpdisp sequence numbers for this insn, as printed
    by %# and %* respectively.  */
+extern GTY(()) int alpha_this_literal_sequence_number;
+extern GTY(()) int alpha_this_gpdisp_sequence_number;
 int alpha_this_literal_sequence_number;
 int alpha_this_gpdisp_sequence_number;
 
+/* Costs of various operations on the different architectures.  */
+
+struct alpha_rtx_cost_data
+{
+  unsigned char fp_add;
+  unsigned char fp_mult;
+  unsigned char fp_div_sf;
+  unsigned char fp_div_df;
+  unsigned char int_mult_si;
+  unsigned char int_mult_di;
+  unsigned char int_shift;
+  unsigned char int_cmov;
+};
+
+static struct alpha_rtx_cost_data const alpha_rtx_cost_data[PROCESSOR_MAX] =
+{
+  { /* EV4 */
+    COSTS_N_INSNS (6),         /* fp_add */
+    COSTS_N_INSNS (6),         /* fp_mult */
+    COSTS_N_INSNS (34),                /* fp_div_sf */
+    COSTS_N_INSNS (63),                /* fp_div_df */
+    COSTS_N_INSNS (23),                /* int_mult_si */
+    COSTS_N_INSNS (23),                /* int_mult_di */
+    COSTS_N_INSNS (2),         /* int_shift */
+    COSTS_N_INSNS (2),         /* int_cmov */
+  },
+  { /* EV5 */
+    COSTS_N_INSNS (4),         /* fp_add */
+    COSTS_N_INSNS (4),         /* fp_mult */
+    COSTS_N_INSNS (15),                /* fp_div_sf */
+    COSTS_N_INSNS (22),                /* fp_div_df */
+    COSTS_N_INSNS (8),         /* int_mult_si */
+    COSTS_N_INSNS (12),                /* int_mult_di */
+    COSTS_N_INSNS (1) + 1,     /* int_shift */
+    COSTS_N_INSNS (1),         /* int_cmov */
+  },
+  { /* EV6 */
+    COSTS_N_INSNS (4),         /* fp_add */
+    COSTS_N_INSNS (4),         /* fp_mult */
+    COSTS_N_INSNS (12),                /* fp_div_sf */
+    COSTS_N_INSNS (15),                /* fp_div_df */
+    COSTS_N_INSNS (7),         /* int_mult_si */
+    COSTS_N_INSNS (7),         /* int_mult_di */
+    COSTS_N_INSNS (1),         /* int_shift */
+    COSTS_N_INSNS (2),         /* int_cmov */
+  },
+};
+
 /* Declarations of static functions.  */
-static bool decl_in_text_section
+static bool alpha_function_ok_for_sibcall
+  PARAMS ((tree, tree));
+static int tls_symbolic_operand_1
+  PARAMS ((rtx, enum machine_mode, int, int));
+static enum tls_model tls_symbolic_operand_type
+  PARAMS ((rtx));
+static bool decl_has_samegp
+  PARAMS ((tree));
+static bool alpha_in_small_data_p
   PARAMS ((tree));
-static bool local_symbol_p
+static rtx get_tls_get_addr
+  PARAMS ((void));
+static int some_small_symbolic_operand_1
+  PARAMS ((rtx *, void *));
+static int split_small_symbolic_operand_1
+  PARAMS ((rtx *, void *));
+static bool alpha_cannot_copy_insn_p
   PARAMS ((rtx));
+static bool alpha_rtx_costs
+  PARAMS ((rtx, int, int, int *));
 static void alpha_set_memflags_1
   PARAMS ((rtx, int, int, int));
 static rtx alpha_emit_set_const_1
@@ -126,9 +200,13 @@ static void alpha_expand_unaligned_load_words
   PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
 static void alpha_expand_unaligned_store_words
   PARAMS ((rtx *out_regs, rtx smem, HOST_WIDE_INT words, HOST_WIDE_INT ofs));
+static void alpha_init_builtins
+  PARAMS ((void));
+static rtx alpha_expand_builtin
+  PARAMS ((tree, rtx, rtx, enum machine_mode, int));
 static void alpha_sa_mask
   PARAMS ((unsigned long *imaskP, unsigned long *fmaskP));
-static int find_lo_sum
+static int find_lo_sum_using_gp
   PARAMS ((rtx *, void *));
 static int alpha_does_function_need_gp
   PARAMS ((void));
@@ -138,6 +216,10 @@ static const char *get_trap_mode_suffix
   PARAMS ((void));
 static const char *get_round_mode_suffix
   PARAMS ((void));
+static const char *get_some_local_dynamic_name
+  PARAMS ((void));
+static int get_some_local_dynamic_name_1
+  PARAMS ((rtx *, void *));
 static rtx set_frame_related_p
   PARAMS ((void));
 static const char *alpha_lookup_xfloating_lib_func
@@ -154,18 +236,35 @@ static int alpha_adjust_cost
   PARAMS ((rtx, rtx, rtx, int));
 static int alpha_issue_rate
   PARAMS ((void));
-static int alpha_variable_issue
-  PARAMS ((FILE *, int, rtx, int));
+static int alpha_use_dfa_pipeline_interface
+  PARAMS ((void));
+static int alpha_multipass_dfa_lookahead
+  PARAMS ((void));
+static void alpha_reorg
+  PARAMS ((void));
 
-#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));
+#ifdef OBJECT_FORMAT_ELF
+static void alpha_elf_select_rtx_section
+  PARAMS ((enum machine_mode, rtx, unsigned HOST_WIDE_INT));
+#endif
+
+#if TARGET_ABI_OPEN_VMS
+static bool alpha_linkage_symbol_p
+  PARAMS ((const char *symname));
+static int alpha_write_one_linkage
+  PARAMS ((splay_tree_node, void *));
+static void alpha_write_linkage
+  PARAMS ((FILE *, const char *, tree));
+#endif
+
+#if TARGET_ABI_OSF
+static void alpha_output_mi_thunk_osf
+  PARAMS ((FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree));
 #endif
 
+static struct machine_function * alpha_init_machine_status
+  PARAMS ((void));
+
 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 *));
@@ -194,15 +293,44 @@ static void vms_asm_out_destructor PARAMS ((rtx, int));
 # define TARGET_SECTION_TYPE_FLAGS vms_section_type_flags
 #endif
 
+#undef TARGET_IN_SMALL_DATA_P
+#define TARGET_IN_SMALL_DATA_P alpha_in_small_data_p
+
 #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));
+static void unicosmk_unique_section PARAMS ((tree, 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
+# undef TARGET_ASM_UNIQUE_SECTION
+# define TARGET_ASM_UNIQUE_SECTION unicosmk_unique_section
+# undef TARGET_ASM_GLOBALIZE_LABEL
+# define TARGET_ASM_GLOBALIZE_LABEL hook_FILEptr_constcharptr_void
+#endif
+
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
+#undef TARGET_ASM_ALIGNED_DI_OP
+#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
+
+/* Default unaligned ops are provided for ELF systems.  To get unaligned
+   data for non-ELF systems, we have to turn off auto alignment.  */
+#ifndef OBJECT_FORMAT_ELF
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP "\t.align 0\n\t.word\t"
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP "\t.align 0\n\t.long\t"
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP "\t.align 0\n\t.quad\t"
+#endif
+
+#ifdef OBJECT_FORMAT_ELF
+#undef TARGET_ASM_SELECT_RTX_SECTION
+#define        TARGET_ASM_SELECT_RTX_SECTION  alpha_elf_select_rtx_section
 #endif
 
 #undef TARGET_ASM_FUNCTION_END_PROLOGUE
@@ -212,8 +340,40 @@ static unsigned int unicosmk_section_type_flags PARAMS ((tree, const char *,
 #define TARGET_SCHED_ADJUST_COST alpha_adjust_cost
 #undef TARGET_SCHED_ISSUE_RATE
 #define TARGET_SCHED_ISSUE_RATE alpha_issue_rate
-#undef TARGET_SCHED_VARIABLE_ISSUE
-#define TARGET_SCHED_VARIABLE_ISSUE alpha_variable_issue
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
+  alpha_use_dfa_pipeline_interface
+#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
+#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \
+  alpha_multipass_dfa_lookahead
+
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+
+#undef  TARGET_INIT_BUILTINS
+#define TARGET_INIT_BUILTINS alpha_init_builtins
+#undef  TARGET_EXPAND_BUILTIN
+#define TARGET_EXPAND_BUILTIN alpha_expand_builtin
+
+#undef TARGET_FUNCTION_OK_FOR_SIBCALL
+#define TARGET_FUNCTION_OK_FOR_SIBCALL alpha_function_ok_for_sibcall
+#undef TARGET_CANNOT_COPY_INSN_P
+#define TARGET_CANNOT_COPY_INSN_P alpha_cannot_copy_insn_p
+
+#if TARGET_ABI_OSF
+#undef TARGET_ASM_OUTPUT_MI_THUNK
+#define TARGET_ASM_OUTPUT_MI_THUNK alpha_output_mi_thunk_osf
+#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
+#define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
+#endif
+
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS alpha_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST hook_int_rtx_0
+
+#undef TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG alpha_reorg
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
@@ -334,6 +494,18 @@ override_options ()
        error ("bad value `%s' for -mfp-trap-mode switch", alpha_fptm_string);
     }
 
+  if (alpha_tls_size_string)
+    {
+      if (strcmp (alpha_tls_size_string, "16") == 0)
+       alpha_tls_size = 16;
+      else if (strcmp (alpha_tls_size_string, "32") == 0)
+       alpha_tls_size = 32;
+      else if (strcmp (alpha_tls_size_string, "64") == 0)
+       alpha_tls_size = 64;
+      else
+       error ("bad value `%s' for -mtls-size switch", alpha_tls_size_string);
+    }
+
   alpha_cpu
     = TARGET_CPU_DEFAULT & MASK_CPU_EV6 ? PROCESSOR_EV6
       : (TARGET_CPU_DEFAULT & MASK_CPU_EV5 ? PROCESSOR_EV5 : PROCESSOR_EV4);
@@ -476,12 +648,16 @@ override_options ()
 
   /* 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
+
+  /* Tell the compiler when we're using VAX floating point.  */
+  if (TARGET_FLOAT_VAX)
+    {
+      real_format_for_mode[SFmode - QFmode] = &vax_f_format;
+      real_format_for_mode[DFmode - QFmode] = &vax_g_format;
+      real_format_for_mode[TFmode - QFmode] = NULL;
+    }
 }
 \f
 /* Returns 1 if VALUE is a mask that contains full bytes of zero or ones.  */
@@ -508,7 +684,7 @@ reg_or_0_operand (op, mode)
       register rtx op;
       enum machine_mode mode;
 {
-  return op == const0_rtx || register_operand (op, mode);
+  return op == CONST0_RTX (mode) || register_operand (op, mode);
 }
 
 /* Return 1 if OP is a constant in the range of 0-63 (for a shift) or
@@ -537,6 +713,16 @@ reg_or_8bit_operand (op, mode)
          || register_operand (op, mode));
 }
 
+/* Return 1 if OP is a constant or any register.  */
+
+int
+reg_or_const_int_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  return GET_CODE (op) == CONST_INT || register_operand (op, mode);
+}
+
 /* Return 1 if OP is an 8-bit constant.  */
 
 int
@@ -643,24 +829,26 @@ mode_mask_operand (op, mode)
      register rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-#if HOST_BITS_PER_WIDE_INT == 32
-  if (GET_CODE (op) == CONST_DOUBLE)
-    return (CONST_DOUBLE_LOW (op) == -1
-           && (CONST_DOUBLE_HIGH (op) == -1
-               || CONST_DOUBLE_HIGH (op) == 0));
-#else
-  if (GET_CODE (op) == CONST_DOUBLE)
-    return (CONST_DOUBLE_LOW (op) == -1 && CONST_DOUBLE_HIGH (op) == 0);
-#endif
+  if (GET_CODE (op) == CONST_INT)
+    {
+      HOST_WIDE_INT value = INTVAL (op);
 
-  return (GET_CODE (op) == CONST_INT
-         && (INTVAL (op) == 0xff
-             || INTVAL (op) == 0xffff
-             || INTVAL (op) == (HOST_WIDE_INT)0xffffffff
-#if HOST_BITS_PER_WIDE_INT == 64
-             || INTVAL (op) == -1
-#endif
-             ));
+      if (value == 0xff)
+       return 1;
+      if (value == 0xffff)
+       return 1;
+      if (value == 0xffffffff)
+       return 1;
+      if (value == -1)
+       return 1;
+    }
+  else if (HOST_BITS_PER_WIDE_INT == 32 && GET_CODE (op) == CONST_DOUBLE)
+    {
+      if (CONST_DOUBLE_LOW (op) == 0xffffffff && CONST_DOUBLE_HIGH (op) == 0)
+       return 1;
+    }
+
+  return 0;
 }
 
 /* Return 1 if OP is a multiple of 8 less than 64.  */
@@ -675,25 +863,14 @@ mul8_operand (op, mode)
          && (INTVAL (op) & 7) == 0);
 }
 
-/* Return 1 if OP is the constant zero in floating-point.  */
+/* Return 1 if OP is the zero constant for MODE.  */
 
 int
-fp0_operand (op, mode)
+const0_operand (op, mode)
      register rtx op;
      enum machine_mode mode;
 {
-  return (GET_MODE (op) == mode
-         && GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode));
-}
-
-/* Return 1 if OP is the floating-point constant zero or a register.  */
-
-int
-reg_or_fp0_operand (op, mode)
-     register rtx op;
-     enum machine_mode mode;
-{
-  return fp0_operand (op, mode) || register_operand (op, mode);
+  return op == CONST0_RTX (mode);
 }
 
 /* Return 1 if OP is a hard floating-point register.  */
@@ -751,8 +928,15 @@ some_operand (op, mode)
 
   switch (GET_CODE (op))
     {
-    case REG:  case MEM:  case CONST_DOUBLE:  case CONST_INT:  case LABEL_REF:
-    case SYMBOL_REF:  case CONST:
+    case REG:
+    case MEM:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case CONST_VECTOR:
+    case LABEL_REF:
+    case SYMBOL_REF:
+    case CONST:
+    case HIGH:
       return 1;
 
     case SUBREG:
@@ -800,11 +984,24 @@ input_operand (op, mode)
     case SYMBOL_REF:
     case CONST:
       if (TARGET_EXPLICIT_RELOCS)
-       return 0;
+       {
+         /* We don't split symbolic operands into something unintelligable
+            until after reload, but we do not wish non-small, non-global
+            symbolic operands to be reconstructed from their high/lo_sum
+            form.  */
+         return (small_symbolic_operand (op, mode)
+                 || global_symbolic_operand (op, mode)
+                 || gotdtp_symbolic_operand (op, mode)
+                 || gottp_symbolic_operand (op, mode));
+       }
 
       /* This handles both the Windows/NT and OSF cases.  */
       return mode == ptr_mode || mode == DImode;
 
+    case HIGH:
+      return (TARGET_EXPLICIT_RELOCS
+             && local_symbolic_operand (XEXP (op, 0), mode));
+
     case REG:
     case ADDRESSOF:
       return 1;
@@ -818,7 +1015,8 @@ input_operand (op, mode)
              && general_operand (op, mode));
 
     case CONST_DOUBLE:
-      return GET_MODE_CLASS (mode) == MODE_FLOAT && op == CONST0_RTX (mode);
+    case CONST_VECTOR:
+      return op == CONST0_RTX (mode);
 
     case CONST_INT:
       return mode == QImode || mode == HImode || add_operand (op, mode);
@@ -837,25 +1035,32 @@ input_operand (op, mode)
    file, and in the same section as the current function.  */
 
 int
-current_file_function_operand (op, mode)
+samegp_function_operand (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
+    return false;
 
   /* Easy test for recursion.  */
   if (op == XEXP (DECL_RTL (current_function_decl), 0))
-    return 1;
+    return true;
 
-  /* Otherwise, we need the DECL for the SYMBOL_REF, which we can't get.
-     So SYMBOL_REF_FLAG has been declared to imply that the function is
-     in the default text section.  So we must also check that the current
-     function is also in the text section.  */
-  if (SYMBOL_REF_FLAG (op) && decl_in_text_section (current_function_decl))
-    return 1;
+  /* Functions that are not local can be overridden, and thus may
+     not share the same gp.  */
+  if (! SYMBOL_REF_LOCAL_P (op))
+    return false;
 
-  return 0;
+  /* If -msmall-data is in effect, assume that there is only one GP
+     for the module, and so any local symbol has this property.  We
+     need explicit relocations to be able to enforce this for symbols
+     not defined in this unit of translation, however.  */
+  if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
+    return true;
+
+  /* Functions that are not external are defined in this UoT,
+     and thus must share the same gp.  */
+  return ! SYMBOL_REF_EXTERNAL_P (op);
 }
 
 /* Return 1 if OP is a SYMBOL_REF for which we can make a call via bsr.  */
@@ -865,43 +1070,55 @@ direct_call_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  /* Must be defined in this file.  */
-  if (! current_file_function_operand (op, mode))
-    return 0;
+  tree op_decl, cfun_sec, op_sec;
+
+  /* Must share the same GP.  */
+  if (!samegp_function_operand (op, mode))
+    return false;
 
   /* If profiling is implemented via linker tricks, we can't jump
-     to the nogp alternate entry point.  */
+     to the nogp alternate entry point.  Note that current_function_profile
+     would not be correct, since that doesn't indicate if the target
+     function uses profiling.  */
   /* ??? TARGET_PROFILING_NEEDS_GP isn't really the right test,
      but is approximately correct for the OSF ABIs.  Don't know
      what to do for VMS, NT, or UMK.  */
-  if (! TARGET_PROFILING_NEEDS_GP
-      && ! profile_flag)
-    return 0;
-
-  return 1;
-}
+  if (!TARGET_PROFILING_NEEDS_GP && profile_flag)
+    return false;
 
-/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
-   a variable known to be defined in this file.  */
+  /* Must be a function.  In some cases folks create thunks in static
+     data structures and then make calls to them.  If we allow the
+     direct call, we'll get an error from the linker about !samegp reloc
+     against a symbol without a .prologue directive.  */
+  if (!SYMBOL_REF_FUNCTION_P (op))
+    return false;
+  
+  /* Must be "near" so that the branch is assumed to reach.  With
+     -msmall-text, this is assumed true of all local symbols.  Since
+     we've already checked samegp, locality is already assured.  */
+  if (TARGET_SMALL_TEXT)
+    return true;
 
-static bool
-local_symbol_p (op)
-     rtx op;
-{
-  const char *str = XSTR (op, 0);
+  /* Otherwise, a decl is "near" if it is defined in the same section.  */
+  if (flag_function_sections)
+    return false;
 
-  /* ??? SYMBOL_REF_FLAG is set for local function symbols, but we
-     run into problems with the rtl inliner in that the symbol was
-     once external, but is local after inlining, which results in
-     unrecognizable insns.  */
+  op_decl = SYMBOL_REF_DECL (op);
+  if (DECL_ONE_ONLY (current_function_decl)
+      || (op_decl && DECL_ONE_ONLY (op_decl)))
+    return false;
 
-  return (CONSTANT_POOL_ADDRESS_P (op)
-         /* If @, then ENCODE_SECTION_INFO sez it's local.  */
-         || str[0] == '@'
-         /* If *$, then ASM_GENERATE_INTERNAL_LABEL sez it's local.  */
-         || (str[0] == '*' && str[1] == '$'));
+  cfun_sec = DECL_SECTION_NAME (current_function_decl);
+  op_sec = op_decl ? DECL_SECTION_NAME (op_decl) : NULL;
+  return ((!cfun_sec && !op_sec)
+         || (cfun_sec && op_sec
+             && strcmp (TREE_STRING_POINTER (cfun_sec),
+                        TREE_STRING_POINTER (op_sec)) == 0));
 }
 
+/* Return true if OP is a LABEL_REF, or SYMBOL_REF or CONST referencing
+   a (non-tls) variable known to be defined in this file.  */
+
 int
 local_symbolic_operand (op, mode)
      rtx op;
@@ -921,7 +1138,7 @@ local_symbolic_operand (op, mode)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
-  return local_symbol_p (op);
+  return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
 }
 
 /* Return true if OP is a SYMBOL_REF or CONST referencing a variable
@@ -932,8 +1149,6 @@ small_symbolic_operand (op, mode)
      rtx op;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
-  const char *str;
-
   if (! TARGET_SMALL_DATA)
     return 0;
 
@@ -948,13 +1163,14 @@ small_symbolic_operand (op, mode)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
+  /* ??? There's no encode_section_info equivalent for the rtl
+     constant pool, so SYMBOL_FLAG_SMALL never gets set.  */
   if (CONSTANT_POOL_ADDRESS_P (op))
-    return GET_MODE_SIZE (get_pool_mode (op)) <= (unsigned) g_switch_value;
-  else
-    {
-      str = XSTR (op, 0);
-      return str[0] == '@' && str[1] == 's';
-    }
+    return GET_MODE_SIZE (get_pool_mode (op)) <= g_switch_value;
+
+  return (SYMBOL_REF_LOCAL_P (op)
+         && SYMBOL_REF_SMALL_P (op)
+         && SYMBOL_REF_TLS_MODEL (op) == 0);
 }
 
 /* Return true if OP is a SYMBOL_REF or CONST referencing a variable
@@ -976,7 +1192,7 @@ global_symbolic_operand (op, mode)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
-  return ! local_symbol_p (op);
+  return !SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
 }
 
 /* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
@@ -992,7 +1208,12 @@ call_operand (op, mode)
   if (GET_CODE (op) == REG)
     {
       if (TARGET_ABI_OSF)
-       return REGNO (op) == 27;
+       {
+         /* Disallow virtual registers to cope with pathalogical test cases
+            such as compile/930117-1.c in which the virtual reg decomposes
+            to the frame pointer.  Which is a hard reg that is not $27.  */
+         return (REGNO (op) == 27 || REGNO (op) > LAST_VIRTUAL_REGISTER);
+       }
       else
        return 1;
     }
@@ -1024,6 +1245,112 @@ symbolic_operand (op, mode)
   return 0;
 }
 
+/* Return true if OP is valid for a particular TLS relocation.  */
+
+static int
+tls_symbolic_operand_1 (op, mode, size, unspec)
+     rtx op;
+     enum machine_mode mode;
+     int size, unspec;
+{
+  if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  if (GET_CODE (op) != CONST)
+    return 0;
+  op = XEXP (op, 0);
+
+  if (GET_CODE (op) != UNSPEC || XINT (op, 1) != unspec)
+    return 0;
+  op = XVECEXP (op, 0, 0);
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  if (SYMBOL_REF_LOCAL_P (op))
+    {
+      if (alpha_tls_size > size)
+       return 0;
+    }
+  else
+    {
+      if (size != 64)
+       return 0;
+    }
+
+  switch (SYMBOL_REF_TLS_MODEL (op))
+    {
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      return unspec == UNSPEC_DTPREL;
+    case TLS_MODEL_INITIAL_EXEC:
+      return unspec == UNSPEC_TPREL && size == 64;
+    case TLS_MODEL_LOCAL_EXEC:
+      return unspec == UNSPEC_TPREL;
+    default:
+      abort ();
+    }
+}
+
+/* Return true if OP is valid for 16-bit DTP relative relocations.  */
+
+int
+dtp16_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_DTPREL);
+}
+
+/* Return true if OP is valid for 32-bit DTP relative relocations.  */
+
+int
+dtp32_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_DTPREL);
+}
+
+/* Return true if OP is valid for 64-bit DTP relative relocations.  */
+
+int
+gotdtp_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_DTPREL);
+}
+
+/* Return true if OP is valid for 16-bit TP relative relocations.  */
+
+int
+tp16_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 16, UNSPEC_TPREL);
+}
+
+/* Return true if OP is valid for 32-bit TP relative relocations.  */
+
+int
+tp32_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 32, UNSPEC_TPREL);
+}
+
+/* Return true if OP is valid for 64-bit TP relative relocations.  */
+
+int
+gottp_symbolic_operand (op, mode)
+      rtx op;
+      enum machine_mode mode;
+{
+  return tls_symbolic_operand_1 (op, mode, 64, UNSPEC_TPREL);
+}
+
 /* Return 1 if OP is a valid Alpha comparison operator.  Here we know which
    comparisons are valid in which insn.  */
 
@@ -1309,7 +1636,7 @@ reg_no_subreg_operand (op, mode)
      register rtx op;
      enum machine_mode mode;
 {
-  if (GET_CODE (op) == SUBREG)
+  if (GET_CODE (op) != REG)
     return 0;
   return register_operand (op, mode);
 }
@@ -1333,6 +1660,102 @@ addition_operation (op, mode)
   return 0;
 }
 
+/* Implements CONST_OK_FOR_LETTER_P.  Return true if the value matches
+   the range defined for C in [I-P].  */
+
+bool
+alpha_const_ok_for_letter_p (value, c)
+     HOST_WIDE_INT value;
+     int c;
+{
+  switch (c)
+    {
+    case 'I':
+      /* An unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) value < 0x100;
+    case 'J':
+      /* The constant zero.  */
+      return value == 0;
+    case 'K':
+      /* A signed 16 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (value + 0x8000) < 0x10000;
+    case 'L':
+      /* A shifted signed 16 bit constant appropriate for LDAH.  */
+      return ((value & 0xffff) == 0
+              && ((value) >> 31 == -1 || value >> 31 == 0));
+    case 'M':
+      /* A constant that can be AND'ed with using a ZAP insn.  */
+      return zap_mask (value);
+    case 'N':
+      /* A complemented unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (~ value) < 0x100;
+    case 'O':
+      /* A negated unsigned 8 bit constant.  */
+      return (unsigned HOST_WIDE_INT) (- value) < 0x100;
+    case 'P':
+      /* The constant 1, 2 or 3.  */
+      return value == 1 || value == 2 || value == 3;
+
+    default:
+      return false;
+    }
+}
+
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
+   matches for C in [GH].  */
+
+bool
+alpha_const_double_ok_for_letter_p (value, c)
+     rtx value;
+     int c;
+{
+  switch (c)
+    {
+    case 'G':
+      /* The floating point zero constant.  */
+      return (GET_MODE_CLASS (GET_MODE (value)) == MODE_FLOAT
+             && value == CONST0_RTX (GET_MODE (value)));
+
+    case 'H':
+      /* A valid operand of a ZAP insn.  */
+      return (GET_MODE (value) == VOIDmode
+             && zap_mask (CONST_DOUBLE_LOW (value))
+             && zap_mask (CONST_DOUBLE_HIGH (value)));
+
+    default:
+      return false;
+    }
+}
+
+/* Implements CONST_DOUBLE_OK_FOR_LETTER_P.  Return true if VALUE
+   matches for C.  */
+
+bool
+alpha_extra_constraint (value, c)
+     rtx value;
+     int c;
+{
+  switch (c)
+    {
+    case 'Q':
+      return normal_memory_operand (value, VOIDmode);
+    case 'R':
+      return direct_call_operand (value, Pmode);
+    case 'S':
+      return (GET_CODE (value) == CONST_INT
+             && (unsigned HOST_WIDE_INT) INTVAL (value) < 64);
+    case 'T':
+      return GET_CODE (value) == HIGH;
+    case 'U':
+      return TARGET_ABI_UNICOSMK && symbolic_operand (value, VOIDmode);
+    case 'W':
+      return (GET_CODE (value) == CONST_VECTOR
+             && value == CONST0_RTX (GET_MODE (value)));
+    default:
+      return false;
+    }
+}
+
 /* Return 1 if this function can directly return via $26.  */
 
 int
@@ -1400,145 +1823,103 @@ alpha_tablejump_best_label (insn)
 
   return best_label ? best_label : const0_rtx;
 }
-\f
-/* Return true if the function DECL will be placed in the default text
-   section.  */
-/* ??? Ideally we'd be able to always move from a SYMBOL_REF back to the
-   decl, as that would allow us to determine if two functions are in the
-   same section, which is what we really want to know.  */
 
-static bool
-decl_in_text_section (decl)
-     tree decl;
+/* Return the TLS model to use for SYMBOL.  */
+
+static enum tls_model
+tls_symbolic_operand_type (symbol)
+     rtx symbol;
 {
-  return (DECL_SECTION_NAME (decl) == NULL_TREE
-         && ! (flag_function_sections
-               || (targetm.have_named_sections
-                   && DECL_ONE_ONLY (decl))));
-}
+  enum tls_model model;
 
-/* If we are referencing a function that is static, make the SYMBOL_REF
-   special.  We use this to see indicate we can branch to this function
-   without setting PV or restoring GP. 
+  if (GET_CODE (symbol) != SYMBOL_REF)
+    return 0;
+  model = SYMBOL_REF_TLS_MODEL (symbol);
 
-   If this is a variable that is known to be defined locally, add "@v"
-   to the name.  If in addition the variable is to go in .sdata/.sbss,
-   then add "@s" instead.  */
+  /* Local-exec with a 64-bit size is the same code as initial-exec.  */
+  if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64)
+    model = TLS_MODEL_INITIAL_EXEC;
 
-void
-alpha_encode_section_info (decl)
+  return model;
+}
+\f
+/* Return true if the function DECL will share the same GP as any
+   function in the current unit of translation.  */
+
+static bool
+decl_has_samegp (decl)
      tree decl;
 {
-  const char *symbol_str;
-  bool is_local, is_small;
-
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* We mark public functions once they are emitted; otherwise we
-        don't know that they exist in this unit of translation.  */
-      if (TREE_PUBLIC (decl))
-       return;
-      /* Do not mark functions that are not in .text; otherwise we
-        don't know that they are near enough for a direct branch.  */
-      if (! decl_in_text_section (decl))
-       return;
+  /* Functions that are not local can be overridden, and thus may
+     not share the same gp.  */
+  if (!(*targetm.binds_local_p) (decl))
+    return false;
 
-      SYMBOL_REF_FLAG (XEXP (DECL_RTL (decl), 0)) = 1;
-      return;
-    }
+  /* If -msmall-data is in effect, assume that there is only one GP
+     for the module, and so any local symbol has this property.  We
+     need explicit relocations to be able to enforce this for symbols
+     not defined in this unit of translation, however.  */
+  if (TARGET_EXPLICIT_RELOCS && TARGET_SMALL_DATA)
+    return true;
 
-  /* Early out if we're not going to do anything with this data.  */
-  if (! TARGET_EXPLICIT_RELOCS)
-    return;
+  /* Functions that are not external are defined in this UoT.  */
+  /* ??? Irritatingly, static functions not yet emitted are still
+     marked "external".  Apply this to non-static functions only.  */
+  return !TREE_PUBLIC (decl) || !DECL_EXTERNAL (decl);
+}
 
-  /* Careful not to prod global register variables.  */
-  if (TREE_CODE (decl) != VAR_DECL
-      || GET_CODE (DECL_RTL (decl)) != MEM
-      || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
-    return;
-    
-  symbol_str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
-
-  /* A variable is considered "local" if it is defined in this module.  */
-
-  if (DECL_EXTERNAL (decl))
-    is_local = false;
-  /* Linkonce and weak data is never local.  */
-  else if (DECL_ONE_ONLY (decl) || DECL_WEAK (decl))
-    is_local = false;
-  else if (! TREE_PUBLIC (decl))
-    is_local = true;
-  /* If PIC, then assume that any global name can be overridden by
-     symbols resolved from other modules.  */
-  else if (flag_pic)
-    is_local = false;
-  /* Uninitialized COMMON variable may be unified with symbols
-     resolved from other modules.  */
-  else if (DECL_COMMON (decl)
-          && (DECL_INITIAL (decl) == NULL
-              || DECL_INITIAL (decl) == error_mark_node))
-    is_local = false;
-  /* Otherwise we're left with initialized (or non-common) global data
-     which is of necessity defined locally.  */
-  else
-    is_local = true;
+/* Return true if EXP should be placed in the small data section.  */
 
-  /* Determine if DECL will wind up in .sdata/.sbss.  */
+static bool
+alpha_in_small_data_p (exp)
+     tree exp;
+{
+  /* We want to merge strings, so we never consider them small data.  */
+  if (TREE_CODE (exp) == STRING_CST)
+    return false;
 
-  is_small = false;
-  if (DECL_SECTION_NAME (decl))
+  if (TREE_CODE (exp) == VAR_DECL && DECL_SECTION_NAME (exp))
     {
-      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (decl));
+      const char *section = TREE_STRING_POINTER (DECL_SECTION_NAME (exp));
       if (strcmp (section, ".sdata") == 0
          || strcmp (section, ".sbss") == 0)
-       is_small = true;
+       return true;
     }
   else
     {
-      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (decl));
+      HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (exp));
 
-      /* If the variable has already been defined in the output file, then it
-        is too late to put it in sdata if it wasn't put there in the first
-        place.  The test is here rather than above, because if it is already
-        in sdata, then it can stay there.  */
+      /* If this is an incomplete type with size 0, then we can't put it
+        in sdata because it might be too big when completed.  */
+      if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
+       return true;
+    }
 
-      if (TREE_ASM_WRITTEN (decl))
-       ;
-
-      /* If this is an incomplete type with size 0, then we can't put it in
-        sdata because it might be too big when completed.  */
-      else if (size > 0 && size <= g_switch_value)
-       is_small = true;
-    }
-
-  /* Finally, encode this into the symbol string.  */
-  if (is_local)
-    {
-      const char *string;
-      char *newstr;
-      size_t len;
+  return false;
+}
 
-      if (symbol_str[0] == '@')
-       {
-         if (symbol_str[1] == (is_small ? 's' : 'v'))
-           return;
-         symbol_str += 2;
-       }
+#if TARGET_ABI_OPEN_VMS
+static bool
+alpha_linkage_symbol_p (symname)
+     const char *symname;
+{
+  int symlen = strlen (symname);
 
-      len = strlen (symbol_str) + 1;
-      newstr = alloca (len + 2);
+  if (symlen > 4)
+    return strcmp (&symname [symlen - 4], "..lk") == 0;
 
-      newstr[0] = '@';
-      newstr[1] = (is_small ? 's' : 'v');
-      memcpy (newstr + 2, symbol_str, len);
-         
-      string = ggc_alloc_string (newstr, len + 2 - 1);
-      XSTR (XEXP (DECL_RTL (decl), 0), 0) = string;
-    }
-  else if (symbol_str[0] == '@')
-    abort ();
+  return false;
 }
 
+#define LINKAGE_SYMBOL_REF_P(X) \
+  ((GET_CODE (X) == SYMBOL_REF   \
+    && alpha_linkage_symbol_p (XSTR (X, 0))) \
+   || (GET_CODE (X) == CONST                 \
+       && GET_CODE (XEXP (X, 0)) == PLUS     \
+       && GET_CODE (XEXP (XEXP (X, 0), 0)) == SYMBOL_REF \
+       && alpha_linkage_symbol_p (XSTR (XEXP (XEXP (X, 0), 0), 0))))
+#endif
+
 /* legitimate_address_p recognizes an RTL expression that is a valid
    memory address for an instruction.  The MODE argument is the
    machine mode for the MEM expression that wants to use this address.
@@ -1578,6 +1959,11 @@ alpha_legitimate_address_p (mode, x, strict)
   if (CONSTANT_ADDRESS_P (x))
     return true;
 
+#if TARGET_ABI_OPEN_VMS
+  if (LINKAGE_SYMBOL_REF_P (x))
+    return true;
+#endif
+
   /* Register plus a small constant offset is valid.  */
   if (GET_CODE (x) == PLUS)
     {
@@ -1607,40 +1993,61 @@ alpha_legitimate_address_p (mode, x, strict)
        return true;
     }
 
-  /* If we're managing explicit relocations, LO_SUM is valid.  */
-  else if (TARGET_EXPLICIT_RELOCS && GET_CODE (x) == LO_SUM)
+  /* If we're managing explicit relocations, LO_SUM is valid, as
+     are small data symbols.  */
+  else if (TARGET_EXPLICIT_RELOCS)
     {
-      rtx ofs = XEXP (x, 1);
-      x = XEXP (x, 0);
-
-      /* Discard non-paradoxical subregs.  */
-      if (GET_CODE (x) == SUBREG
-          && (GET_MODE_SIZE (GET_MODE (x))
-             < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
-       x = SUBREG_REG (x);
-
-      /* Must have a valid base register.  */
-      if (! (REG_P (x)
-            && (strict
-                ? STRICT_REG_OK_FOR_BASE_P (x)
-                : NONSTRICT_REG_OK_FOR_BASE_P (x))))
-       return false;
-
-      /* The symbol must be local.  */
-      if (local_symbolic_operand (ofs, Pmode))
+      if (small_symbolic_operand (x, Pmode))
        return true;
+
+      if (GET_CODE (x) == LO_SUM)
+       {
+         rtx ofs = XEXP (x, 1);
+         x = XEXP (x, 0);
+
+         /* Discard non-paradoxical subregs.  */
+         if (GET_CODE (x) == SUBREG
+             && (GET_MODE_SIZE (GET_MODE (x))
+                 < GET_MODE_SIZE (GET_MODE (SUBREG_REG (x)))))
+           x = SUBREG_REG (x);
+
+         /* Must have a valid base register.  */
+         if (! (REG_P (x)
+                && (strict
+                    ? STRICT_REG_OK_FOR_BASE_P (x)
+                    : NONSTRICT_REG_OK_FOR_BASE_P (x))))
+           return false;
+
+         /* The symbol must be local.  */
+         if (local_symbolic_operand (ofs, Pmode)
+             || dtp32_symbolic_operand (ofs, Pmode)
+             || tp32_symbolic_operand (ofs, Pmode))
+           return true;
+       }
     }
 
   return false;
 }
 
+/* Build the SYMBOL_REF for __tls_get_addr.  */
+
+static GTY(()) rtx tls_get_addr_libfunc;
+
+static rtx
+get_tls_get_addr ()
+{
+  if (!tls_get_addr_libfunc)
+    tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
+  return tls_get_addr_libfunc;
+}
+
 /* Try machine-dependent ways of modifying an illegitimate address
    to be legitimate.  If we find one, return the new, valid address.  */
 
 rtx
-alpha_legitimize_address (x, oldx, mode)
+alpha_legitimize_address (x, scratch, mode)
      rtx x;
-     rtx oldx ATTRIBUTE_UNUSED;
+     rtx scratch;
      enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   HOST_WIDE_INT addend;
@@ -1662,7 +2069,8 @@ alpha_legitimize_address (x, oldx, mode)
      part of the CONST_INT.  Then load FOO plus any high-order part of the
      CONST_INT into a register.  Our address is (plus reg low-part-const).
      This is done to reduce the number of GOT entries.  */
-  if (GET_CODE (x) == CONST
+  if (!no_new_pseudos
+      && GET_CODE (x) == CONST
       && GET_CODE (XEXP (x, 0)) == PLUS
       && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)
     {
@@ -1674,7 +2082,8 @@ alpha_legitimize_address (x, oldx, mode)
   /* If we have a (plus reg const), emit the load as in (2), then add
      the two registers, and finally generate (plus reg low-part-const) as
      our address.  */
-  if (GET_CODE (x) == PLUS
+  if (!no_new_pseudos
+      && GET_CODE (x) == PLUS
       && GET_CODE (XEXP (x, 0)) == REG
       && GET_CODE (XEXP (x, 1)) == CONST
       && GET_CODE (XEXP (XEXP (x, 1), 0)) == PLUS
@@ -1690,33 +2099,112 @@ alpha_legitimize_address (x, oldx, mode)
   /* If this is a local symbol, split the address into HIGH/LO_SUM parts.  */
   if (TARGET_EXPLICIT_RELOCS && symbolic_operand (x, Pmode))
     {
-      rtx scratch;
-      if (local_symbolic_operand (x, Pmode))
+      rtx r0, r16, eqv, tga, tp, insn, dest, seq;
+
+      switch (tls_symbolic_operand_type (x))
        {
-         if (small_symbolic_operand (x, Pmode))
-           scratch = pic_offset_table_rtx;
-         else
-           {
-             rtx insn, tmp;
+       case TLS_MODEL_GLOBAL_DYNAMIC:
+         start_sequence ();
+
+         r0 = gen_rtx_REG (Pmode, 0);
+         r16 = gen_rtx_REG (Pmode, 16);
+         tga = get_tls_get_addr ();
+         dest = gen_reg_rtx (Pmode);
+         seq = GEN_INT (alpha_next_sequence_number++);
+         
+         emit_insn (gen_movdi_er_tlsgd (r16, pic_offset_table_rtx, x, seq));
+         insn = gen_call_value_osf_tlsgd (r0, tga, seq);
+         insn = emit_call_insn (insn);
+         CONST_OR_PURE_CALL_P (insn) = 1;
+         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
 
-             scratch = gen_reg_rtx (Pmode);
+          insn = get_insns ();
+         end_sequence ();
+
+         emit_libcall_block (insn, dest, r0, x);
+         return dest;
+
+       case TLS_MODEL_LOCAL_DYNAMIC:
+         start_sequence ();
+
+         r0 = gen_rtx_REG (Pmode, 0);
+         r16 = gen_rtx_REG (Pmode, 16);
+         tga = get_tls_get_addr ();
+         scratch = gen_reg_rtx (Pmode);
+         seq = GEN_INT (alpha_next_sequence_number++);
+
+         emit_insn (gen_movdi_er_tlsldm (r16, pic_offset_table_rtx, seq));
+         insn = gen_call_value_osf_tlsldm (r0, tga, seq);
+         insn = emit_call_insn (insn);
+         CONST_OR_PURE_CALL_P (insn) = 1;
+         use_reg (&CALL_INSN_FUNCTION_USAGE (insn), r16);
+
+          insn = get_insns ();
+         end_sequence ();
 
-             tmp = gen_rtx_HIGH (Pmode, x);
-             tmp = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp);
-              insn = emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp));
-             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, tmp,
-                                                   REG_NOTES (insn));
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+                               UNSPEC_TLSLDM_CALL);
+         emit_libcall_block (insn, scratch, r0, eqv);
+
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_DTPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
+
+         if (alpha_tls_size == 64)
+           {
+             dest = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, dest, eqv));
+             emit_insn (gen_adddi3 (dest, dest, scratch));
+             return dest;
+           }
+         if (alpha_tls_size == 32)
+           {
+             insn = gen_rtx_HIGH (Pmode, eqv);
+             insn = gen_rtx_PLUS (Pmode, scratch, insn);
+             scratch = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, scratch, insn));
            }
+         return gen_rtx_LO_SUM (Pmode, scratch, eqv);
+
+       case TLS_MODEL_INITIAL_EXEC:
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
+         tp = gen_reg_rtx (Pmode);
+         scratch = gen_reg_rtx (Pmode);
+         dest = gen_reg_rtx (Pmode);
 
-         return gen_rtx_LO_SUM (Pmode, scratch, x);
+         emit_insn (gen_load_tp (tp));
+         emit_insn (gen_rtx_SET (VOIDmode, scratch, eqv));
+         emit_insn (gen_adddi3 (dest, tp, scratch));
+         return dest;
+
+       case TLS_MODEL_LOCAL_EXEC:
+         eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, x), UNSPEC_TPREL);
+         eqv = gen_rtx_CONST (Pmode, eqv);
+         tp = gen_reg_rtx (Pmode);
+
+         emit_insn (gen_load_tp (tp));
+         if (alpha_tls_size == 32)
+           {
+             insn = gen_rtx_HIGH (Pmode, eqv);
+             insn = gen_rtx_PLUS (Pmode, tp, insn);
+             tp = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, tp, insn));
+           }
+         return gen_rtx_LO_SUM (Pmode, tp, eqv);
        }
-      else
+
+      if (local_symbolic_operand (x, Pmode))
        {
-         scratch = gen_reg_rtx (Pmode);
-         emit_insn (gen_movdi_er_high_g (scratch, pic_offset_table_rtx,
-                                         x, const0_rtx));
-         /* ??? FIXME: Tag the use of scratch with a lituse.  */
-         return scratch;
+         if (small_symbolic_operand (x, Pmode))
+           return x;
+         else
+           {
+             if (!no_new_pseudos)
+               scratch = gen_reg_rtx (Pmode);
+             emit_insn (gen_rtx_SET (VOIDmode, scratch,
+                                     gen_rtx_HIGH (Pmode, x)));
+             return gen_rtx_LO_SUM (Pmode, scratch, x);
+           }
        }
     }
 
@@ -1724,14 +2212,145 @@ alpha_legitimize_address (x, oldx, mode)
 
  split_addend:
   {
-    HOST_WIDE_INT lowpart = (addend & 0xffff) - 2 * (addend & 0x8000);
-    HOST_WIDE_INT highpart = addend - lowpart;
-    x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (highpart),
-                            NULL_RTX, 1, OPTAB_LIB_WIDEN);
-    return plus_constant (x, lowpart);
+    HOST_WIDE_INT low, high;
+
+    low = ((addend & 0xffff) ^ 0x8000) - 0x8000;
+    addend -= low;
+    high = ((addend & 0xffffffff) ^ 0x80000000) - 0x80000000;
+    addend -= high;
+
+    if (addend)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (addend),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
+    if (high)
+      x = expand_simple_binop (Pmode, PLUS, x, GEN_INT (high),
+                              (no_new_pseudos ? scratch : NULL_RTX),
+                              1, OPTAB_LIB_WIDEN);
+
+    return plus_constant (x, low);
   }
 }
 
+/* We do not allow indirect calls to be optimized into sibling calls, nor
+   can we allow a call to a function with a different GP to be optimized
+   into a sibcall.  */
+
+static bool
+alpha_function_ok_for_sibcall (decl, exp)
+     tree decl;
+     tree exp ATTRIBUTE_UNUSED;
+{
+  /* Can't do indirect tail calls, since we don't know if the target
+     uses the same GP.  */
+  if (!decl)
+    return false;
+
+  /* Otherwise, we can make a tail call if the target function shares
+     the same GP.  */
+  return decl_has_samegp (decl);
+}
+
+/* For TARGET_EXPLICIT_RELOCS, we don't obfuscate a SYMBOL_REF to a
+   small symbolic operand until after reload.  At which point we need
+   to replace (mem (symbol_ref)) with (mem (lo_sum $29 symbol_ref))
+   so that sched2 has the proper dependency information.  */
+
+int
+some_small_symbolic_operand (x, mode)
+     rtx x;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return for_each_rtx (&x, some_small_symbolic_operand_1, NULL);
+}
+
+static int
+some_small_symbolic_operand_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
+
+  return small_symbolic_operand (x, Pmode) != 0;
+}
+
+rtx
+split_small_symbolic_operand (x)
+     rtx x;
+{
+  x = copy_insn (x);
+  for_each_rtx (&x, split_small_symbolic_operand_1, NULL);
+  return x;
+}
+
+static int
+split_small_symbolic_operand_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  /* Don't re-split.  */
+  if (GET_CODE (x) == LO_SUM)
+    return -1;
+
+  if (small_symbolic_operand (x, Pmode))
+    {
+      x = gen_rtx_LO_SUM (Pmode, pic_offset_table_rtx, x);
+      *px = x;
+      return -1;
+    }
+
+  return 0;
+}
+
+/* Indicate that INSN cannot be duplicated.  This is true for any insn
+   that we've marked with gpdisp relocs, since those have to stay in
+   1-1 correspondence with one another.
+
+   Techinically we could copy them if we could set up a mapping from one
+   sequence number to another, across the set of insns to be duplicated.
+   This seems overly complicated and error-prone since interblock motion
+   from sched-ebb could move one of the pair of insns to a different block.  */
+
+static bool
+alpha_cannot_copy_insn_p (insn)
+     rtx insn;
+{
+  rtx pat;
+
+  if (!reload_completed || !TARGET_EXPLICIT_RELOCS)
+    return false;
+
+  if (GET_CODE (insn) != INSN)
+    return false;
+  if (asm_noperands (insn) >= 0)
+    return false;
+
+  pat = PATTERN (insn);
+  if (GET_CODE (pat) != SET)
+    return false;
+  pat = SET_SRC (pat);
+  if (GET_CODE (pat) == UNSPEC_VOLATILE)
+    {
+      if (XINT (pat, 1) == UNSPECV_LDGP1
+         || XINT (pat, 1) == UNSPECV_PLDGP2)
+       return true;
+    }
+  else if (GET_CODE (pat) == UNSPEC)
+    {
+      if (XINT (pat, 1) == UNSPEC_LDGP2)
+       return true;
+    }
+
+  return false;
+}
+
+  
 /* Try a machine-dependent way of reloading an illegitimate address
    operand.  If we find one, push the reload and return the new rtx.  */
    
@@ -1790,6 +2409,150 @@ alpha_legitimize_reload_address (x, mode, opnum, type, ind_levels)
   return NULL_RTX;
 }
 \f
+/* Compute a (partial) cost for rtx X.  Return true if the complete
+   cost has been computed, and false if subexpressions should be
+   scanned.  In either case, *TOTAL contains the cost result.  */
+
+static bool
+alpha_rtx_costs (x, code, outer_code, total)
+     rtx x;
+     int code, outer_code;
+     int *total;
+{
+  enum machine_mode mode = GET_MODE (x);
+  bool float_mode_p = FLOAT_MODE_P (mode);
+
+  switch (code)
+    {
+      /* If this is an 8-bit constant, return zero since it can be used
+        nearly anywhere with no cost.  If it is a valid operand for an
+        ADD or AND, likewise return 0 if we know it will be used in that
+        context.  Otherwise, return 2 since it might be used there later.
+        All other constants take at least two insns.  */
+    case CONST_INT:
+      if (INTVAL (x) >= 0 && INTVAL (x) < 256)
+       {
+         *total = 0;
+         return true;
+       }
+      /* FALLTHRU */
+
+    case CONST_DOUBLE:
+      if (x == CONST0_RTX (mode))
+       *total = 0;
+      else if ((outer_code == PLUS && add_operand (x, VOIDmode))
+              || (outer_code == AND && and_operand (x, VOIDmode)))
+       *total = 0;
+      else if (add_operand (x, VOIDmode) || and_operand (x, VOIDmode))
+       *total = 2;
+      else
+       *total = COSTS_N_INSNS (2);
+      return true;
+      
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      if (TARGET_EXPLICIT_RELOCS && small_symbolic_operand (x, VOIDmode))
+       *total = COSTS_N_INSNS (outer_code != MEM);
+      else if (TARGET_EXPLICIT_RELOCS && local_symbolic_operand (x, VOIDmode))
+       *total = COSTS_N_INSNS (1 + (outer_code != MEM));
+      else if (tls_symbolic_operand_type (x))
+       /* Estimate of cost for call_pal rduniq.  */
+       *total = COSTS_N_INSNS (15);
+      else
+       /* Otherwise we do a load from the GOT.  */
+       *total = COSTS_N_INSNS (alpha_memory_latency);
+      return true;
+    
+    case PLUS:
+    case MINUS:
+      if (float_mode_p)
+       *total = alpha_rtx_cost_data[alpha_cpu].fp_add;
+      else if (GET_CODE (XEXP (x, 0)) == MULT
+              && const48_operand (XEXP (XEXP (x, 0), 1), VOIDmode))
+       {
+         *total = (rtx_cost (XEXP (XEXP (x, 0), 0), outer_code)
+                   + rtx_cost (XEXP (x, 1), outer_code) + 2);
+         return true;
+       }
+      return false;
+
+    case MULT:
+      if (float_mode_p)
+       *total = alpha_rtx_cost_data[alpha_cpu].fp_mult;
+      else if (mode == DImode)
+       *total = alpha_rtx_cost_data[alpha_cpu].int_mult_di;
+      else
+       *total = alpha_rtx_cost_data[alpha_cpu].int_mult_si;
+      return false;
+
+    case ASHIFT:
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) <= 3)
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
+
+    case ASHIFTRT:
+    case LSHIFTRT:
+      *total = alpha_rtx_cost_data[alpha_cpu].int_shift;
+      return false;
+
+    case IF_THEN_ELSE:
+      if (float_mode_p)
+        *total = alpha_rtx_cost_data[alpha_cpu].fp_add;
+      else
+        *total = alpha_rtx_cost_data[alpha_cpu].int_cmov;
+      return false;
+
+    case DIV:
+    case UDIV:
+    case MOD:
+    case UMOD:
+      if (!float_mode_p)
+       *total = COSTS_N_INSNS (70);    /* ??? */
+      else if (mode == SFmode)
+        *total = alpha_rtx_cost_data[alpha_cpu].fp_div_sf;
+      else
+        *total = alpha_rtx_cost_data[alpha_cpu].fp_div_df;
+      return false;
+
+    case MEM:
+      *total = COSTS_N_INSNS (alpha_memory_latency);
+      return true;
+
+    case NEG:
+      if (! float_mode_p)
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
+      /* FALLTHRU */
+
+    case ABS:
+      if (! float_mode_p)
+       {
+         *total = COSTS_N_INSNS (1) + alpha_rtx_cost_data[alpha_cpu].int_cmov;
+         return false;
+       }
+      /* FALLTHRU */
+
+    case FLOAT:
+    case UNSIGNED_FLOAT:
+    case FIX:
+    case UNSIGNED_FIX:
+    case FLOAT_EXTEND:
+    case FLOAT_TRUNCATE:
+      *total = alpha_rtx_cost_data[alpha_cpu].fp_add;
+      return false;
+
+    default:
+      return false;
+    }
+}
+\f
 /* REF is an alignable memory location.  Place an aligned SImode
    reference into *PALIGNED_MEM and the number of bits to shift into
    *PBITNUM.  SCRATCH is a free register for use in reloading out
@@ -1822,12 +2585,8 @@ get_aligned_mem (ref, paligned_mem, pbitnum)
   if (GET_CODE (base) == PLUS)
     offset += INTVAL (XEXP (base, 1)), base = XEXP (base, 0);
 
-  *paligned_mem = gen_rtx_MEM (SImode, plus_constant (base, offset & ~3));
-  MEM_COPY_ATTRIBUTES (*paligned_mem, ref);
-
-  /* Sadly, we cannot use alias sets here because we may overlap other
-     data in a different alias set.  */
-  set_mem_alias_set (*paligned_mem, 0);
+  *paligned_mem
+    = widen_memory_access (ref, SImode, (offset & ~3) - offset);
 
   if (WORDS_BIG_ENDIAN)
     *pbitnum = GEN_INT (32 - (GET_MODE_BITSIZE (GET_MODE (ref))
@@ -1869,6 +2628,39 @@ get_unaligned_address (ref, extra_offset)
   return plus_constant (base, offset + extra_offset);
 }
 
+/* On the Alpha, all (non-symbolic) constants except zero go into
+   a floating-point register via memory.  Note that we cannot 
+   return anything that is not a subset of CLASS, and that some
+   symbolic constants cannot be dropped to memory.  */
+
+enum reg_class
+alpha_preferred_reload_class(x, class)
+     rtx x;
+     enum reg_class class;
+{
+  /* Zero is present in any register class.  */
+  if (x == CONST0_RTX (GET_MODE (x)))
+    return class;
+
+  /* These sorts of constants we can easily drop to memory.  */
+  if (GET_CODE (x) == CONST_INT || GET_CODE (x) == CONST_DOUBLE)
+    {
+      if (class == FLOAT_REGS)
+       return NO_REGS;
+      if (class == ALL_REGS)
+       return GENERAL_REGS;
+      return class;
+    }
+
+  /* All other kinds of constants should not (and in the case of HIGH
+     cannot) be dropped to memory -- instead we use a GENERAL_REGS
+     secondary reload.  */
+  if (CONSTANT_P (x))
+    return (class == ALL_REGS ? GENERAL_REGS : class);
+
+  return class;
+}
+
 /* Loading and storing HImode or QImode values to and from memory
    usually requires a scratch register.  The exceptions are loading
    QImode and HImode from an aligned address to a general register
@@ -1932,6 +2724,8 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
   switch (GET_CODE (x))
     {
     case SEQUENCE:
+      abort ();
+
     case PARALLEL:
       for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
        alpha_set_memflags_1 (XVECEXP (x, 0, i), in_struct_p, volatile_p,
@@ -1966,11 +2760,11 @@ alpha_set_memflags_1 (x, in_struct_p, volatile_p, unchanging_p)
     }
 }
 
-/* Given INSN, which is either an INSN or a SEQUENCE generated to
-   perform a memory operation, look for any MEMs in either a SET_DEST or
-   a SET_SRC and copy the in-struct, unchanging, and volatile flags from
-   REF into each of the MEMs found.  If REF is not a MEM, don't do
-   anything.  */
+/* Given INSN, which is an INSN list or the PATTERN of a single insn
+   generated to perform a memory operation, look for any MEMs in either
+   a SET_DEST or a SET_SRC and copy the in-struct, unchanging, and
+   volatile flags from REF into each of the MEMs found.  If REF is not
+   a MEM, don't do anything.  */
 
 void
 alpha_set_memflags (insn, ref)
@@ -2008,15 +2802,39 @@ alpha_emit_set_const (target, mode, c, n)
      HOST_WIDE_INT c;
      int n;
 {
-  rtx pat;
+  rtx result = 0;
+  rtx orig_target = target;
   int i;
 
+  /* If we can't make any pseudos, TARGET is an SImode hard register, we
+     can't load this constant in one insn, do this in DImode.  */
+  if (no_new_pseudos && mode == SImode
+      && GET_CODE (target) == REG && REGNO (target) < FIRST_PSEUDO_REGISTER
+      && (result = alpha_emit_set_const_1 (target, mode, c, 1)) == 0)
+    {
+      target = gen_lowpart (DImode, target);
+      mode = DImode;
+    }
+
   /* Try 1 insn, then 2, then up to N.  */
   for (i = 1; i <= n; i++)
-    if ((pat = alpha_emit_set_const_1 (target, mode, c, i)) != 0)
-      return pat;
+    {
+      result = alpha_emit_set_const_1 (target, mode, c, i);
+      if (result)
+       {
+         rtx insn = get_last_insn ();
+         rtx set = single_set (insn);
+         if (! CONSTANT_P (SET_SRC (set)))
+           set_unique_reg_note (get_last_insn (), REG_EQUAL, GEN_INT (c));
+         break;
+       }
+    }
 
-  return 0;
+  /* Allow for the case where we changed the mode of TARGET.  */
+  if (result == target)
+    result = orig_target;
+
+  return result;
 }
 
 /* Internal routine for the above to check for N or below insns.  */
@@ -2032,18 +2850,8 @@ alpha_emit_set_const_1 (target, mode, c, n)
   int i, bits;
   /* Use a pseudo if highly optimizing and still generating RTL.  */
   rtx subtarget
-    = (flag_expensive_optimizations && rtx_equal_function_value_matters
-       ? 0 : target);
-  rtx temp;
-
-#if HOST_BITS_PER_WIDE_INT == 64
-  /* We are only called for SImode and DImode.  If this is SImode, ensure that
-     we are sign extended to a full word.  This does not make any sense when
-     cross-compiling on a narrow machine.  */
-
-  if (mode == SImode)
-    c = ((c & 0xffffffff) ^ 0x80000000) - 0x80000000;
-#endif
+    = (flag_expensive_optimizations && !no_new_pseudos ? 0 : target);
+  rtx temp, insn;
 
   /* If this is a sign-extended 32-bit constant, we can do this in at most
      three insns, so do it if we have enough insns left.  We always have
@@ -2084,12 +2892,28 @@ alpha_emit_set_const_1 (target, mode, c, n)
        {
          temp = copy_to_suggested_reg (GEN_INT (high << 16), subtarget, mode);
 
+         /* As of 2002-02-23, addsi3 is only available when not optimizing.
+            This means that if we go through expand_binop, we'll try to
+            generate extensions, etc, which will require new pseudos, which
+            will fail during some split phases.  The SImode add patterns
+            still exist, but are not named.  So build the insns by hand.  */
+
          if (extra != 0)
-           temp = expand_binop (mode, add_optab, temp, GEN_INT (extra << 16),
-                                subtarget, 0, OPTAB_WIDEN);
+           {
+             if (! subtarget)
+               subtarget = gen_reg_rtx (mode);
+             insn = gen_rtx_PLUS (mode, temp, GEN_INT (extra << 16));
+             insn = gen_rtx_SET (VOIDmode, subtarget, insn);
+             emit_insn (insn);
+             temp = subtarget;
+           }
 
-         return expand_binop (mode, add_optab, temp, GEN_INT (low),
-                              target, 0, OPTAB_WIDEN);
+         if (target == NULL)
+           target = gen_reg_rtx (mode);
+         insn = gen_rtx_PLUS (mode, temp, GEN_INT (low));
+         insn = gen_rtx_SET (VOIDmode, target, insn);
+         emit_insn (insn);
+         return target;
        }
     }
 
@@ -2098,8 +2922,7 @@ alpha_emit_set_const_1 (target, mode, c, n)
      we can't make pseudos, we can't do anything since the expand_binop
      and expand_unop calls will widen and try to make pseudos.  */
 
-  if (n == 1
-      || (mode == SImode && ! rtx_equal_function_value_matters))
+  if (n == 1 || (mode == SImode && no_new_pseudos))
     return 0;
 
   /* Next, see if we can load a related constant and then shift and possibly
@@ -2277,36 +3100,36 @@ alpha_expand_mov (mode, operands)
       && ! reg_or_0_operand (operands[1], mode))
     operands[1] = force_reg (mode, operands[1]);
 
-  if (TARGET_EXPLICIT_RELOCS && symbolic_operand (operands[1], mode))
+  /* Allow legitimize_address to perform some simplifications.  */
+  if (mode == Pmode && symbolic_operand (operands[1], mode))
     {
-      if (local_symbolic_operand (operands[1], mode))
-       {
-         rtx scratch;
-
-         if (small_symbolic_operand (operands[1], Pmode))
-           scratch = pic_offset_table_rtx;
-         else
-           {
-             rtx insn, tmp;
+      rtx tmp;
 
-             scratch = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
-
-             tmp = gen_rtx_HIGH (Pmode, operands[1]);
-             tmp = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, tmp);
-              insn = emit_insn (gen_rtx_SET (VOIDmode, scratch, tmp));
-             REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, tmp,
-                                                   REG_NOTES (insn));
-           }
+      /* With RTL inlining, at -O3, rtl is generated, stored, then actually
+        compiled at the end of compilation.  In the meantime, someone can
+        re-encode-section-info on some symbol changing it e.g. from global
+        to local-not-small.  If this happens, we'd have emitted a plain
+        load rather than a high+losum load and not recognize the insn.
 
-          operands[1] = gen_rtx_LO_SUM (Pmode, scratch, operands[1]);
-         return false;
-       }
-      else
+        So if rtl inlining is in effect, we delay the global/not-global
+        decision until rest_of_compilation by wrapping it in an
+        UNSPEC_SYMBOL.  */
+      if (TARGET_EXPLICIT_RELOCS && flag_inline_functions
+         && rtx_equal_function_value_matters
+         && global_symbolic_operand (operands[1], mode))
        {
-         emit_insn (gen_movdi_er_high_g (operands[0], pic_offset_table_rtx,
-                                         operands[1], const0_rtx));
+         emit_insn (gen_movdi_er_maybe_g (operands[0], operands[1]));
          return true;
        }
+
+      tmp = alpha_legitimize_address (operands[1], operands[0], mode);
+      if (tmp)
+       {
+         if (tmp == operands[0])
+           return true;
+         operands[1] = tmp;
+         return false;
+       }
     }
 
   /* Early out for non-constants and valid constants.  */
@@ -2352,7 +3175,7 @@ alpha_expand_mov (mode, operands)
     }
 
   /* Otherwise we've nothing left but to drop the thing to memory.  */
-  operands[1] = force_const_mem (DImode, operands[1]);
+  operands[1] = force_const_mem (mode, operands[1]);
   if (reload_in_progress)
     {
       emit_move_insn (operands[0], XEXP (operands[1], 0));
@@ -2577,21 +3400,29 @@ alpha_emit_conditional_branch (code)
            1  true
         Convert the compare against the raw return value.  */
 
-      if (code == UNORDERED || code == ORDERED)
-       cmp_code = EQ;
-      else
-       cmp_code = code;
+      switch (code)
+       {
+       case UNORDERED:
+         cmp_code = EQ;
+         code = LT;
+         break;
+       case ORDERED:
+         cmp_code = EQ;
+         code = GE;
+         break;
+       case NE:
+         cmp_code = NE;
+         code = NE;
+         break;
+       default:
+         cmp_code = code;
+         code = GT;
+         break;
+       }
 
       op0 = alpha_emit_xfloating_compare (cmp_code, op0, op1);
       op1 = const0_rtx;
       alpha_compare.fp_p = 0;
-
-      if (code == UNORDERED)
-       code = LT;
-      else if (code == ORDERED)
-       code = GE;
-      else
-        code = GT;
     }
 
   /* The general case: fold the comparison code to the types of compares
@@ -2648,7 +3479,7 @@ alpha_emit_conditional_branch (code)
        }
       else
        {
-         /* ??? We mark the the branch mode to be CCmode to prevent the
+         /* ??? We mark the branch mode to be CCmode to prevent the
             compare and branch from being combined, since the compare 
             insn follows IEEE rules that the branch does not.  */
          branch_mode = CCmode;
@@ -2816,7 +3647,7 @@ alpha_emit_setcc (code)
 /* Rewrite a comparison against zero CMP of the form
    (CODE (cc0) (const_int 0)) so it can be written validly in
    a conditional move (if_then_else CMP ...).
-   If both of the operands that set cc0 are non-zero we must emit
+   If both of the operands that set cc0 are nonzero we must emit
    an insn to perform the compare (it can't be done within
    the conditional move).  */
 rtx
@@ -2848,7 +3679,7 @@ alpha_emit_conditional_move (cmp, mode)
 
       /* If we have fp<->int register move instructions, do a cmov by
         performing the comparison in fp registers, and move the
-        zero/non-zero value to integer registers, where we can then
+        zero/nonzero value to integer registers, where we can then
         use a normal cmov, or vice-versa.  */
 
       switch (code)
@@ -2987,6 +3818,9 @@ alpha_split_conditional_move (code, dest, cond, t_rtx, f_rtx)
       else
        subtarget = target;
     }
+  /* Below, we must be careful to use copy_rtx on target and subtarget
+     in intermediate insns, as they may be a subreg rtx, which may not
+     be shared.  */
 
   if (f == 0 && exact_log2 (diff) > 0
       /* On EV6, we've got enough shifters to make non-arithmatic shifts
@@ -2995,33 +3829,35 @@ alpha_split_conditional_move (code, dest, cond, t_rtx, f_rtx)
       && (diff <= 8 || alpha_cpu == PROCESSOR_EV6))
     {
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-      tmp = gen_rtx_ASHIFT (DImode, subtarget, GEN_INT (exact_log2 (t)));
+      tmp = gen_rtx_ASHIFT (DImode, copy_rtx (subtarget),
+                           GEN_INT (exact_log2 (t)));
       emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
     }
   else if (f == 0 && t == -1)
     {
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
-      emit_insn (gen_negdi2 (target, subtarget));
+      emit_insn (gen_negdi2 (target, copy_rtx (subtarget)));
     }
   else if (diff == 1 || diff == 4 || diff == 8)
     {
       rtx add_op;
 
       tmp = gen_rtx_fmt_ee (code, DImode, cond, const0_rtx);
-      emit_insn (gen_rtx_SET (VOIDmode, subtarget, tmp));
+      emit_insn (gen_rtx_SET (VOIDmode, copy_rtx (subtarget), tmp));
 
       if (diff == 1)
-       emit_insn (gen_adddi3 (target, subtarget, GEN_INT (f)));
+       emit_insn (gen_adddi3 (target, copy_rtx (subtarget), GEN_INT (f)));
       else
        {
          add_op = GEN_INT (f);
          if (sext_add_operand (add_op, mode))
            {
-             tmp = gen_rtx_MULT (DImode, subtarget, GEN_INT (diff));
+             tmp = gen_rtx_MULT (DImode, copy_rtx (subtarget),
+                                 GEN_INT (diff));
              tmp = gen_rtx_PLUS (DImode, tmp, add_op);
              emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
            }
@@ -3230,7 +4066,7 @@ alpha_emit_xfloating_libcall (func, target, operands, noperands, equiv)
       abort ();
     }
 
-  tmp = gen_rtx_MEM (QImode, gen_rtx_SYMBOL_REF (Pmode, (char *) func));
+  tmp = gen_rtx_MEM (QImode, init_one_libfunc (func));
   tmp = emit_call_insn (GEN_CALL_VALUE (reg, tmp, const0_rtx,
                                        const0_rtx, const0_rtx));
   CALL_INSN_FUNCTION_USAGE (tmp) = usage;
@@ -3375,7 +4211,7 @@ alpha_split_tfmode_frobsign (operands, operation)
 
   alpha_split_tfmode_pair (operands);
 
-  /* Detect three flavours of operand overlap.  */
+  /* Detect three flavors of operand overlap.  */
   move = 1;
   if (rtx_equal_p (operands[0], operands[2]))
     move = 0;
@@ -3621,17 +4457,13 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
          emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffff), addr));
          break;
        case 4:
-         emit_insn (gen_mskxl_be (dsth, dsth, GEN_INT (0xffffffff), addr));
-         break;
-       case 8:
          {
-#if HOST_BITS_PER_WIDE_INT == 32
-           rtx msk = immed_double_const (0xffffffff, 0xffffffff, DImode);
-#else
-           rtx msk = constm1_rtx;
-#endif
+           rtx msk = immed_double_const (0xffffffff, 0, DImode);
            emit_insn (gen_mskxl_be (dsth, dsth, msk, addr));
+           break;
          }
+       case 8:
+         emit_insn (gen_mskxl_be (dsth, dsth, constm1_rtx, addr));
          break;
        }
 
@@ -3668,17 +4500,13 @@ alpha_expand_unaligned_store (dst, src, size, ofs)
          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);
-#else
-           rtx msk = constm1_rtx;
-#endif
+           rtx msk = immed_double_const (0xffffffff, 0, DImode);
            emit_insn (gen_mskxl_le (dstl, dstl, msk, addr));
+           break;
          }
+       case 8:
+         emit_insn (gen_mskxl_le (dstl, dstl, constm1_rtx, addr));
          break;
        }
     }
@@ -3804,11 +4632,6 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
 {
   rtx const im8 = GEN_INT (-8);
   rtx const i64 = GEN_INT (64);
-#if HOST_BITS_PER_WIDE_INT == 32
-  rtx const im1 = immed_double_const (0xffffffff, 0xffffffff, DImode);
-#else
-  rtx const im1 = constm1_rtx;
-#endif
   rtx ins_tmps[MAX_MOVE_WORDS];
   rtx st_tmp_1, st_tmp_2, dreg;
   rtx st_addr_1, st_addr_2, dmema;
@@ -3872,13 +4695,13 @@ alpha_expand_unaligned_store_words (data_regs, dmem, words, ofs)
   /* Split and merge the ends with the destination data.  */
   if (WORDS_BIG_ENDIAN)
     {
-      emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, im1, dreg));
+      emit_insn (gen_mskxl_be (st_tmp_2, st_tmp_2, constm1_rtx, 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));
+      emit_insn (gen_mskxl_le (st_tmp_1, st_tmp_1, constm1_rtx, dreg));
     }
 
   if (data_regs != NULL)
@@ -4543,6 +5366,75 @@ alpha_expand_block_clear (operands)
 
   return 1;
 }
+
+/* Returns a mask so that zap(x, value) == x & mask.  */
+
+rtx
+alpha_expand_zap_mask (value)
+     HOST_WIDE_INT value;
+{
+  rtx result;
+  int i;
+
+  if (HOST_BITS_PER_WIDE_INT >= 64)
+    {
+      HOST_WIDE_INT mask = 0;
+
+      for (i = 7; i >= 0; --i)
+       {
+         mask <<= 8;
+         if (!((value >> i) & 1))
+           mask |= 0xff;
+       }
+
+      result = gen_int_mode (mask, DImode);
+    }
+  else if (HOST_BITS_PER_WIDE_INT == 32)
+    {
+      HOST_WIDE_INT mask_lo = 0, mask_hi = 0;
+
+      for (i = 7; i >= 4; --i)
+       {
+         mask_hi <<= 8;
+         if (!((value >> i) & 1))
+           mask_hi |= 0xff;
+       }
+
+      for (i = 3; i >= 0; --i)
+       {
+         mask_lo <<= 8;
+         if (!((value >> i) & 1))
+           mask_lo |= 0xff;
+       }
+
+      result = immed_double_const (mask_lo, mask_hi, DImode);
+    }
+  else
+    abort ();
+
+  return result;
+}
+
+void
+alpha_expand_builtin_vector_binop (gen, mode, op0, op1, op2)
+     rtx (*gen) PARAMS ((rtx, rtx, rtx));
+     enum machine_mode mode;
+     rtx op0, op1, op2;
+{
+  op0 = gen_lowpart (mode, op0);
+
+  if (op1 == const0_rtx)
+    op1 = CONST0_RTX (mode);
+  else
+    op1 = gen_lowpart (mode, op1);
+
+  if (op2 == const0_rtx)
+    op2 = CONST0_RTX (mode);
+  else
+    op2 = gen_lowpart (mode, op2);
+
+  emit_insn ((*gen) (op0, op1, op2));
+}
 \f
 /* Adjust the cost of a scheduling dependency.  Return the new cost of
    a dependency LINK or INSN on DEP_INSN.  COST is the current cost.  */
@@ -4554,15 +5446,13 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
      rtx dep_insn;
      int cost;
 {
-  rtx set, set_src;
   enum attr_type insn_type, dep_insn_type;
 
   /* If the dependence is an anti-dependence, there is no cost.  For an
      output dependence, there is sometimes a cost, but it doesn't seem
      worth handling those few cases.  */
-
   if (REG_NOTE_KIND (link) != 0)
-    return 0;
+    return cost;
 
   /* If we can't recognize the insns, we can't really do anything.  */
   if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
@@ -4577,122 +5467,13 @@ alpha_adjust_cost (insn, link, dep_insn, cost)
       || dep_insn_type == TYPE_LDSYM)
     cost += alpha_memory_latency-1;
 
-  switch (alpha_cpu)
-    {
-    case PROCESSOR_EV4:
-      /* On EV4, if INSN is a store insn and DEP_INSN is setting the data
-        being stored, we can sometimes lower the cost.  */
-
-      if ((insn_type == TYPE_IST || insn_type == TYPE_FST)
-         && (set = single_set (dep_insn)) != 0
-         && GET_CODE (PATTERN (insn)) == SET
-         && rtx_equal_p (SET_DEST (set), SET_SRC (PATTERN (insn))))
-       {
-         switch (dep_insn_type)
-           {
-           case TYPE_ILD:
-           case TYPE_FLD:
-             /* No savings here.  */
-             return cost;
-
-           case TYPE_IMUL:
-             /* In these cases, we save one cycle.  */
-             return cost - 1;
-
-           default:
-             /* In all other cases, we save two cycles.  */
-             return MAX (0, cost - 2);
-           }
-       }
-
-      /* Another case that needs adjustment is an arithmetic or logical
-        operation.  It's cost is usually one cycle, but we default it to
-        two in the MD file.  The only case that it is actually two is
-        for the address in loads, stores, and jumps.  */
-
-      if (dep_insn_type == TYPE_IADD || dep_insn_type == TYPE_ILOG)
-       {
-         switch (insn_type)
-           {
-           case TYPE_ILD:
-           case TYPE_IST:
-           case TYPE_FLD:
-           case TYPE_FST:
-           case TYPE_JSR:
-             return cost;
-           default:
-             return 1;
-           }
-       }
-
-      /* The final case is when a compare feeds into an integer branch;
-        the cost is only one cycle in that case.  */
-
-      if (dep_insn_type == TYPE_ICMP && insn_type == TYPE_IBR)
-       return 1;
-      break;
-
-    case PROCESSOR_EV5:
-      /* And the lord DEC saith:  "A special bypass provides an effective
-        latency of 0 cycles for an ICMP or ILOG insn producing the test
-        operand of an IBR or ICMOV insn." */
-
-      if ((dep_insn_type == TYPE_ICMP || dep_insn_type == TYPE_ILOG)
-         && (set = single_set (dep_insn)) != 0)
-       {
-         /* A branch only has one input.  This must be it.  */
-         if (insn_type == TYPE_IBR)
-           return 0;
-         /* A conditional move has three, make sure it is the test.  */
-         if (insn_type == TYPE_ICMOV
-             && GET_CODE (set_src = PATTERN (insn)) == SET
-             && GET_CODE (set_src = SET_SRC (set_src)) == IF_THEN_ELSE
-             && rtx_equal_p (SET_DEST (set), XEXP (set_src, 0)))
-           return 0;
-       }
-
-      /* "The multiplier is unable to receive data from IEU bypass paths.
-        The instruction issues at the expected time, but its latency is
-        increased by the time it takes for the input data to become
-        available to the multiplier" -- which happens in pipeline stage
-        six, when results are comitted to the register file.  */
-
-      if (insn_type == TYPE_IMUL)
-       {
-         switch (dep_insn_type)
-           {
-           /* These insns produce their results in pipeline stage five.  */
-           case TYPE_ILD:
-           case TYPE_ICMOV:
-           case TYPE_IMUL:
-           case TYPE_MVI:
-             return cost + 1;
-
-           /* Other integer insns produce results in pipeline stage four.  */
-           default:
-             return cost + 2;
-           }
-       }
-      break;
-
-    case PROCESSOR_EV6:
-      /* There is additional latency to move the result of (most) FP 
-         operations anywhere but the FP register file.  */
-
-      if ((insn_type == TYPE_FST || insn_type == TYPE_FTOI)
-         && (dep_insn_type == TYPE_FADD ||
-             dep_insn_type == TYPE_FMUL ||
-             dep_insn_type == TYPE_FCMOV))
-        return cost + 2;
-
-      break;
-    }
+  /* Everything else handled in DFA bypasses now.  */
 
-  /* Otherwise, return the default cost.  */
   return cost;
 }
 
-/* Function to initialize the issue rate used by the scheduler.  */
+/* The number of instructions that can be issued per cycle.  */
+
 static int
 alpha_issue_rate ()
 {
@@ -4700,57 +5481,50 @@ alpha_issue_rate ()
 }
 
 static int
-alpha_variable_issue (dump, verbose, insn, cim)
-     FILE *dump ATTRIBUTE_UNUSED;
-     int verbose ATTRIBUTE_UNUSED;
-     rtx insn;
-     int cim;
+alpha_use_dfa_pipeline_interface ()
 {
-    if (recog_memoized (insn) < 0 || get_attr_type (insn) == TYPE_MULTI)
-      return 0;
-
-    return cim - 1;
+  return true;
 }
 
-\f
-/* Register global variables and machine-specific functions with the
-   garbage collector.  */
+/* How many alternative schedules to try.  This should be as wide as the
+   scheduling freedom in the DFA, but no wider.  Making this value too
+   large results extra work for the scheduler.
 
-#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));
+   For EV4, loads can be issued to either IB0 or IB1, thus we have 2
+   alternative schedules.  For EV5, we can choose between E0/E1 and
+   FA/FM.  For EV6, an arithmatic insn can be issued to U0/U1/L0/L1.  */
 
-  p->machine->first_ciw = NULL_RTX;
-  p->machine->last_ciw = NULL_RTX;
-  p->machine->ciw_count = 0;
-  p->machine->addr_list = NULL_RTX;
+static int
+alpha_multipass_dfa_lookahead ()
+{
+  return (alpha_cpu == PROCESSOR_EV6 ? 4 : 2);
 }
+\f
+/* Machine-specific function data.  */
 
-static void
-alpha_mark_machine_status (p)
-     struct function *p;
+struct machine_function GTY(())
 {
-  struct machine_function *machine = p->machine;
+  /* For unicosmk. */
+  /* List of call information words for calls from this function.  */
+  struct rtx_def *first_ciw;
+  struct rtx_def *last_ciw;
+  int ciw_count;
 
-  if (machine)
-    {
-      ggc_mark_rtx (machine->first_ciw);
-      ggc_mark_rtx (machine->addr_list);
-    }
-}
+  /* List of deferred case vectors.  */
+  struct rtx_def *addr_list;
 
-static void
-alpha_free_machine_status (p)
-     struct function *p;
+  /* For OSF. */
+  const char *some_ld_name;
+};
+
+/* How to allocate a 'struct machine_function'.  */
+
+static struct machine_function *
+alpha_init_machine_status ()
 {
-  free (p->machine);
-  p->machine = NULL;
+  return ((struct machine_function *) 
+               ggc_alloc_cleared (sizeof (struct machine_function)));
 }
-#endif /* TARGET_ABI_UNICOSMK */
 
 /* Functions to save and restore alpha_return_addr_rtx.  */
 
@@ -4773,7 +5547,10 @@ alpha_return_addr (count, frame)
 rtx
 alpha_gp_save_rtx ()
 {
-  return get_hard_reg_initial_val (DImode, 29);
+  rtx r = get_hard_reg_initial_val (DImode, 29);
+  if (GET_CODE (r) != MEM)
+    r = gen_mem_addressof (r, NULL_TREE, /*rescan=*/true);
+  return r;
 }
 
 static int
@@ -4781,10 +5558,6 @@ alpha_ra_ever_killed ()
 {
   rtx top;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
-    return 0;
-#endif
   if (!has_hard_reg_initial_val (Pmode, REG_RA))
     return regs_ever_live[REG_RA];
 
@@ -4895,6 +5668,42 @@ get_round_mode_suffix ()
   abort ();
 }
 
+/* Locate some local-dynamic symbol still in use by this function
+   so that we can print its name in some movdi_er_tlsldm pattern.  */
+
+static const char *
+get_some_local_dynamic_name ()
+{
+  rtx insn;
+
+  if (cfun->machine->some_ld_name)
+    return cfun->machine->some_ld_name;
+
+  for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
+    if (INSN_P (insn)
+       && for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
+      return cfun->machine->some_ld_name;
+
+  abort ();
+}
+
+static int
+get_some_local_dynamic_name_1 (px, data)
+     rtx *px;
+     void *data ATTRIBUTE_UNUSED;
+{
+  rtx x = *px;
+
+  if (GET_CODE (x) == SYMBOL_REF
+      && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
+    {
+      cfun->machine->some_ld_name = XSTR (x, 0);
+      return 1;
+    }
+
+  return 0;
+}
+
 /* Print an operand.  Recognize special options, documented below.  */
 
 void
@@ -4912,6 +5721,10 @@ print_operand (file, x, code)
       assemble_name (file, alpha_fnname);
       break;
 
+    case '&':
+      assemble_name (file, get_some_local_dynamic_name ());
+      break;
+
     case '/':
       {
        const char *trap = get_trap_mode_suffix ();
@@ -4933,6 +5746,13 @@ print_operand (file, x, code)
       fputc ((TARGET_FLOAT_VAX ? 'g' : 't'), file);
       break;
 
+    case '+':
+      /* Generates a nop after a noreturn call at the very end of the
+        function.  */
+      if (next_real_insn (current_output_insn) == 0)
+       fprintf (file, "\n\tnop");
+      break;
+
     case '#':
       if (alpha_this_literal_sequence_number == 0)
        alpha_this_literal_sequence_number = alpha_next_sequence_number++;
@@ -4952,6 +5772,33 @@ print_operand (file, x, code)
        output_operand_lossage ("invalid %%H value");
       break;
 
+    case 'J':
+      {
+       const char *lituse;
+
+        if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSGD_CALL)
+         {
+           x = XVECEXP (x, 0, 0);
+           lituse = "lituse_tlsgd";
+         }
+       else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLSLDM_CALL)
+         {
+           x = XVECEXP (x, 0, 0);
+           lituse = "lituse_tlsldm";
+         }
+       else if (GET_CODE (x) == CONST_INT)
+         lituse = "lituse_jsr";
+       else
+         {
+           output_operand_lossage ("invalid %%J value");
+           break;
+         }
+
+       if (x != const0_rtx)
+         fprintf (file, "\t\t!%s!%d", lituse, (int) INTVAL (x));
+      }
+      break;
+
     case 'r':
       /* If this operand is the constant zero, write it as "$31".  */
       if (GET_CODE (x) == REG)
@@ -5057,31 +5904,40 @@ print_operand (file, x, code)
 
     case 'U':
       /* Similar, except do it from the mask.  */
-      if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xff)
-       fprintf (file, "b");
-      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffff)
-       fprintf (file, "w");
-      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == 0xffffffff)
-       fprintf (file, "l");
-#if HOST_BITS_PER_WIDE_INT == 32
-      else if (GET_CODE (x) == CONST_DOUBLE
-              && CONST_DOUBLE_HIGH (x) == 0
-              && CONST_DOUBLE_LOW (x) == -1)
-       fprintf (file, "l");
-      else if (GET_CODE (x) == CONST_DOUBLE
-              && CONST_DOUBLE_HIGH (x) == -1
-              && CONST_DOUBLE_LOW (x) == -1)
-       fprintf (file, "q");
-#else
-      else if (GET_CODE (x) == CONST_INT && INTVAL (x) == -1)
-       fprintf (file, "q");
-      else if (GET_CODE (x) == CONST_DOUBLE
-              && CONST_DOUBLE_HIGH (x) == 0
-              && CONST_DOUBLE_LOW (x) == -1)
-       fprintf (file, "q");
-#endif
-      else
-       output_operand_lossage ("invalid %%U value");
+      if (GET_CODE (x) == CONST_INT)
+       {
+         HOST_WIDE_INT value = INTVAL (x);
+
+         if (value == 0xff)
+           {
+             fputc ('b', file);
+             break;
+           }
+         if (value == 0xffff)
+           {
+             fputc ('w', file);
+             break;
+           }
+         if (value == 0xffffffff)
+           {
+             fputc ('l', file);
+             break;
+           }
+         if (value == -1)
+           {
+             fputc ('q', file);
+             break;
+           }
+       }
+      else if (HOST_BITS_PER_WIDE_INT == 32
+              && GET_CODE (x) == CONST_DOUBLE
+              && CONST_DOUBLE_LOW (x) == 0xffffffff
+              && CONST_DOUBLE_HIGH (x) == 0)
+       {
+         fputc ('l', file);
+         break;
+       }
+      output_operand_lossage ("invalid %%U value");
       break;
 
     case 's':
@@ -5183,6 +6039,19 @@ print_operand (file, x, code)
        fprintf (file, "%s", reg_names[REGNO (x)]);
       else if (GET_CODE (x) == MEM)
        output_address (XEXP (x, 0));
+      else if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == UNSPEC)
+       {
+         switch (XINT (XEXP (x, 0), 1))
+           {
+           case UNSPEC_DTPREL:
+           case UNSPEC_TPREL:
+             output_addr_const (file, XVECEXP (XEXP (x, 0), 0, 0));
+             break;
+           default:
+             output_operand_lossage ("unknown relocation unspec");
+             break;
+           }
+       }
       else
        output_addr_const (file, x);
       break;
@@ -5212,12 +6081,38 @@ print_operand_address (file, addr)
 
   if (GET_CODE (addr) == LO_SUM)
     {
-      output_addr_const (file, XEXP (addr, 1));
-      if (offset)
+      const char *reloc16, *reloclo;
+      rtx op1 = XEXP (addr, 1);
+
+      if (GET_CODE (op1) == CONST && GET_CODE (XEXP (op1, 0)) == UNSPEC)
+       {
+         op1 = XEXP (op1, 0);
+         switch (XINT (op1, 1))
+           {
+           case UNSPEC_DTPREL:
+             reloc16 = NULL;
+             reloclo = (alpha_tls_size == 16 ? "dtprel" : "dtprello");
+             break;
+           case UNSPEC_TPREL:
+             reloc16 = NULL;
+             reloclo = (alpha_tls_size == 16 ? "tprel" : "tprello");
+             break;
+           default:
+             output_operand_lossage ("unknown relocation unspec");
+             return;
+           }
+
+         output_addr_const (file, XVECEXP (op1, 0, 0));
+       }
+      else
        {
-         fputc ('+', file);
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
+         reloc16 = "gprel";
+         reloclo = "gprellow";
+         output_addr_const (file, op1);
        }
+
+      if (offset)
+       fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
       
       addr = XEXP (addr, 0);
       if (GET_CODE (addr) == REG)
@@ -5229,7 +6124,7 @@ print_operand_address (file, addr)
        abort ();
 
       fprintf (file, "($%d)\t\t!%s", basereg,
-              (basereg == 29 ? "gprel" : "gprellow"));
+              (basereg == 29 ? reloc16 : reloclo));
       return;
     }
 
@@ -5240,11 +6135,28 @@ print_operand_address (file, addr)
     basereg = subreg_regno (addr);
   else if (GET_CODE (addr) == CONST_INT)
     offset = INTVAL (addr);
+
+#if TARGET_ABI_OPEN_VMS
+  else if (GET_CODE (addr) == SYMBOL_REF)
+    {
+      fprintf (file, "%s", XSTR (addr, 0));
+      return;
+    }
+  else if (GET_CODE (addr) == CONST
+          && GET_CODE (XEXP (addr, 0)) == PLUS
+          && GET_CODE (XEXP (XEXP (addr, 0), 0)) == SYMBOL_REF)
+    {
+      fprintf (file, "%s+%d",
+              XSTR (XEXP (XEXP (addr, 0), 0), 0),
+              INTVAL (XEXP (XEXP (addr, 0), 1)));
+      return;
+    }
+#endif
+
   else
     abort ();
 
-  fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
-  fprintf (file, "($%d)", basereg);
+  fprintf (file, HOST_WIDE_INT_PRINT_DEC "($%d)", offset, basereg);
 }
 \f
 /* Emit RTL insns to initialize the variable parts of a trampoline at
@@ -5290,20 +6202,21 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
                           OPTAB_WIDEN);
       temp = expand_shift (RSHIFT_EXPR, Pmode, temp,
                           build_int_2 (2, 0), NULL_RTX, 1);
-      temp = expand_and (gen_lowpart (SImode, temp), GEN_INT (0x3fff), 0);
+      temp = expand_and (SImode, gen_lowpart (SImode, temp),
+                        GEN_INT (0x3fff), 0);
 
       /* Merge in the hint.  */
       addr = memory_address (SImode, plus_constant (tramp, jmpofs));
       temp1 = force_reg (SImode, gen_rtx_MEM (SImode, addr));
-      temp1 = expand_and (temp1, GEN_INT (0xffffc000), NULL_RTX);
+      temp1 = expand_and (SImode, temp1, GEN_INT (0xffffc000), NULL_RTX);
       temp1 = expand_binop (SImode, ior_optab, temp1, temp, temp1, 1,
                            OPTAB_WIDEN);
       emit_move_insn (gen_rtx_MEM (SImode, addr), temp1);
     }
 
 #ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
-                    0, VOIDmode, 1, addr, Pmode);
+  emit_library_call (init_one_libfunc ("__enable_execute_stack"),
+                    0, VOIDmode, 1, tramp, Pmode);
 #endif
 
   if (jmpofs >= 0)
@@ -5449,7 +6362,7 @@ alpha_build_va_list ()
   if (TARGET_ABI_OPEN_VMS || TARGET_ABI_UNICOSMK)
     return ptr_type_node;
 
-  record = make_lang_type (RECORD_TYPE);
+  record = (*lang_hooks.types.make_type) (RECORD_TYPE);
   type_decl = build_decl (TYPE_DECL, get_identifier ("__va_list_tag"), record);
   TREE_CHAIN (record) = type_decl;
   TYPE_NAME (record) = type_decl;
@@ -5471,9 +6384,55 @@ alpha_build_va_list ()
   return record;
 }
 
+/* Perform any needed actions needed for a function that is receiving a
+   variable number of arguments. 
+
+   On the Alpha, we allocate space for all 12 arg registers, but only
+   push those that are remaining.  However, if NO registers need to be
+   saved, don't allocate any space.  This is not only because we won't
+   need the space, but because AP includes the current_pretend_args_size
+   and we don't want to mess up any ap-relative addresses already made.
+
+   If we are not to use the floating-point registers, save the integer
+   registers where we would put the floating-point registers.  This is
+   not the most efficient way to implement varargs with just one register
+   class, but it isn't worth doing anything more efficient in this rare
+   case.  */
+
+void   
+alpha_setup_incoming_varargs(cum, mode, type, pretend_size, no_rtl)
+     CUMULATIVE_ARGS cum;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     tree type ATTRIBUTE_UNUSED;
+     int *pretend_size;
+     int no_rtl;
+{
+  if (cum >= 6)
+    return;
+
+  if (!no_rtl)
+    {
+      int set = get_varargs_alias_set ();
+      rtx tmp;
+
+      tmp = gen_rtx_MEM (BLKmode,
+                        plus_constant (virtual_incoming_args_rtx,
+                                       (cum + 6) * UNITS_PER_WORD));
+      set_mem_alias_set (tmp, set);
+      move_block_from_reg (16 + cum, tmp, 6 - cum);
+
+      tmp = gen_rtx_MEM (BLKmode,
+                        plus_constant (virtual_incoming_args_rtx,
+                                       cum * UNITS_PER_WORD));
+      set_mem_alias_set (tmp, set);
+      move_block_from_reg (16 + (TARGET_FPREGS ? 32 : 0) + cum, tmp,
+                          6 - cum);
+     }
+  *pretend_size = 12 * UNITS_PER_WORD;
+}
+
 void
-alpha_va_start (stdarg_p, valist, nextarg)
-     int stdarg_p;
+alpha_va_start (valist, nextarg)
      tree valist;
      rtx nextarg ATTRIBUTE_UNUSED;
 {
@@ -5484,7 +6443,7 @@ alpha_va_start (stdarg_p, valist, nextarg)
     return;
 
   if (TARGET_ABI_UNICOSMK)
-    std_expand_builtin_va_start (stdarg_p, valist, nextarg);
+    std_expand_builtin_va_start (valist, nextarg);
 
   /* For Unix, SETUP_INCOMING_VARARGS moves the starting address base
      up by 48, storing fp arg registers in the first 48 bytes, and the
@@ -5493,12 +6452,15 @@ alpha_va_start (stdarg_p, valist, nextarg)
 
      If no integer registers need be stored, then we must subtract 48
      in order to account for the integer arg registers which are counted
-     in argsize above, but which are not actually stored on the stack.  */
+     in argsize above, but which are not actually stored on the stack.
+     Must further be careful here about structures straddling the last
+     integer argument register; that futzes with pretend_args_size, 
+     which changes the meaning of AP.  */
 
-  if (NUM_ARGS <= 5 + stdarg_p)
+  if (NUM_ARGS <= 6)
     offset = TARGET_ABI_OPEN_VMS ? UNITS_PER_WORD : 6 * UNITS_PER_WORD;
   else
-    offset = -6 * UNITS_PER_WORD;
+    offset = -6 * UNITS_PER_WORD + current_function_pretend_args_size;
 
   if (TARGET_ABI_OPEN_VMS)
     {
@@ -5537,9 +6499,8 @@ rtx
 alpha_va_arg (valist, type)
      tree valist, type;
 {
-  HOST_WIDE_INT tsize;
   rtx addr;
-  tree t;
+  tree t, type_size, rounded_size;
   tree offset_field, base_field, addr_tree, addend;
   tree wide_type, wide_ofs;
   int indirect = 0;
@@ -5547,7 +6508,18 @@ alpha_va_arg (valist, type)
   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;
+  if (type == error_mark_node
+      || (type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type))) == NULL
+      || TREE_OVERFLOW (type_size))
+    rounded_size = size_zero_node;
+  else
+    rounded_size = fold (build (MULT_EXPR, sizetype,
+                               fold (build (TRUNC_DIV_EXPR, sizetype,
+                                            fold (build (PLUS_EXPR, sizetype,
+                                                         type_size,
+                                                         size_int (7))),
+                                            size_int (8))),
+                               size_int (8)));
 
   base_field = TYPE_FIELDS (TREE_TYPE (valist));
   offset_field = TREE_CHAIN (base_field);
@@ -5557,6 +6529,17 @@ alpha_va_arg (valist, type)
   offset_field = build (COMPONENT_REF, TREE_TYPE (offset_field),
                        valist, offset_field);
 
+  /* If the type could not be passed in registers, skip the block
+     reserved for the registers.  */
+  if (MUST_PASS_IN_STACK (TYPE_MODE (type), type))
+    {
+      t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field,
+                build (MAX_EXPR, TREE_TYPE (offset_field), 
+                       offset_field, build_int_2 (6*8, 0)));
+      TREE_SIDE_EFFECTS (t) = 1;
+      expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+    }
+
   wide_type = make_signed_type (64);
   wide_ofs = save_expr (build1 (CONVERT_EXPR, wide_type, offset_field));
 
@@ -5565,7 +6548,7 @@ alpha_va_arg (valist, type)
   if (TYPE_MODE (type) == TFmode || TYPE_MODE (type) == TCmode)
     {
       indirect = 1;
-      tsize = UNITS_PER_WORD;
+      rounded_size = size_int (UNITS_PER_WORD);
     }
   else if (FLOAT_TYPE_P (type))
     {
@@ -5589,7 +6572,7 @@ alpha_va_arg (valist, type)
 
   t = build (MODIFY_EXPR, TREE_TYPE (offset_field), offset_field,
             build (PLUS_EXPR, TREE_TYPE (offset_field), 
-                   offset_field, build_int_2 (tsize, 0)));
+                   offset_field, rounded_size));
   TREE_SIDE_EFFECTS (t) = 1;
   expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
 
@@ -5602,6 +6585,310 @@ alpha_va_arg (valist, type)
   return addr;
 }
 \f
+/* Builtins.  */
+
+enum alpha_builtin
+{
+  ALPHA_BUILTIN_CMPBGE,
+  ALPHA_BUILTIN_EXTBL,
+  ALPHA_BUILTIN_EXTWL,
+  ALPHA_BUILTIN_EXTLL,
+  ALPHA_BUILTIN_EXTQL,
+  ALPHA_BUILTIN_EXTWH,
+  ALPHA_BUILTIN_EXTLH,
+  ALPHA_BUILTIN_EXTQH,
+  ALPHA_BUILTIN_INSBL,
+  ALPHA_BUILTIN_INSWL,
+  ALPHA_BUILTIN_INSLL,
+  ALPHA_BUILTIN_INSQL,
+  ALPHA_BUILTIN_INSWH,
+  ALPHA_BUILTIN_INSLH,
+  ALPHA_BUILTIN_INSQH,
+  ALPHA_BUILTIN_MSKBL,
+  ALPHA_BUILTIN_MSKWL,
+  ALPHA_BUILTIN_MSKLL,
+  ALPHA_BUILTIN_MSKQL,
+  ALPHA_BUILTIN_MSKWH,
+  ALPHA_BUILTIN_MSKLH,
+  ALPHA_BUILTIN_MSKQH,
+  ALPHA_BUILTIN_UMULH,
+  ALPHA_BUILTIN_ZAP,
+  ALPHA_BUILTIN_ZAPNOT,
+  ALPHA_BUILTIN_AMASK,
+  ALPHA_BUILTIN_IMPLVER,
+  ALPHA_BUILTIN_RPCC,
+  ALPHA_BUILTIN_THREAD_POINTER,
+  ALPHA_BUILTIN_SET_THREAD_POINTER,
+
+  /* TARGET_MAX */
+  ALPHA_BUILTIN_MINUB8,
+  ALPHA_BUILTIN_MINSB8,
+  ALPHA_BUILTIN_MINUW4,
+  ALPHA_BUILTIN_MINSW4,
+  ALPHA_BUILTIN_MAXUB8,
+  ALPHA_BUILTIN_MAXSB8,
+  ALPHA_BUILTIN_MAXUW4,
+  ALPHA_BUILTIN_MAXSW4,
+  ALPHA_BUILTIN_PERR,
+  ALPHA_BUILTIN_PKLB,
+  ALPHA_BUILTIN_PKWB,
+  ALPHA_BUILTIN_UNPKBL,
+  ALPHA_BUILTIN_UNPKBW,
+
+  /* TARGET_CIX */
+  ALPHA_BUILTIN_CTTZ,
+  ALPHA_BUILTIN_CTLZ,
+  ALPHA_BUILTIN_CTPOP,
+
+  ALPHA_BUILTIN_max
+};
+
+static unsigned int const code_for_builtin[ALPHA_BUILTIN_max] = {
+  CODE_FOR_builtin_cmpbge,
+  CODE_FOR_builtin_extbl,
+  CODE_FOR_builtin_extwl,
+  CODE_FOR_builtin_extll,
+  CODE_FOR_builtin_extql,
+  CODE_FOR_builtin_extwh,
+  CODE_FOR_builtin_extlh,
+  CODE_FOR_builtin_extqh,
+  CODE_FOR_builtin_insbl,
+  CODE_FOR_builtin_inswl,
+  CODE_FOR_builtin_insll,
+  CODE_FOR_builtin_insql,
+  CODE_FOR_builtin_inswh,
+  CODE_FOR_builtin_inslh,
+  CODE_FOR_builtin_insqh,
+  CODE_FOR_builtin_mskbl,
+  CODE_FOR_builtin_mskwl,
+  CODE_FOR_builtin_mskll,
+  CODE_FOR_builtin_mskql,
+  CODE_FOR_builtin_mskwh,
+  CODE_FOR_builtin_msklh,
+  CODE_FOR_builtin_mskqh,
+  CODE_FOR_umuldi3_highpart,
+  CODE_FOR_builtin_zap,
+  CODE_FOR_builtin_zapnot,
+  CODE_FOR_builtin_amask,
+  CODE_FOR_builtin_implver,
+  CODE_FOR_builtin_rpcc,
+  CODE_FOR_load_tp,
+  CODE_FOR_set_tp,
+
+  /* TARGET_MAX */
+  CODE_FOR_builtin_minub8,
+  CODE_FOR_builtin_minsb8,
+  CODE_FOR_builtin_minuw4,
+  CODE_FOR_builtin_minsw4,
+  CODE_FOR_builtin_maxub8,
+  CODE_FOR_builtin_maxsb8,
+  CODE_FOR_builtin_maxuw4,
+  CODE_FOR_builtin_maxsw4,
+  CODE_FOR_builtin_perr,
+  CODE_FOR_builtin_pklb,
+  CODE_FOR_builtin_pkwb,
+  CODE_FOR_builtin_unpkbl,
+  CODE_FOR_builtin_unpkbw,
+
+  /* TARGET_CIX */
+  CODE_FOR_builtin_cttz,
+  CODE_FOR_builtin_ctlz,
+  CODE_FOR_builtin_ctpop
+};
+
+struct alpha_builtin_def
+{
+  const char *name;
+  enum alpha_builtin code;
+  unsigned int target_mask;
+};
+
+static struct alpha_builtin_def const zero_arg_builtins[] = {
+  { "__builtin_alpha_implver", ALPHA_BUILTIN_IMPLVER,  0 },
+  { "__builtin_alpha_rpcc",    ALPHA_BUILTIN_RPCC,     0 }
+};
+
+static struct alpha_builtin_def const one_arg_builtins[] = {
+  { "__builtin_alpha_amask",   ALPHA_BUILTIN_AMASK,    0 },
+  { "__builtin_alpha_pklb",    ALPHA_BUILTIN_PKLB,     MASK_MAX },
+  { "__builtin_alpha_pkwb",    ALPHA_BUILTIN_PKWB,     MASK_MAX },
+  { "__builtin_alpha_unpkbl",  ALPHA_BUILTIN_UNPKBL,   MASK_MAX },
+  { "__builtin_alpha_unpkbw",  ALPHA_BUILTIN_UNPKBW,   MASK_MAX },
+  { "__builtin_alpha_cttz",    ALPHA_BUILTIN_CTTZ,     MASK_CIX },
+  { "__builtin_alpha_ctlz",    ALPHA_BUILTIN_CTLZ,     MASK_CIX },
+  { "__builtin_alpha_ctpop",   ALPHA_BUILTIN_CTPOP,    MASK_CIX }
+};
+
+static struct alpha_builtin_def const two_arg_builtins[] = {
+  { "__builtin_alpha_cmpbge",  ALPHA_BUILTIN_CMPBGE,   0 },
+  { "__builtin_alpha_extbl",   ALPHA_BUILTIN_EXTBL,    0 },
+  { "__builtin_alpha_extwl",   ALPHA_BUILTIN_EXTWL,    0 },
+  { "__builtin_alpha_extll",   ALPHA_BUILTIN_EXTLL,    0 },
+  { "__builtin_alpha_extql",   ALPHA_BUILTIN_EXTQL,    0 },
+  { "__builtin_alpha_extwh",   ALPHA_BUILTIN_EXTWH,    0 },
+  { "__builtin_alpha_extlh",   ALPHA_BUILTIN_EXTLH,    0 },
+  { "__builtin_alpha_extqh",   ALPHA_BUILTIN_EXTQH,    0 },
+  { "__builtin_alpha_insbl",   ALPHA_BUILTIN_INSBL,    0 },
+  { "__builtin_alpha_inswl",   ALPHA_BUILTIN_INSWL,    0 },
+  { "__builtin_alpha_insll",   ALPHA_BUILTIN_INSLL,    0 },
+  { "__builtin_alpha_insql",   ALPHA_BUILTIN_INSQL,    0 },
+  { "__builtin_alpha_inswh",   ALPHA_BUILTIN_INSWH,    0 },
+  { "__builtin_alpha_inslh",   ALPHA_BUILTIN_INSLH,    0 },
+  { "__builtin_alpha_insqh",   ALPHA_BUILTIN_INSQH,    0 },
+  { "__builtin_alpha_mskbl",   ALPHA_BUILTIN_MSKBL,    0 },
+  { "__builtin_alpha_mskwl",   ALPHA_BUILTIN_MSKWL,    0 },
+  { "__builtin_alpha_mskll",   ALPHA_BUILTIN_MSKLL,    0 },
+  { "__builtin_alpha_mskql",   ALPHA_BUILTIN_MSKQL,    0 },
+  { "__builtin_alpha_mskwh",   ALPHA_BUILTIN_MSKWH,    0 },
+  { "__builtin_alpha_msklh",   ALPHA_BUILTIN_MSKLH,    0 },
+  { "__builtin_alpha_mskqh",   ALPHA_BUILTIN_MSKQH,    0 },
+  { "__builtin_alpha_umulh",   ALPHA_BUILTIN_UMULH,    0 },
+  { "__builtin_alpha_zap",     ALPHA_BUILTIN_ZAP,      0 },
+  { "__builtin_alpha_zapnot",  ALPHA_BUILTIN_ZAPNOT,   0 },
+  { "__builtin_alpha_minub8",  ALPHA_BUILTIN_MINUB8,   MASK_MAX },
+  { "__builtin_alpha_minsb8",  ALPHA_BUILTIN_MINSB8,   MASK_MAX },
+  { "__builtin_alpha_minuw4",  ALPHA_BUILTIN_MINUW4,   MASK_MAX },
+  { "__builtin_alpha_minsw4",  ALPHA_BUILTIN_MINSW4,   MASK_MAX },
+  { "__builtin_alpha_maxub8",  ALPHA_BUILTIN_MAXUB8,   MASK_MAX },
+  { "__builtin_alpha_maxsb8",  ALPHA_BUILTIN_MAXSB8,   MASK_MAX },
+  { "__builtin_alpha_maxuw4",  ALPHA_BUILTIN_MAXUW4,   MASK_MAX },
+  { "__builtin_alpha_maxsw4",  ALPHA_BUILTIN_MAXSW4,   MASK_MAX },
+  { "__builtin_alpha_perr",    ALPHA_BUILTIN_PERR,     MASK_MAX }
+};
+
+static void
+alpha_init_builtins ()
+{
+  const struct alpha_builtin_def *p;
+  tree ftype;
+  size_t i;
+
+  ftype = build_function_type (long_integer_type_node, void_list_node);
+
+  p = zero_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (zero_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                       NULL, NULL_TREE);
+
+  ftype = build_function_type_list (long_integer_type_node,
+                                   long_integer_type_node, NULL_TREE);
+
+  p = one_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (one_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                       NULL, NULL_TREE);
+
+  ftype = build_function_type_list (long_integer_type_node,
+                                   long_integer_type_node,
+                                   long_integer_type_node, NULL_TREE);
+
+  p = two_arg_builtins;
+  for (i = 0; i < ARRAY_SIZE (two_arg_builtins); ++i, ++p)
+    if ((target_flags & p->target_mask) == p->target_mask)
+      builtin_function (p->name, ftype, p->code, BUILT_IN_MD,
+                       NULL, NULL_TREE);
+
+  ftype = build_function_type (ptr_type_node, void_list_node);
+  builtin_function ("__builtin_thread_pointer", ftype,
+                   ALPHA_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
+                   NULL, NULL_TREE);
+
+  ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
+  builtin_function ("__builtin_set_thread_pointer", ftype,
+                   ALPHA_BUILTIN_SET_THREAD_POINTER, BUILT_IN_MD,
+                   NULL, NULL_TREE);
+}
+
+/* Expand an expression EXP that calls a built-in function,
+   with result going to TARGET if that's convenient
+   (and in mode MODE if that's convenient).
+   SUBTARGET may be used as the target for computing one of EXP's operands.
+   IGNORE is nonzero if the value is to be ignored.  */
+
+static rtx
+alpha_expand_builtin (exp, target, subtarget, mode, ignore)
+     tree exp;
+     rtx target;
+     rtx subtarget ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     int ignore ATTRIBUTE_UNUSED;
+{
+#define MAX_ARGS 2
+
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum insn_code icode;
+  rtx op[MAX_ARGS], pat;
+  int arity;
+  bool nonvoid;
+
+  if (fcode >= ALPHA_BUILTIN_max)
+    internal_error ("bad builtin fcode");
+  icode = code_for_builtin[fcode];
+  if (icode == 0)
+    internal_error ("bad builtin fcode");
+
+  nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
+
+  for (arglist = TREE_OPERAND (exp, 1), arity = 0;
+       arglist;
+       arglist = TREE_CHAIN (arglist), arity++)
+    {
+      const struct insn_operand_data *insn_op;
+
+      tree arg = TREE_VALUE (arglist);
+      if (arg == error_mark_node)
+       return NULL_RTX;
+      if (arity > MAX_ARGS)
+       return NULL_RTX;
+
+      insn_op = &insn_data[icode].operand[arity + nonvoid];
+
+      op[arity] = expand_expr (arg, NULL_RTX, insn_op->mode, 0);
+
+      if (!(*insn_op->predicate) (op[arity], insn_op->mode))
+       op[arity] = copy_to_mode_reg (insn_op->mode, op[arity]);
+    }
+
+  if (nonvoid)
+    {
+      enum machine_mode tmode = insn_data[icode].operand[0].mode;
+      if (!target
+         || GET_MODE (target) != tmode
+         || !(*insn_data[icode].operand[0].predicate) (target, tmode))
+       target = gen_reg_rtx (tmode);
+    }
+
+  switch (arity)
+    {
+    case 0:
+      pat = GEN_FCN (icode) (target);
+      break;
+    case 1:
+      if (nonvoid)
+        pat = GEN_FCN (icode) (target, op[0]);
+      else
+       pat = GEN_FCN (icode) (op[0]);
+      break;
+    case 2:
+      pat = GEN_FCN (icode) (target, op[0], op[1]);
+      break;
+    default:
+      abort ();
+    }
+  if (!pat)
+    return NULL_RTX;
+  emit_insn (pat);
+
+  if (nonvoid)
+    return target;
+  else
+    return const0_rtx;
+}
+\f
 /* This page contains routines that are used to determine what the function
    prologue and epilogue code will do and write them out.  */
 
@@ -5613,7 +6900,8 @@ alpha_va_arg (valist, type)
    descriptior to generate.  */
 
 /* Nonzero if we need a stack procedure.  */
-static int alpha_is_stack_procedure;
+enum alpha_procedure_types {PT_NULL = 0, PT_REGISTER = 1, PT_STACK = 2};
+static enum alpha_procedure_types alpha_procedure_type;
 
 /* Register number (either FP or SP) that is used to unwind the frame.  */
 static int vms_unwind_regno;
@@ -5637,46 +6925,49 @@ alpha_sa_mask (imaskP, fmaskP)
   unsigned long fmask = 0;
   unsigned int i;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (!current_function_is_thunk)
-#endif
+  /* Irritatingly, there are two kinds of thunks -- those created with
+     TARGET_ASM_OUTPUT_MI_THUNK and those with DECL_THUNK_P that go
+     through the regular part of the compiler.  In the
+     TARGET_ASM_OUTPUT_MI_THUNK case we don't have valid register life
+     info, but assemble_start_function wants to output .frame and
+     .mask directives.  */
+  if (current_function_is_thunk && !no_new_pseudos)
     {
-      if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
-       imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+      *imaskP = 0;
+      *fmaskP = 0;
+      return;
+    }
 
-      /* One for every register we have to save.  */
-      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
-       if (! fixed_regs[i] && ! call_used_regs[i]
-           && regs_ever_live[i] && i != REG_RA
-           && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
-         {
-           if (i < 32)
-             imask |= (1L << i);
-           else
-             fmask |= (1L << (i - 32));
-         }
+  if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+    imask |= (1UL << HARD_FRAME_POINTER_REGNUM);
 
-      /* We need to restore these for the handler.  */
-      if (current_function_calls_eh_return)
-       {
-         for (i = 0; ; ++i)
-           {
-             unsigned regno = EH_RETURN_DATA_REGNO (i);
-             if (regno == INVALID_REGNUM)
-               break;
-             imask |= 1L << regno;
-           }
-       }
+  /* One for every register we have to save.  */
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    if (! fixed_regs[i] && ! call_used_regs[i]
+       && regs_ever_live[i] && i != REG_RA
+       && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
+      {
+       if (i < 32)
+         imask |= (1UL << i);
+       else
+         fmask |= (1UL << (i - 32));
+      }
+
+  /* We need to restore these for the handler.  */
+  if (current_function_calls_eh_return)
+    for (i = 0; ; ++i)
+      {
+       unsigned regno = EH_RETURN_DATA_REGNO (i);
+       if (regno == INVALID_REGNUM)
+         break;
+       imask |= 1UL << regno;
+      }
      
-      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);
-       }
-    }
+  /* 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 |= (1UL << REG_RA);
 
   *imaskP = imask;
   *fmaskP = fmask;
@@ -5685,34 +6976,23 @@ alpha_sa_mask (imaskP, fmaskP)
 int
 alpha_sa_size ()
 {
+  unsigned long mask[2];
   int sa_size = 0;
-  int i;
+  int i, j;
 
-#ifdef ASM_OUTPUT_MI_THUNK
-  if (current_function_is_thunk)
-    sa_size = 0;
+  alpha_sa_mask (&mask[0], &mask[1]);
+
+  if (TARGET_ABI_UNICOSMK)
+    {
+      if (mask[0] || mask[1])
+       sa_size = 14;
+    }
   else
-#endif
     {
-      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++;
-       }
+      for (j = 0; j < 2; ++j)
+       for (i = 0; i < 32; ++i)
+         if ((mask[j] >> i) & 1)
+           sa_size++;
     }
 
   if (TARGET_ABI_UNICOSMK)
@@ -5723,18 +7003,16 @@ alpha_sa_size ()
         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;
+      alpha_procedure_type
+       = (sa_size || get_frame_size() != 0
+          || current_function_outgoing_args_size
+          || current_function_stdarg || current_function_calls_alloca
+          || frame_pointer_needed)
+         ? PT_STACK : PT_REGISTER;
 
       /* Always reserve space for saving callee-saved registers if we
         need a frame as required by the calling convention.  */
-      if (alpha_is_stack_procedure)
+      if (alpha_procedure_type == PT_STACK)
         sa_size = 14;
     }
   else if (TARGET_ABI_OPEN_VMS)
@@ -5742,17 +7020,29 @@ alpha_sa_size ()
       /* Start by assuming we can use a register procedure if we don't
         make any calls (REG_RA not used) or need to save any
         registers and a stack procedure if we do.  */
-      alpha_is_stack_procedure = sa_size != 0 || alpha_ra_ever_killed ();
+      if ((mask[0] >> REG_RA) & 1)
+       alpha_procedure_type = PT_STACK;
+      else if (get_frame_size() != 0)
+       alpha_procedure_type = PT_REGISTER;
+      else
+       alpha_procedure_type = PT_NULL;
+
+      /* Don't reserve space for saving FP & RA yet.  Do that later after we've
+        made the final decision on stack procedure vs register procedure.  */
+      if (alpha_procedure_type == PT_STACK)
+       sa_size -= 2;
 
       /* Decide whether to refer to objects off our PV via FP or PV.
         If we need FP for something else or if we receive a nonlocal
         goto (which expects PV to contain the value), we must use PV.
         Otherwise, start by assuming we can use FP.  */
-      vms_base_regno = (frame_pointer_needed
-                       || current_function_has_nonlocal_label
-                       || alpha_is_stack_procedure
-                       || current_function_outgoing_args_size
-                       ? REG_PV : HARD_FRAME_POINTER_REGNUM);
+
+      vms_base_regno
+       = (frame_pointer_needed
+          || current_function_has_nonlocal_label
+          || alpha_procedure_type == PT_STACK
+          || current_function_outgoing_args_size)
+         ? REG_PV : HARD_FRAME_POINTER_REGNUM;
 
       /* If we want to copy PV into FP, we need to find some register
         in which to save FP.  */
@@ -5763,24 +7053,21 @@ alpha_sa_size ()
          if (! fixed_regs[i] && call_used_regs[i] && ! regs_ever_live[i])
            vms_save_fp_regno = i;
 
-      if (vms_save_fp_regno == -1)
-       vms_base_regno = REG_PV, alpha_is_stack_procedure = 1;
+      if (vms_save_fp_regno == -1 && alpha_procedure_type == PT_REGISTER)
+       vms_base_regno = REG_PV, alpha_procedure_type = PT_STACK;
+      else if (alpha_procedure_type == PT_NULL)
+       vms_base_regno = REG_PV;
 
       /* Stack unwinding should be done via FP unless we use it for PV.  */
       vms_unwind_regno = (vms_base_regno == REG_PV
                          ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
       /* If this is a stack procedure, allow space for saving FP and RA.  */
-      if (alpha_is_stack_procedure)
+      if (alpha_procedure_type == PT_STACK)
        sa_size += 2;
     }
   else
     {
-      /* If some registers were saved but not RA, RA must also be saved,
-        so leave space for it.  */
-      if (!TARGET_ABI_UNICOSMK && (sa_size != 0 || alpha_ra_ever_killed ()))
-       sa_size++;
-
       /* Our size must be even (multiple of 16 bytes).  */
       if (sa_size & 1)
        sa_size++;
@@ -5789,11 +7076,35 @@ alpha_sa_size ()
   return sa_size * 8;
 }
 
+/* Define the offset between two registers, one to be eliminated,
+   and the other its replacement, at the start of a routine.  */
+
+HOST_WIDE_INT
+alpha_initial_elimination_offset (from, to)
+     unsigned int from, to ATTRIBUTE_UNUSED;
+{
+  HOST_WIDE_INT ret;
+
+  ret = alpha_sa_size ();
+  ret += ALPHA_ROUND (current_function_outgoing_args_size);
+
+  if (from == FRAME_POINTER_REGNUM)
+    ;
+  else if (from == ARG_POINTER_REGNUM)
+    ret += (ALPHA_ROUND (get_frame_size ()
+                        + current_function_pretend_args_size)
+           - current_function_pretend_args_size);
+  else
+    abort ();
+
+  return ret;
+}
+
 int
 alpha_pv_save_size ()
 {
   alpha_sa_size ();
-  return alpha_is_stack_procedure ? 8 : 0;
+  return alpha_procedure_type == PT_STACK ? 8 : 0;
 }
 
 int
@@ -5808,18 +7119,27 @@ alpha_using_fp ()
 const struct attribute_spec vms_attribute_table[] =
 {
   /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
-  { "overlaid", 0, 0, true,  false, false, NULL },
-  { NULL,       0, 0, false, false, false, NULL }
+  { "overlaid",   0, 0, true,  false, false, NULL },
+  { "global",     0, 0, true,  false, false, NULL },
+  { "initialize", 0, 0, true,  false, false, NULL },
+  { NULL,         0, 0, false, false, false, NULL }
 };
 
 #endif
 
 static int
-find_lo_sum (px, data)
+find_lo_sum_using_gp (px, data)
      rtx *px;
      void *data ATTRIBUTE_UNUSED;
 {
-  return GET_CODE (*px) == LO_SUM;
+  return GET_CODE (*px) == LO_SUM && XEXP (*px, 0) == pic_offset_table_rtx;
+}
+
+int
+alpha_find_lo_sum_using_gp (insn)
+     rtx insn;
+{
+  return for_each_rtx (&PATTERN (insn), find_lo_sum_using_gp, NULL) > 0;
 }
 
 static int
@@ -5831,13 +7151,11 @@ alpha_does_function_need_gp ()
   if (! TARGET_ABI_OSF)
     return 0;
 
-  if (TARGET_PROFILING_NEEDS_GP && profile_flag)
+  if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
     return 1;
 
-#ifdef ASM_OUTPUT_MI_THUNK
   if (current_function_is_thunk)
     return 1;
-#endif
 
   /* If we need a GP (we have a LDSYM insn or a CALL_INSN), load it first. 
      Even if we are a static function, we still need to do this in case
@@ -5850,15 +7168,9 @@ alpha_does_function_need_gp ()
   for (; insn; insn = NEXT_INSN (insn))
     if (INSN_P (insn)
        && GET_CODE (PATTERN (insn)) != USE
-       && GET_CODE (PATTERN (insn)) != CLOBBER)
-      {
-       enum attr_type type = get_attr_type (insn);
-       if (type == TYPE_LDSYM || type == TYPE_JSR)
-         return 1;
-       if (TARGET_EXPLICIT_RELOCS
-           && for_each_rtx (&PATTERN (insn), find_lo_sum, NULL) > 0)
-         return 1;
-      }
+       && GET_CODE (PATTERN (insn)) != CLOBBER
+       && get_attr_usegp (insn))
+      return 1;
 
   return 0;
 }
@@ -5885,22 +7197,30 @@ alpha_write_verstamp (file)
 static rtx
 set_frame_related_p ()
 {
-  rtx seq = gen_sequence ();
+  rtx seq = get_insns ();
+  rtx insn;
+
   end_sequence ();
 
-  if (GET_CODE (seq) == SEQUENCE)
+  if (!seq)
+    return NULL_RTX;
+
+  if (INSN_P (seq))
     {
-      int i = XVECLEN (seq, 0);
-      while (--i >= 0)
-       RTX_FRAME_RELATED_P (XVECEXP (seq, 0, i)) = 1;
-     return emit_insn (seq);
+      insn = seq;
+      while (insn != NULL_RTX)
+       {
+         RTX_FRAME_RELATED_P (insn) = 1;
+         insn = NEXT_INSN (insn);
+       }
+      seq = emit_insn (seq);
     }
   else
     {
       seq = emit_insn (seq);
       RTX_FRAME_RELATED_P (seq) = 1;
-      return seq;
     }
+  return seq;
 }
 
 #define FRP(exp)  (start_sequence (), exp, set_frame_related_p ())
@@ -5942,13 +7262,13 @@ alpha_expand_prologue ()
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (alpha_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
   else if (TARGET_ABI_UNICOSMK)
     /* We have to allocate space for the DSIB if we generate a frame.  */
     frame_size = ALPHA_ROUND (sa_size
-                             + (alpha_is_stack_procedure ? 48 : 0))
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
                 + ALPHA_ROUND (frame_size
                                + current_function_outgoing_args_size);
   else
@@ -5976,7 +7296,7 @@ alpha_expand_prologue ()
      the call to mcount ourselves, rather than having the linker do it
      magically in response to -pg.  Since _mcount has special linkage,
      don't represent the call as a call.  */
-  if (TARGET_PROFILING_NEEDS_GP && profile_flag)
+  if (TARGET_PROFILING_NEEDS_GP && current_function_profile)
     emit_insn (gen_prologue_mcount ());
 
   if (TARGET_ABI_UNICOSMK)
@@ -6103,7 +7423,7 @@ alpha_expand_prologue ()
        }
     
       /* Save regs in stack order.  Beginning with VMS PV.  */
-      if (TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
+      if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
        {
          mem = gen_rtx_MEM (DImode, stack_pointer_rtx);
          set_mem_alias_set (mem, alpha_sr_alias_set);
@@ -6111,18 +7431,18 @@ alpha_expand_prologue ()
        }
 
       /* Save register RA next.  */
-      if (imask & (1L << REG_RA))
+      if (imask & (1UL << REG_RA))
        {
          mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
          set_mem_alias_set (mem, alpha_sr_alias_set);
          FRP (emit_move_insn (mem, gen_rtx_REG (DImode, REG_RA)));
-         imask &= ~(1L << REG_RA);
+         imask &= ~(1UL << REG_RA);
          reg_offset += 8;
        }
 
       /* Now save any other registers required to be saved.  */
       for (i = 0; i < 32; i++)
-       if (imask & (1L << i))
+       if (imask & (1UL << i))
          {
            mem = gen_rtx_MEM (DImode, plus_constant (sa_reg, reg_offset));
            set_mem_alias_set (mem, alpha_sr_alias_set);
@@ -6131,7 +7451,7 @@ alpha_expand_prologue ()
          }
 
       for (i = 0; i < 32; i++)
-       if (fmask & (1L << i))
+       if (fmask & (1UL << i))
          {
            mem = gen_rtx_MEM (DFmode, plus_constant (sa_reg, reg_offset));
            set_mem_alias_set (mem, alpha_sr_alias_set);
@@ -6139,7 +7459,7 @@ alpha_expand_prologue ()
            reg_offset += 8;
          }
     }
-  else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+  else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
     {
       /* The standard frame on the T3E includes space for saving registers.
         We just have to use it. We don't have to save the return address and
@@ -6147,7 +7467,7 @@ alpha_expand_prologue ()
 
       reg_offset = -56;
       for (i = 9; i < 15; i++)
-       if (imask & (1L << i))
+       if (imask & (1UL << i))
          {
            mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
                                                     reg_offset));
@@ -6156,7 +7476,7 @@ alpha_expand_prologue ()
            reg_offset -= 8;
          }
       for (i = 2; i < 10; i++)
-       if (fmask & (1L << i))
+       if (fmask & (1UL << i))
          {
            mem = gen_rtx_MEM (DFmode, plus_constant (hard_frame_pointer_rtx,
                                                      reg_offset));
@@ -6168,26 +7488,47 @@ alpha_expand_prologue ()
 
   if (TARGET_ABI_OPEN_VMS)
     {
-      if (!alpha_is_stack_procedure)
-       /* Register frame procedures save the fp.  */
-       /* ??? Ought to have a dwarf2 save for this.  */
+      if (alpha_procedure_type == PT_REGISTER)
+       /* Register frame procedures save the fp.
+          ?? Ought to have a dwarf2 save for this.  */
        emit_move_insn (gen_rtx_REG (DImode, vms_save_fp_regno),
                        hard_frame_pointer_rtx);
 
-      if (vms_base_regno != REG_PV)
+      if (alpha_procedure_type != PT_NULL && vms_base_regno != REG_PV)
        emit_insn (gen_force_movdi (gen_rtx_REG (DImode, vms_base_regno),
                                    gen_rtx_REG (DImode, REG_PV)));
 
-      if (vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
+      if (alpha_procedure_type != PT_NULL
+         && vms_unwind_regno == HARD_FRAME_POINTER_REGNUM)
        FRP (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx));
 
       /* If we have to allocate space for outgoing args, do it now.  */
       if (current_function_outgoing_args_size != 0)
-       FRP (emit_move_insn
-            (stack_pointer_rtx, 
-             plus_constant (hard_frame_pointer_rtx,
-                            - (ALPHA_ROUND
-                               (current_function_outgoing_args_size)))));
+       {
+         rtx seq
+           = emit_move_insn (stack_pointer_rtx, 
+                             plus_constant
+                             (hard_frame_pointer_rtx,
+                              - (ALPHA_ROUND
+                                 (current_function_outgoing_args_size))));
+         
+         /* Only set FRAME_RELATED_P on the stack adjustment we just emitted
+            if ! frame_pointer_needed. Setting the bit will change the CFA
+            computation rule to use sp again, which would be wrong if we had
+            frame_pointer_needed, as this means sp might move unpredictably
+            later on.
+
+            Also, note that
+              frame_pointer_needed
+              => vms_unwind_regno == HARD_FRAME_POINTER_REGNUM
+            and
+              current_function_outgoing_args_size != 0
+              => alpha_procedure_type != PT_NULL,
+
+            so when we are not setting the bit here, we are guaranteed to
+            have emited an FRP frame pointer update just before.  */
+         RTX_FRAME_RELATED_P (seq) = ! frame_pointer_needed;
+       }
     }
   else if (!TARGET_ABI_UNICOSMK)
     {
@@ -6231,7 +7572,7 @@ alpha_start_function (file, fnname, decl)
   /* Stack space needed for pushing registers clobbered by us.  */
   HOST_WIDE_INT sa_size;
   /* Complete stack size needed.  */
-  HOST_WIDE_INT frame_size;
+  unsigned HOST_WIDE_INT frame_size;
   /* Offset from base reg to register save area.  */
   HOST_WIDE_INT reg_offset;
   char *entry_label = (char *) alloca (strlen (fnname) + 6);
@@ -6251,12 +7592,12 @@ alpha_start_function (file, fnname, decl)
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (alpha_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
   else if (TARGET_ABI_UNICOSMK)
     frame_size = ALPHA_ROUND (sa_size
-                             + (alpha_is_stack_procedure ? 48 : 0))
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
                 + ALPHA_ROUND (frame_size
                              + current_function_outgoing_args_size);
   else
@@ -6303,7 +7644,9 @@ alpha_start_function (file, fnname, decl)
 
       /* If the function needs GP, we'll write the "..ng" label there.
         Otherwise, do it here.  */
-      if (TARGET_ABI_OSF && ! alpha_function_needs_gp)
+      if (TARGET_ABI_OSF
+          && ! alpha_function_needs_gp
+         && ! current_function_is_thunk)
        {
          putc ('$', file);
          assemble_name (file, fnname);
@@ -6345,23 +7688,17 @@ alpha_start_function (file, fnname, decl)
   if (TARGET_ABI_UNICOSMK)
     ;
   else if (TARGET_ABI_OPEN_VMS)
-    {
-      fprintf (file, "\t.frame $%d,", vms_unwind_regno);
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-              frame_size >= ((HOST_WIDE_INT) 1 << 31) ? 0 : frame_size);
-      fputs (",$26,", file);
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC, reg_offset);
-      fputs ("\n", file);
-    }
+    fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,"
+            HOST_WIDE_INT_PRINT_DEC "\n",
+            vms_unwind_regno,
+            frame_size >= (1UL << 31) ? 0 : frame_size,
+            reg_offset);
   else if (!flag_inhibit_size_directive)
-    {
-      fprintf (file, "\t.frame $%d,",
-              (frame_pointer_needed
-               ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM));
-      fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-              frame_size >= (1l << 31) ? 0 : frame_size);
-      fprintf (file, ",$26,%d\n", current_function_pretend_args_size);
-    }
+    fprintf (file, "\t.frame $%d," HOST_WIDE_INT_PRINT_DEC ",$26,%d\n",
+            (frame_pointer_needed
+             ? HARD_FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM),
+            frame_size >= (1UL << 31) ? 0 : frame_size,
+            current_function_pretend_args_size);
 
   /* Describe which registers were spilled.  */
   if (TARGET_ABI_UNICOSMK)
@@ -6371,54 +7708,37 @@ alpha_start_function (file, fnname, decl)
       if (imask)
         /* ??? 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));
+       fprintf (file, "\t.mask 0x%lx,0\n", imask & ~(1UL << REG_RA));
       if (fmask)
        fprintf (file, "\t.fmask 0x%lx,0\n", fmask);
-      if (!alpha_is_stack_procedure)
+      if (alpha_procedure_type == PT_REGISTER)
        fprintf (file, "\t.fp_save $%d\n", vms_save_fp_regno);
     }
   else if (!flag_inhibit_size_directive)
     {
       if (imask)
        {
-         fprintf (file, "\t.mask 0x%lx,", imask);
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-                  frame_size >= (1l << 31) ? 0 : reg_offset - frame_size);
-         putc ('\n', file);
+         fprintf (file, "\t.mask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", imask,
+                  frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size);
 
          for (i = 0; i < 32; ++i)
-           if (imask & (1L << i))
+           if (imask & (1UL << i))
              reg_offset += 8;
        }
 
       if (fmask)
-       {
-         fprintf (file, "\t.fmask 0x%lx,", fmask);
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC,
-                  frame_size >= (1l << 31) ? 0 : reg_offset - frame_size);
-         putc ('\n', file);
-       }
+       fprintf (file, "\t.fmask 0x%lx," HOST_WIDE_INT_PRINT_DEC "\n", fmask,
+                frame_size >= (1UL << 31) ? 0 : reg_offset - frame_size);
     }
 
 #if TARGET_ABI_OPEN_VMS
-  /* Ifdef'ed cause readonly_section and link_section are only
-     available then.  */
-  readonly_section ();
+  /* Ifdef'ed cause link_section are only available then.  */
+  readonly_data_section ();
   fprintf (file, "\t.align 3\n");
   assemble_name (file, fnname); fputs ("..na:\n", file);
   fputs ("\t.ascii \"", file);
   assemble_name (file, fnname);
   fputs ("\\0\"\n", file);
-      
-  link_section ();
-  fprintf (file, "\t.align 3\n");
-  fputs ("\t.name ", file);
-  assemble_name (file, fnname);
-  fputs ("..na\n", file);
-  ASM_OUTPUT_LABEL (file, fnname);
-  fprintf (file, "\t.pdesc ");
-  assemble_name (file, fnname);
-  fprintf (file, "..en,%s\n", alpha_is_stack_procedure ? "stack" : "reg");
   alpha_need_linkage (fnname, 1);
   text_section ();
 #endif
@@ -6437,7 +7757,8 @@ alpha_output_function_end_prologue (file)
   else if (TARGET_ABI_WINDOWS_NT)
     fputs ("\t.prologue 0\n", file);
   else if (!flag_inhibit_size_directive)
-    fprintf (file, "\t.prologue %d\n", alpha_function_needs_gp);
+    fprintf (file, "\t.prologue %d\n",
+            alpha_function_needs_gp || current_function_is_thunk);
 }
 
 /* Write function epilogue.  */
@@ -6471,12 +7792,12 @@ alpha_expand_epilogue ()
   frame_size = get_frame_size ();
   if (TARGET_ABI_OPEN_VMS)
     frame_size = ALPHA_ROUND (sa_size 
-                             + (alpha_is_stack_procedure ? 8 : 0)
+                             + (alpha_procedure_type == PT_STACK ? 8 : 0)
                              + frame_size
                              + current_function_pretend_args_size);
   else if (TARGET_ABI_UNICOSMK)
     frame_size = ALPHA_ROUND (sa_size
-                             + (alpha_is_stack_procedure ? 48 : 0))
+                             + (alpha_procedure_type == PT_STACK ? 48 : 0))
                 + ALPHA_ROUND (frame_size
                              + current_function_outgoing_args_size);
   else
@@ -6486,14 +7807,20 @@ alpha_expand_epilogue ()
                                 + current_function_pretend_args_size));
 
   if (TARGET_ABI_OPEN_VMS)
-    reg_offset = 8;
+    {
+       if (alpha_procedure_type == PT_STACK)
+          reg_offset = 8;
+       else
+          reg_offset = 0;
+    }
   else
     reg_offset = ALPHA_ROUND (current_function_outgoing_args_size);
 
   alpha_sa_mask (&imask, &fmask);
 
-  fp_is_frame_pointer = ((TARGET_ABI_OPEN_VMS && alpha_is_stack_procedure)
-                        || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
+  fp_is_frame_pointer
+    = ((TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
+       || (!TARGET_ABI_OPEN_VMS && frame_pointer_needed));
   fp_offset = 0;
   sa_reg = stack_pointer_rtx;
 
@@ -6535,10 +7862,10 @@ alpha_expand_epilogue ()
       FRP (emit_move_insn (gen_rtx_REG (DImode, REG_RA), mem));
 
       reg_offset += 8;
-      imask &= ~(1L << REG_RA);
+      imask &= ~(1UL << REG_RA);
 
       for (i = 0; i < 32; ++i)
-       if (imask & (1L << i))
+       if (imask & (1UL << i))
          {
            if (i == HARD_FRAME_POINTER_REGNUM && fp_is_frame_pointer)
              fp_offset = reg_offset;
@@ -6552,7 +7879,7 @@ alpha_expand_epilogue ()
          }
 
       for (i = 0; i < 32; ++i)
-       if (fmask & (1L << i))
+       if (fmask & (1UL << i))
          {
            mem = gen_rtx_MEM (DFmode, plus_constant(sa_reg, reg_offset));
            set_mem_alias_set (mem, alpha_sr_alias_set);
@@ -6560,14 +7887,14 @@ alpha_expand_epilogue ()
            reg_offset += 8;
          }
     }
-  else if (TARGET_ABI_UNICOSMK && alpha_is_stack_procedure)
+  else if (TARGET_ABI_UNICOSMK && alpha_procedure_type == PT_STACK)
     {
       /* Restore callee-saved general-purpose registers.  */
 
       reg_offset = -56;
 
       for (i = 9; i < 15; i++)
-       if (imask & (1L << i))
+       if (imask & (1UL << i))
          {
            mem = gen_rtx_MEM (DImode, plus_constant(hard_frame_pointer_rtx,
                                                     reg_offset));
@@ -6577,7 +7904,7 @@ alpha_expand_epilogue ()
          }
 
       for (i = 2; i < 10; i++)
-       if (fmask & (1L << i))
+       if (fmask & (1UL << i))
          {
            mem = gen_rtx_MEM (DFmode, plus_constant(hard_frame_pointer_rtx,
                                                     reg_offset));
@@ -6680,13 +8007,13 @@ alpha_expand_epilogue ()
     }
   else 
     {
-      if (TARGET_ABI_OPEN_VMS && !alpha_is_stack_procedure)
+      if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_REGISTER)
         {
           emit_insn (gen_blockage ());
           FRP (emit_move_insn (hard_frame_pointer_rtx,
                               gen_rtx_REG (DImode, vms_save_fp_regno)));
         }
-      else if (TARGET_ABI_UNICOSMK && !alpha_is_stack_procedure)
+      else if (TARGET_ABI_UNICOSMK && alpha_procedure_type != PT_STACK)
        {
          /* Decrement the frame pointer if the function does not have a
             frame.  */
@@ -6697,7 +8024,7 @@ alpha_expand_epilogue ()
         }
     }
 }
-
+\f
 /* Output the rest of the textual info surrounding the epilogue.  */
 
 void
@@ -6715,20 +8042,9 @@ alpha_end_function (file, fnname, decl)
     }
   inside_function = FALSE;
 
-  /* Show that we know this function if it is called again. 
-
-     Don't do this for global functions in object files destined for a
-     shared library because the function may be overridden by the application
-     or other libraries.  Similarly, don't do this for weak functions.
-
-     Don't do this for functions not defined in the .text section, as
-     otherwise it's not unlikely that the destination is out of range
-     for a direct branch.  */
-
-  if (!DECL_WEAK (current_function_decl)
-      && (!flag_pic || !TREE_PUBLIC (current_function_decl))
-      && decl_in_text_section (current_function_decl))
-    SYMBOL_REF_FLAG (XEXP (DECL_RTL (current_function_decl), 0)) = 1;
+#if TARGET_ABI_OPEN_VMS
+  alpha_write_linkage (file, fnname, decl);
+#endif
 
   /* Output jump tables and the static subroutine information block.  */
   if (TARGET_ABI_UNICOSMK)
@@ -6737,6 +8053,110 @@ alpha_end_function (file, fnname, decl)
       unicosmk_output_deferred_case_vectors (file);
     }
 }
+
+#if TARGET_ABI_OSF
+/* Emit a tail call to FUNCTION after adjusting THIS by DELTA.
+
+   In order to avoid the hordes of differences between generated code
+   with and without TARGET_EXPLICIT_RELOCS, and to avoid duplicating
+   lots of code loading up large constants, generate rtl and emit it
+   instead of going straight to text.
+
+   Not sure why this idea hasn't been explored before...  */
+
+static void
+alpha_output_mi_thunk_osf (file, thunk_fndecl, delta, vcall_offset, function)
+     FILE *file;
+     tree thunk_fndecl ATTRIBUTE_UNUSED;
+     HOST_WIDE_INT delta;
+     HOST_WIDE_INT vcall_offset;
+     tree function;
+{
+  HOST_WIDE_INT hi, lo;
+  rtx this, insn, funexp;
+
+  /* We always require a valid GP.  */
+  emit_insn (gen_prologue_ldgp ());
+  emit_note (NULL, NOTE_INSN_PROLOGUE_END);
+
+  /* Find the "this" pointer.  If the function returns a structure,
+     the structure return pointer is in $16.  */
+  if (aggregate_value_p (TREE_TYPE (TREE_TYPE (function))))
+    this = gen_rtx_REG (Pmode, 17);
+  else
+    this = gen_rtx_REG (Pmode, 16);
+
+  /* Add DELTA.  When possible we use ldah+lda.  Otherwise load the
+     entire constant for the add.  */
+  lo = ((delta & 0xffff) ^ 0x8000) - 0x8000;
+  hi = (((delta - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+  if (hi + lo == delta)
+    {
+      if (hi)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (hi)));
+      if (lo)
+       emit_insn (gen_adddi3 (this, this, GEN_INT (lo)));
+    }
+  else
+    {
+      rtx tmp = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 0),
+                                          delta, -(delta < 0));
+      emit_insn (gen_adddi3 (this, this, tmp));
+    }
+
+  /* Add a delta stored in the vtable at VCALL_OFFSET.  */
+  if (vcall_offset)
+    {
+      rtx tmp, tmp2;
+
+      tmp = gen_rtx_REG (Pmode, 0);
+      emit_move_insn (tmp, gen_rtx_MEM (Pmode, this));
+
+      lo = ((vcall_offset & 0xffff) ^ 0x8000) - 0x8000;
+      hi = (((vcall_offset - lo) & 0xffffffff) ^ 0x80000000) - 0x80000000;
+      if (hi + lo == vcall_offset)
+       {
+         if (hi)
+           emit_insn (gen_adddi3 (tmp, tmp, GEN_INT (hi)));
+       }
+      else
+       {
+         tmp2 = alpha_emit_set_long_const (gen_rtx_REG (Pmode, 1),
+                                           vcall_offset, -(vcall_offset < 0));
+          emit_insn (gen_adddi3 (tmp, tmp, tmp2));
+         lo = 0;
+       }
+      if (lo)
+       tmp2 = gen_rtx_PLUS (Pmode, tmp, GEN_INT (lo));
+      else
+       tmp2 = tmp;
+      emit_move_insn (tmp, gen_rtx_MEM (Pmode, tmp2));
+
+      emit_insn (gen_adddi3 (this, this, tmp));
+    }
+
+  /* Generate a tail call to the target function.  */
+  if (! TREE_USED (function))
+    {
+      assemble_external (function);
+      TREE_USED (function) = 1;
+    }
+  funexp = XEXP (DECL_RTL (function), 0);
+  funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
+  insn = emit_call_insn (gen_sibcall (funexp, const0_rtx));
+  SIBLING_CALL_P (insn) = 1;
+
+  /* Run just enough of rest_of_compilation to get the insns emitted.
+     There's not really enough bulk here to make other passes such as
+     instruction scheduling worth while.  Note that use_thunk calls
+     assemble_start_function and assemble_end_function.  */
+  insn = get_insns ();
+  shorten_branches (insn);
+  final_start_function (insn, file, 1);
+  final (insn, file, 1, 0);
+  final_end_function ();
+}
+#endif /* TARGET_ABI_OSF */
 \f
 /* Debugging support.  */
 
@@ -6841,7 +8261,7 @@ struct shadow_summary
 };
 
 static void summarize_insn PARAMS ((rtx, struct shadow_summary *, int));
-static void alpha_handle_trap_shadows PARAMS ((rtx));
+static void alpha_handle_trap_shadows PARAMS ((void));
 
 /* Summary the effects of expression X on the machine.  Update SUM, a pointer
    to the summary structure.  SET is nonzero if the insn is setting the
@@ -7005,8 +8425,7 @@ summarize_insn (x, sum, set)
    (d) The trap shadow may not include any branch instructions.  */
 
 static void
-alpha_handle_trap_shadows (insns)
-     rtx insns;
+alpha_handle_trap_shadows ()
 {
   struct shadow_summary shadow;
   int trap_pending, exception_nesting;
@@ -7019,7 +8438,7 @@ alpha_handle_trap_shadows (insns)
   shadow.used.mem = 0;
   shadow.defd = shadow.used;
   
-  for (i = insns; i ; i = NEXT_INSN (i))
+  for (i = get_insns (); i ; i = NEXT_INSN (i))
     {
       if (GET_CODE (i) == NOTE)
        {
@@ -7167,7 +8586,7 @@ static rtx alphaev4_next_nop PARAMS ((int *));
 static rtx alphaev5_next_nop PARAMS ((int *));
 
 static void alpha_align_insns
-  PARAMS ((rtx, unsigned int, rtx (*)(rtx, int *, int *), rtx (*)(int *)));
+  PARAMS ((unsigned int, rtx (*)(rtx, int *, int *), rtx (*)(int *)));
 
 static enum alphaev4_pipe
 alphaev4_insn_pipe (insn)
@@ -7199,6 +8618,7 @@ alphaev4_insn_pipe (insn)
     case TYPE_MISC:
     case TYPE_IBR:
     case TYPE_JSR:
+    case TYPE_CALLPAL:
     case TYPE_FCPYS:
     case TYPE_FCMOV:
     case TYPE_FADD:
@@ -7241,6 +8661,7 @@ alphaev5_insn_pipe (insn)
 
     case TYPE_IBR:
     case TYPE_JSR:
+    case TYPE_CALLPAL:
       return EV5_E1;
 
     case TYPE_FCPYS:
@@ -7554,8 +8975,7 @@ alphaev5_next_nop (pin_use)
 /* The instruction group alignment main loop.  */
 
 static void
-alpha_align_insns (insns, max_align, next_group, next_nop)
-     rtx insns;
+alpha_align_insns (max_align, next_group, next_nop)
      unsigned int max_align;
      rtx (*next_group) PARAMS ((rtx, int *, int *));
      rtx (*next_nop) PARAMS ((int *));
@@ -7568,17 +8988,17 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
   rtx i, next;
 
   /* Let shorten branches care for assigning alignments to code labels.  */
-  shorten_branches (insns);
+  shorten_branches (get_insns ());
 
   if (align_functions < 4)
     align = 4;
-  else if (align_functions < max_align)
+  else if ((unsigned int) align_functions < max_align)
     align = align_functions;
   else
     align = max_align;
 
   ofs = prev_in_use = 0;
-  i = insns;
+  i = get_insns ();
   if (GET_CODE (i) == NOTE)
     i = next_nonnote_insn (i);
 
@@ -7622,15 +9042,20 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
       else if ((int) align < len)
        {
          unsigned int new_log_align = len > 8 ? 4 : 3;
-         rtx where;
+         rtx prev, where;
 
-         where = prev_nonnote_insn (i);
+         where = prev = prev_nonnote_insn (i);
          if (!where || GET_CODE (where) != CODE_LABEL)
            where = i;
 
-         emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
-         align = 1 << new_log_align;
-         ofs = 0;
+         /* Can't realign between a call and its gp reload.  */
+         if (! (TARGET_EXPLICIT_RELOCS
+                && prev && GET_CODE (prev) == CALL_INSN))
+           {
+             emit_insn_before (gen_realign (GEN_INT (new_log_align)), where);
+             align = 1 << new_log_align;
+             ofs = 0;
+           }
        }
 
       /* If the group won't fit in the same INT16 as the previous,
@@ -7644,8 +9069,8 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
          int nop_count = (align - ofs) / 4;
          rtx where;
 
-         /* Insert nops before labels and branches to truely merge the
-            execution of the nops with the previous instruction group.  */
+         /* Insert nops before labels, branches, and calls to truely merge
+            the execution of the nops with the previous instruction group.  */
          where = prev_nonnote_insn (i);
          if (where)
            {
@@ -7655,7 +9080,7 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
                  if (where2 && GET_CODE (where2) == JUMP_INSN)
                    where = where2;
                }
-             else if (GET_CODE (where) != JUMP_INSN)
+             else if (GET_CODE (where) == INSN)
                where = i;
            }
          else
@@ -7675,12 +9100,11 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
 \f
 /* Machine dependent reorg pass.  */
 
-void
-alpha_reorg (insns)
-     rtx insns;
+static void
+alpha_reorg ()
 {
   if (alpha_tp != ALPHA_TP_PROG || flag_exceptions)
-    alpha_handle_trap_shadows (insns);
+    alpha_handle_trap_shadows ();
 
   /* Due to the number of extra trapb insns, don't bother fixing up
      alignment when trap precision is instruction.  Moreover, we can
@@ -7690,89 +9114,60 @@ alpha_reorg (insns)
       && flag_schedule_insns_after_reload)
     {
       if (alpha_cpu == PROCESSOR_EV4)
-       alpha_align_insns (insns, 8, alphaev4_next_group, alphaev4_next_nop);
+       alpha_align_insns (8, alphaev4_next_group, alphaev4_next_nop);
       else if (alpha_cpu == PROCESSOR_EV5)
-       alpha_align_insns (insns, 16, alphaev5_next_group, alphaev5_next_nop);
+       alpha_align_insns (16, alphaev5_next_group, alphaev5_next_nop);
     }
 }
 \f
-/* Check a floating-point value for validity for a particular machine mode.  */
-
-static const char * const float_strings[] =
-{
-  /* These are for FLOAT_VAX.  */
-   "1.70141173319264430e+38", /* 2^127 (2^24 - 1) / 2^24 */
-  "-1.70141173319264430e+38",
-   "2.93873587705571877e-39", /* 2^-128 */
-  "-2.93873587705571877e-39",
-  /* These are for the default broken IEEE mode, which traps
-     on infinity or denormal numbers.  */
-   "3.402823466385288598117e+38", /* 2^128 (1 - 2^-24) */
-  "-3.402823466385288598117e+38",
-   "1.1754943508222875079687e-38", /* 2^-126 */
-  "-1.1754943508222875079687e-38",
-};
+#ifdef OBJECT_FORMAT_ELF
 
-static REAL_VALUE_TYPE float_values[8];
-static int inited_float_values = 0;
+/* Switch to the section to which we should output X.  The only thing
+   special we do here is to honor small data.  */
 
-int
-check_float_value (mode, d, overflow)
+static void
+alpha_elf_select_rtx_section (mode, x, align)
      enum machine_mode mode;
-     REAL_VALUE_TYPE *d;
-     int overflow ATTRIBUTE_UNUSED;
+     rtx x;
+     unsigned HOST_WIDE_INT align;
 {
+  if (TARGET_SMALL_DATA && GET_MODE_SIZE (mode) <= g_switch_value)
+    /* ??? Consider using mergable sdata sections.  */
+    sdata_section ();
+  else
+    default_elf_select_rtx_section (mode, x, align);
+}
 
-  if (TARGET_IEEE || TARGET_IEEE_CONFORMANT || TARGET_IEEE_WITH_INEXACT)
-    return 0;
+#endif /* OBJECT_FORMAT_ELF */
+\f
+/* Structure to collect function names for final output in link section.  */
+/* Note that items marked with GTY can't be ifdef'ed out.  */
 
-  if (inited_float_values == 0)
-    {
-      int i;
-      for (i = 0; i < 8; i++)
-       float_values[i] = REAL_VALUE_ATOF (float_strings[i], DFmode);
+enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
+enum reloc_kind {KIND_LINKAGE, KIND_CODEADDR};
 
-      inited_float_values = 1;
-    }
+struct alpha_links GTY(())
+{
+  int num;
+  rtx linkage;
+  enum links_kind lkind;
+  enum reloc_kind rkind;
+};
 
-  if (mode == SFmode)
-    {
-      REAL_VALUE_TYPE r;
-      REAL_VALUE_TYPE *fvptr;
+struct alpha_funcs GTY(())
+{
+  int num;
+  splay_tree GTY ((param1_is (char *), param2_is (struct alpha_links *)))
+    links;
+};
 
-      if (TARGET_FLOAT_VAX)
-       fvptr = &float_values[0];
-      else
-       fvptr = &float_values[4];
+static GTY ((param1_is (char *), param2_is (struct alpha_links *)))
+  splay_tree alpha_links_tree;
+static GTY ((param1_is (tree), param2_is (struct alpha_funcs *)))
+  splay_tree alpha_funcs_tree;
 
-      memcpy (&r, d, sizeof (REAL_VALUE_TYPE));
-      if (REAL_VALUES_LESS (fvptr[0], r))
-       {
-         memcpy (d, &fvptr[0], sizeof (REAL_VALUE_TYPE));
-         return 1;
-       }
-      else if (REAL_VALUES_LESS (r, fvptr[1]))
-       {
-         memcpy (d, &fvptr[1], sizeof (REAL_VALUE_TYPE));
-         return 1;
-       }
-      else if (REAL_VALUES_LESS (dconst0, r)
-               && REAL_VALUES_LESS (r, fvptr[2]))
-       {
-         memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
-         return 1;
-       }
-      else if (REAL_VALUES_LESS (r, dconst0)
-               && REAL_VALUES_LESS (fvptr[3], r))
-       {
-         memcpy (d, &dconst0, sizeof (REAL_VALUE_TYPE));
-         return 1;
-       }
-    }
+static GTY(()) int alpha_funcs_num;
 
-  return 0;
-}
-\f
 #if TARGET_ABI_OPEN_VMS
 
 /* Return the VMS argument type corresponding to MODE.  */
@@ -7808,45 +9203,6 @@ alpha_arg_info_reg_val (cum)
   return GEN_INT (regval);
 }
 \f
-#include <splay-tree.h>
-
-/* Structure to collect function names for final output
-   in link section.  */
-
-enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
-
-struct alpha_links
-{
-  rtx linkage;
-  enum links_kind kind;
-};
-
-static splay_tree alpha_links;
-
-static int mark_alpha_links_node       PARAMS ((splay_tree_node, void *));
-static void mark_alpha_links           PARAMS ((void *));
-static int alpha_write_one_linkage     PARAMS ((splay_tree_node, void *));
-
-/* Protect alpha_links from garbage collection.  */
-
-static int
-mark_alpha_links_node (node, data)
-     splay_tree_node node;
-     void *data ATTRIBUTE_UNUSED;
-{
-  struct alpha_links *links = (struct alpha_links *) node->value;
-  ggc_mark_rtx (links->linkage);
-  return 0;
-}
-
-static void
-mark_alpha_links (ptr)
-     void *ptr;
-{
-  splay_tree tree = *(splay_tree *) ptr;
-  splay_tree_foreach (tree, mark_alpha_links_node, NULL);
-}
-
 /* Make (or fake) .linkage entry for function call.
 
    IS_LOCAL is 0 if name is used in call, 1 if name is used in definition.
@@ -7864,42 +9220,55 @@ alpha_need_linkage (name, is_local)
   if (name[0] == '*')
     name++;
 
-  if (alpha_links)
+  if (is_local)
+    {
+      struct alpha_funcs *cfaf;
+
+      if (!alpha_funcs_tree)
+        alpha_funcs_tree = splay_tree_new_ggc ((splay_tree_compare_fn)
+                                              splay_tree_compare_pointers);
+    
+      cfaf = (struct alpha_funcs *) ggc_alloc (sizeof (struct alpha_funcs));
+
+      cfaf->links = 0;
+      cfaf->num = ++alpha_funcs_num;
+
+      splay_tree_insert (alpha_funcs_tree,
+                        (splay_tree_key) current_function_decl,
+                        (splay_tree_value) cfaf);
+    }
+
+  if (alpha_links_tree)
     {
       /* Is this name already defined?  */
 
-      node = splay_tree_lookup (alpha_links, (splay_tree_key) name);
+      node = splay_tree_lookup (alpha_links_tree, (splay_tree_key) name);
       if (node)
        {
          al = (struct alpha_links *) node->value;
          if (is_local)
            {
              /* Defined here but external assumed.  */
-             if (al->kind == KIND_EXTERN)
-               al->kind = KIND_LOCAL;
+             if (al->lkind == KIND_EXTERN)
+               al->lkind = KIND_LOCAL;
            }
          else
            {
              /* Used here but unused assumed.  */
-             if (al->kind == KIND_UNUSED)
-               al->kind = KIND_LOCAL;
+             if (al->lkind == KIND_UNUSED)
+               al->lkind = KIND_LOCAL;
            }
          return al->linkage;
        }
     }
   else
-    {
-      alpha_links = splay_tree_new ((splay_tree_compare_fn) strcmp, 
-                                   (splay_tree_delete_key_fn) free,
-                                   (splay_tree_delete_key_fn) free);
-      ggc_add_root (&alpha_links, 1, 1, mark_alpha_links);
-    }
+    alpha_links_tree = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp);
 
-  al = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
-  name = xstrdup (name);
+  al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links));
+  name = ggc_strdup (name);
 
   /* Assume external if no definition.  */
-  al->kind = (is_local ? KIND_UNUSED : KIND_EXTERN);
+  al->lkind = (is_local ? KIND_UNUSED : KIND_EXTERN);
 
   /* Ensure we have an IDENTIFIER so assemble_name can mark it used.  */
   get_identifier (name);
@@ -7915,54 +9284,168 @@ alpha_need_linkage (name, is_local)
                                      ggc_alloc_string (linksym, name_len + 5));
   }
 
-  splay_tree_insert (alpha_links, (splay_tree_key) name,
+  splay_tree_insert (alpha_links_tree, (splay_tree_key) name,
                     (splay_tree_value) al);
 
   return al->linkage;
 }
 
+rtx
+alpha_use_linkage (linkage, cfundecl, lflag, rflag)
+     rtx linkage;
+     tree cfundecl;
+     int lflag;
+     int rflag;
+{
+  splay_tree_node cfunnode;
+  struct alpha_funcs *cfaf;
+  struct alpha_links *al;
+  const char *name = XSTR (linkage, 0);
+
+  cfaf = (struct alpha_funcs *) 0;
+  al = (struct alpha_links *) 0;
+
+  cfunnode = splay_tree_lookup (alpha_funcs_tree, (splay_tree_key) cfundecl);
+  cfaf = (struct alpha_funcs *) cfunnode->value;
+
+  if (cfaf->links)
+    {
+      splay_tree_node lnode;
+
+      /* Is this name already defined?  */
+
+      lnode = splay_tree_lookup (cfaf->links, (splay_tree_key) name);
+      if (lnode)
+       al = (struct alpha_links *) lnode->value;
+    }
+  else
+    cfaf->links = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp);
+
+  if (!al)
+    {
+      size_t name_len;
+      size_t buflen;
+      char buf [512];
+      char *linksym;
+      splay_tree_node node = 0;
+      struct alpha_links *anl;
+
+      if (name[0] == '*')
+       name++;
+
+      name_len = strlen (name);
+
+      al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links));
+      al->num = cfaf->num;
+
+      node = splay_tree_lookup (alpha_links_tree, (splay_tree_key) name);
+      if (node)
+       {
+         anl = (struct alpha_links *) node->value;
+         al->lkind = anl->lkind;
+       }
+
+      sprintf (buf, "$%d..%s..lk", cfaf->num, name);
+      buflen = strlen (buf);
+      linksym = alloca (buflen + 1);
+      memcpy (linksym, buf, buflen + 1);
+
+      al->linkage = gen_rtx_SYMBOL_REF
+       (Pmode, ggc_alloc_string (linksym, buflen + 1));
+
+      splay_tree_insert (cfaf->links, (splay_tree_key) name,
+                        (splay_tree_value) al);
+    }
+
+  if (rflag)
+    al->rkind = KIND_CODEADDR;
+  else
+    al->rkind = KIND_LINKAGE;
+      
+  if (lflag)
+    return gen_rtx_MEM (Pmode, plus_constant (al->linkage, 8));
+  else
+    return al->linkage;
+}
+
 static int
 alpha_write_one_linkage (node, data)
      splay_tree_node node;
      void *data;
 {
   const char *const name = (const char *) node->key;
-  struct alpha_links *links = (struct alpha_links *) node->value;
+  struct alpha_links *link = (struct alpha_links *) node->value;
   FILE *stream = (FILE *) data;
 
-  if (links->kind == KIND_UNUSED
-      || ! TREE_SYMBOL_REFERENCED (get_identifier (name)))
-    return 0;
-
-  fprintf (stream, "$%s..lk:\n", name);
-  if (links->kind == KIND_LOCAL)
+  fprintf (stream, "$%d..%s..lk:\n", link->num, name);
+  if (link->rkind == KIND_CODEADDR)
     {
-      /* Local and used, build linkage pair.  */
-      fprintf (stream, "\t.quad %s..en\n", name);
-      fprintf (stream, "\t.quad %s\n", name);
+      if (link->lkind == KIND_LOCAL)
+       {
+         /* Local and used */
+         fprintf (stream, "\t.quad %s..en\n", name);
+       }
+      else
+       {
+         /* External and used, request code address.  */
+         fprintf (stream, "\t.code_address %s\n", name);
+       }
     }
   else
     {
-      /* External and used, request linkage pair.  */
-      fprintf (stream, "\t.linkage %s\n", name);
+      if (link->lkind == KIND_LOCAL)
+       {
+         /* Local and used, build linkage pair.  */
+         fprintf (stream, "\t.quad %s..en\n", name);
+         fprintf (stream, "\t.quad %s\n", name);
+       }
+      else
+       {
+         /* External and used, request linkage pair.  */
+         fprintf (stream, "\t.linkage %s\n", name);
+       }
     }
 
   return 0;
 }
 
-void
-alpha_write_linkage (stream)
-    FILE *stream;
+static void
+alpha_write_linkage (stream, funname, fundecl)
+     FILE *stream;
+     const char *funname;
+     tree fundecl;
 {
-  readonly_section ();
+  splay_tree_node node;
+  struct alpha_funcs *func;
+
+  link_section ();
   fprintf (stream, "\t.align 3\n");
-  splay_tree_foreach (alpha_links, alpha_write_one_linkage, stream);
+  node = splay_tree_lookup (alpha_funcs_tree, (splay_tree_key) fundecl);
+  func = (struct alpha_funcs *) node->value;
+
+  fputs ("\t.name ", stream);
+  assemble_name (stream, funname);
+  fputs ("..na\n", stream);
+  ASM_OUTPUT_LABEL (stream, funname);
+  fprintf (stream, "\t.pdesc ");
+  assemble_name (stream, funname);
+  fprintf (stream, "..en,%s\n",
+          alpha_procedure_type == PT_STACK ? "stack"
+          : alpha_procedure_type == PT_REGISTER ? "reg" : "null");
+
+  if (func->links)
+    {
+      splay_tree_foreach (func->links, alpha_write_one_linkage, stream);
+      /* splay_tree_delete (func->links); */
+    }
 }
 
 /* Given a decl, a section name, and whether the decl initializer
    has relocs, choose attributes for the section.  */
 
 #define SECTION_VMS_OVERLAY    SECTION_FORGET
+#define SECTION_VMS_GLOBAL SECTION_MACH_DEP
+#define SECTION_VMS_INITIALIZE (SECTION_VMS_GLOBAL << 1)
 
 static unsigned int
 vms_section_type_flags (decl, name, reloc)
@@ -7975,6 +9458,12 @@ vms_section_type_flags (decl, name, reloc)
   if (decl && DECL_ATTRIBUTES (decl)
       && lookup_attribute ("overlaid", DECL_ATTRIBUTES (decl)))
     flags |= SECTION_VMS_OVERLAY;
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("global", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_GLOBAL;
+  if (decl && DECL_ATTRIBUTES (decl)
+      && lookup_attribute ("initialize", DECL_ATTRIBUTES (decl)))
+    flags |= SECTION_VMS_INITIALIZE;
 
   return flags;
 }
@@ -7988,14 +9477,19 @@ vms_asm_named_section (name, flags)
      const char *name;
      unsigned int flags;
 {
-  const char *flag_str = "";
+  fputc ('\n', asm_out_file);
+  fprintf (asm_out_file, ".section\t%s", name);
 
   if (flags & SECTION_VMS_OVERLAY)
-    flag_str = ",OVR";
-  else if (flags & SECTION_DEBUG)
-    flag_str = ",NOWRT";
+    fprintf (asm_out_file, ",OVR");
+  if (flags & SECTION_VMS_GLOBAL)
+    fprintf (asm_out_file, ",GBL");
+  if (flags & SECTION_VMS_INITIALIZE)
+    fprintf (asm_out_file, ",NOMOD");
+  if (flags & SECTION_DEBUG)
+    fprintf (asm_out_file, ",NOWRT");
 
-  fprintf (asm_out_file, ".section\t%s%s\n", name, flag_str);
+  fputc ('\n', asm_out_file);
 }
 
 /* Record an element in the table of global constructors.  SYMBOL is
@@ -8035,6 +9529,16 @@ alpha_need_linkage (name, is_local)
   return NULL_RTX;
 }
 
+rtx
+alpha_use_linkage (linkage, cfundecl, lflag, rflag)
+     rtx linkage ATTRIBUTE_UNUSED;
+     tree cfundecl ATTRIBUTE_UNUSED;
+     int lflag ATTRIBUTE_UNUSED;
+     int rflag ATTRIBUTE_UNUSED;
+{
+  return NULL_RTX;
+}
+
 #endif /* TARGET_ABI_OPEN_VMS */
 \f
 #if TARGET_ABI_UNICOSMK
@@ -8098,9 +9602,8 @@ unicosmk_output_module_name (file)
      prefix the module name with a '$' if necessary.  */
 
   if (!ISALPHA (*name))
-    fprintf (file, "$%s", name);
-  else
-    fputs (name, file);
+    putc ('$', file);
+  output_clean_symbol_name (file, name);
 }
 
 /* Output text that to appear at the beginning of an assembler file.  */
@@ -8239,7 +9742,7 @@ unicosmk_section_type_flags (decl, name, reloc)
 /* Generate a section name for decl and associate it with the
    declaration.  */
 
-void
+static void
 unicosmk_unique_section (decl, reloc)
       tree decl;
       int reloc ATTRIBUTE_UNUSED;
@@ -8251,7 +9754,7 @@ unicosmk_unique_section (decl, reloc)
     abort ();
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  STRIP_NAME_ENCODING (name, name);
+  name = default_strip_name_encoding (name);
   len = strlen (name);
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -8319,7 +9822,7 @@ unicosmk_insert_attributes (decl, attr_ptr)
 {
   if (DECL_P (decl)
       && (TREE_PUBLIC (decl) || TREE_CODE (decl) == FUNCTION_DECL))
-    UNIQUE_SECTION (decl, 0);
+    unicosmk_unique_section (decl, 0);
 }
 
 /* Output an alignment directive. We have to use the macro 'gcc@code@align'
@@ -8364,7 +9867,7 @@ unicosmk_output_addr_vec (file, vec)
   int vlen = XVECLEN (body, 0);
   int idx;
 
-  ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (lab));
+  (*targetm.asm_out.internal_label) (file, "L", CODE_LABEL_NUMBER (lab));
 
   for (idx = 0; idx < vlen; idx++)
     {
@@ -8398,7 +9901,7 @@ static void
 unicosmk_gen_dsib (imaskP)
       unsigned long * imaskP;
 {
-  if (alpha_is_stack_procedure)
+  if (alpha_procedure_type == PT_STACK)
     {
       const char *ssib_name;
       rtx mem;
@@ -8414,14 +9917,14 @@ unicosmk_gen_dsib (imaskP)
       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);
+      (*imaskP) &= ~(1UL << 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);
+      (*imaskP) &= ~(1UL << HARD_FRAME_POINTER_REGNUM);
 
       emit_insn (gen_blockage ());
 
@@ -8482,8 +9985,7 @@ unicosmk_ssib_name ()
   x = XEXP (x, 0);
   if (GET_CODE (x) != SYMBOL_REF)
     abort ();
-  fnname = XSTR (x, 0);
-  STRIP_NAME_ENCODING (fnname, fnname);
+  fnname = default_name_encoding (XSTR (x, 0));
 
   len = strlen (fnname);
   if (len + SSIB_PREFIX_LEN > 255)
@@ -8549,14 +10051,12 @@ unicosmk_output_ssib (file, fnname)
   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,
+      fprintf (file, "\t.quad\t" HOST_WIDE_INT_PRINT_DOUBLE_HEX "\n",
               CONST_DOUBLE_HIGH (ciw), CONST_DOUBLE_LOW (ciw));
 #else
-      fprintf (file, HOST_WIDE_INT_PRINT_HEX, INTVAL (ciw));
+      fprintf (file, "\t.quad\t" HOST_WIDE_INT_PRINT_HEX "\n", INTVAL (ciw));
 #endif
-      fprintf (file, "\n");
     }
 }
 
@@ -8613,6 +10113,7 @@ unicosmk_data_section ()
 
 /* List of identifiers for which an extern declaration might have to be
    emitted.  */
+/* FIXME: needs to use GC, so it can be saved and restored for PCH.  */
 
 struct unicosmk_extern_list
 {
@@ -8658,7 +10159,7 @@ unicosmk_output_externs (file)
       /* 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);
+      real_name = default_strip_name_encoding (p->name);
       if (len && p->name[0] == '*'
          && !memcmp (real_name, user_label_prefix, len))
        real_name += len;
@@ -8683,7 +10184,7 @@ unicosmk_add_extern (name)
   struct unicosmk_extern_list *p;
 
   p = (struct unicosmk_extern_list *)
-       permalloc (sizeof (struct unicosmk_extern_list));
+       xmalloc (sizeof (struct unicosmk_extern_list));
   p->next = unicosmk_extern_head;
   p->name = name;
   unicosmk_extern_head = p;
@@ -8695,6 +10196,7 @@ unicosmk_add_extern (name)
 
 /* Structure to collect identifiers which have been replaced by DEX
    expressions.  */
+/* FIXME: needs to use GC, so it can be saved and restored for PCH.  */
 
 struct unicosmk_dex {
   struct unicosmk_dex *next;
@@ -8765,7 +10267,7 @@ unicosmk_need_dex (x)
       --i;
     }
       
-  dex = (struct unicosmk_dex *) permalloc (sizeof (struct unicosmk_dex));
+  dex = (struct unicosmk_dex *) xmalloc (sizeof (struct unicosmk_dex));
   dex->name = name;
   dex->next = unicosmk_dex_list;
   unicosmk_dex_list = dex;
@@ -8833,3 +10335,6 @@ unicosmk_need_dex (x)
 }
 
 #endif /* TARGET_ABI_UNICOSMK */
+
+#include "gt-alpha.h"
+
This page took 0.148467 seconds and 5 git commands to generate.