]> 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 18573741227aa0dd7bd7ec96260cf7f2c785cd45..76f399e3c6e15119f1d5eb7ef5893763b50ec392 100644 (file)
@@ -106,20 +106,71 @@ 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 alpha_function_ok_for_sibcall
   PARAMS ((tree, tree));
@@ -127,20 +178,20 @@ 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_in_text_section
-  PARAMS ((tree));
 static bool decl_has_samegp
   PARAMS ((tree));
 static bool alpha_in_small_data_p
   PARAMS ((tree));
-static void alpha_encode_section_info
-  PARAMS ((tree, int));
-static const char *alpha_strip_name_encoding
-  PARAMS ((const char *));
+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
@@ -155,7 +206,7 @@ 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));
@@ -189,6 +240,8 @@ static int alpha_use_dfa_pipeline_interface
   PARAMS ((void));
 static int alpha_multipass_dfa_lookahead
   PARAMS ((void));
+static void alpha_reorg
+  PARAMS ((void));
 
 #ifdef OBJECT_FORMAT_ELF
 static void alpha_elf_select_rtx_section
@@ -198,6 +251,8 @@ static void alpha_elf_select_rtx_section
 #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
@@ -240,10 +295,6 @@ static void vms_asm_out_destructor PARAMS ((rtx, int));
 
 #undef TARGET_IN_SMALL_DATA_P
 #define TARGET_IN_SMALL_DATA_P alpha_in_small_data_p
-#undef TARGET_ENCODE_SECTION_INFO
-#define TARGET_ENCODE_SECTION_INFO alpha_encode_section_info
-#undef TARGET_STRIP_NAME_ENCODING
-#define TARGET_STRIP_NAME_ENCODING alpha_strip_name_encoding
 
 #if TARGET_ABI_UNICOSMK
 static void unicosmk_asm_named_section PARAMS ((const char *, unsigned int));
@@ -306,6 +357,8 @@ static void unicosmk_unique_section PARAMS ((tree, int));
 
 #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
@@ -314,6 +367,14 @@ static void unicosmk_unique_section PARAMS ((tree, int));
 #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
 /* Parse target option strings.  */
@@ -979,15 +1040,27 @@ samegp_function_operand (op, mode)
      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, encode_section_info recorded whether we are to treat
-     this symbol as having the same GP.  */
-  return SYMBOL_REF_FLAG (op);
+  /* Functions that are not local can be overridden, and thus may
+     not share the same gp.  */
+  if (! SYMBOL_REF_LOCAL_P (op))
+    return false;
+
+  /* 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.  */
@@ -997,9 +1070,11 @@ direct_call_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
+  tree op_decl, cfun_sec, op_sec;
+
   /* Must share the same GP.  */
   if (!samegp_function_operand (op, mode))
-    return 0;
+    return false;
 
   /* If profiling is implemented via linker tricks, we can't jump
      to the nogp alternate entry point.  Note that current_function_profile
@@ -1009,16 +1084,36 @@ direct_call_operand (op, mode)
      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 false;
 
+  /* Must be a function.  In some cases folks create thunks in static
+     data structures and then make calls to them.  If we allow the
+     direct call, we'll get an error from the linker about !samegp reloc
+     against a symbol without a .prologue directive.  */
+  if (!SYMBOL_REF_FUNCTION_P (op))
+    return false;
+  
   /* Must be "near" so that the branch is assumed to reach.  With
-     -msmall-text, this is true of all local symbols.  */
+     -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 op->jump;
+    return true;
+
+  /* Otherwise, a decl is "near" if it is defined in the same section.  */
+  if (flag_function_sections)
+    return false;
+
+  op_decl = SYMBOL_REF_DECL (op);
+  if (DECL_ONE_ONLY (current_function_decl)
+      || (op_decl && DECL_ONE_ONLY (op_decl)))
+    return false;
 
-  /* Otherwise, a decl is "near" if it is defined in the same section.
-     See alpha_encode_section_info for commentary.  */
-  return op->jump && decl_in_text_section (cfun->decl);
+  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
@@ -1029,8 +1124,6 @@ local_symbolic_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  const char *str;
-
   if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
     return 0;
 
@@ -1045,26 +1138,7 @@ local_symbolic_operand (op, mode)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
-  /* Easy pickings.  */
-  if (CONSTANT_POOL_ADDRESS_P (op) || STRING_POOL_ADDRESS_P (op))
-    return 1;
-
-  /* ??? 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.  */
-
-  str = XSTR (op, 0);
-
-  /* If @[LS], then alpha_encode_section_info sez it's local.  */
-  if (str[0] == '@' && (str[1] == 'L' || str[1] == 'S'))
-    return 1;
-
-  /* If *$, then ASM_GENERATE_INTERNAL_LABEL sez it's local.  */
-  if (str[0] == '*' && str[1] == '$')
-    return 1;
-
-  return 0;
+  return SYMBOL_REF_LOCAL_P (op) && !SYMBOL_REF_TLS_MODEL (op);
 }
 
 /* Return true if OP is a SYMBOL_REF or CONST referencing a variable
@@ -1075,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;
 
@@ -1091,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
@@ -1108,8 +1181,6 @@ global_symbolic_operand (op, mode)
      rtx op;
      enum machine_mode mode;
 {
-  const char *str;
-
   if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
     return 0;
 
@@ -1121,12 +1192,7 @@ global_symbolic_operand (op, mode)
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
 
-  if (local_symbolic_operand (op, mode))
-    return 0;
-
-  /* Also verify that it's not a TLS symbol.  */
-  str = XSTR (op, 0);
-  return str[0] != '%' && str[0] != '@';
+  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.  */
@@ -1187,8 +1253,6 @@ tls_symbolic_operand_1 (op, mode, size, unspec)
      enum machine_mode mode;
      int size, unspec;
 {
-  const char *str;
-
   if (mode != VOIDmode && GET_MODE (op) != VOIDmode && mode != GET_MODE (op))
     return 0;
 
@@ -1202,29 +1266,26 @@ tls_symbolic_operand_1 (op, mode, size, unspec)
 
   if (GET_CODE (op) != SYMBOL_REF)
     return 0;
-  str = XSTR (op, 0);
 
-  if (str[0] == '%')
+  if (SYMBOL_REF_LOCAL_P (op))
     {
-      if (size != 64)
+      if (alpha_tls_size > size)
        return 0;
     }
-  else if (str[0] == '@')
+  else
     {
-      if (alpha_tls_size > size)
+      if (size != 64)
        return 0;
     }
-  else
-    return 0;
 
-  switch (str[1])
+  switch (SYMBOL_REF_TLS_MODEL (op))
     {
-    case 'D':
+    case TLS_MODEL_LOCAL_DYNAMIC:
       return unspec == UNSPEC_DTPREL;
-    case 'T':
+    case TLS_MODEL_INITIAL_EXEC:
       return unspec == UNSPEC_TPREL && size == 64;
-    case 't':
-      return unspec == UNSPEC_TPREL && size < 64;
+    case TLS_MODEL_LOCAL_EXEC:
+      return unspec == UNSPEC_TPREL;
     default:
       abort ();
     }
@@ -1769,59 +1830,19 @@ static enum tls_model
 tls_symbolic_operand_type (symbol)
      rtx symbol;
 {
-  const char *str;
+  enum tls_model model;
 
   if (GET_CODE (symbol) != SYMBOL_REF)
     return 0;
-  str = XSTR (symbol, 0);
+  model = SYMBOL_REF_TLS_MODEL (symbol);
 
-  if (str[0] == '%')
-    {
-      /* ??? Be prepared for -ftls-model=local-dynamic.  Perhaps we shouldn't
-        have separately encoded local-ness.  On well, maybe the user will use
-        attribute visibility next time.  At least we don't crash...  */
-      if (str[1] == 'G' || str[1] == 'D')
-       return TLS_MODEL_GLOBAL_DYNAMIC;
-      if (str[1] == 'T')
-       return TLS_MODEL_INITIAL_EXEC;
-    }
-  else if (str[0] == '@')
-    {
-      if (str[1] == 'D')
-       {
-         /* Local dynamic is a waste if we're not going to combine
-            the __tls_get_addr calls.  So avoid it if not optimizing.  */
-         if (optimize)
-           return TLS_MODEL_LOCAL_DYNAMIC;
-         else
-           return TLS_MODEL_GLOBAL_DYNAMIC;
-       }
-      if (str[1] == 'T')
-       return TLS_MODEL_INITIAL_EXEC;
-      if (str[1] == 't')
-       return TLS_MODEL_LOCAL_EXEC;
-    }
+  /* Local-exec with a 64-bit size is the same code as initial-exec.  */
+  if (model == TLS_MODEL_LOCAL_EXEC && alpha_tls_size == 64)
+    model = TLS_MODEL_INITIAL_EXEC;
 
-  return 0;
+  return model;
 }
-
 \f
-/* Return true if the function DECL will be placed in the default text
-   section.  */
-/* ??? Ideally we'd be able to always move from a SYMBOL_REF back to the
-   decl, as that would allow us to determine if two functions are in the
-   same section, which is what we really want to know.  */
-
-static bool
-decl_in_text_section (decl)
-     tree decl;
-{
-  return (DECL_SECTION_NAME (decl) == NULL_TREE
-         && ! (flag_function_sections
-               || (targetm.have_named_sections
-                   && DECL_ONE_ONLY (decl))));
-}
-
 /* Return true if the function DECL will share the same GP as any
    function in the current unit of translation.  */
 
@@ -1870,149 +1891,13 @@ alpha_in_small_data_p (exp)
 
       /* 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 && size <= g_switch_value)
+      if (size > 0 && (unsigned HOST_WIDE_INT) size <= g_switch_value)
        return true;
     }
 
   return false;
 }
 
-/* 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 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.  */
-
-static void
-alpha_encode_section_info (decl, first)
-     tree decl;
-     int first ATTRIBUTE_UNUSED;
-{
-  const char *symbol_str;
-  bool is_local;
-  char encoding = 0;
-  rtx rtl, symbol;
-
-  rtl = DECL_P (decl) ? DECL_RTL (decl) : TREE_CST_RTL (decl);
-
-  /* Careful not to prod global register variables.  */
-  if (GET_CODE (rtl) != MEM)
-    return;
-  symbol = XEXP (rtl, 0);
-  if (GET_CODE (symbol) != SYMBOL_REF)
-    return;
-
-  /* A variable is considered "local" if it is defined in this module.  */
-  is_local = (*targetm.binds_local_p) (decl);
-    
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    {
-      /* Mark whether the decl is "near" in distance.  If -msmall-text is
-        in effect, this is trivially true of all local symbols.  */
-      if (TARGET_SMALL_TEXT)
-       {
-         if (is_local)
-           symbol->jump = 1;
-       }
-      else
-       {
-         /* Otherwise, a decl is "near" if it is defined in this same
-            section.  What we really need is to be able to access the
-            target decl of a call from the call_insn pattern, so that
-            we can determine if the call is from the same section.  We
-            can't do that at present, so handle the common case and
-            match up .text with .text.
-
-            Delay marking public functions until they are emitted; otherwise
-            we don't know that they exist in this unit of translation.  */
-         if (!TREE_PUBLIC (decl) && decl_in_text_section (decl))
-            symbol->jump = 1;
-       }
-
-      /* Indicate whether the target function shares the same GP as any
-        function emitted in this unit of translation.  */
-      if (decl_has_samegp (decl))
-       SYMBOL_REF_FLAG (symbol) = 1;
-      return;
-    }
-
-  /* Early out if we're not going to do anything with this data.  */
-  if (! TARGET_EXPLICIT_RELOCS)
-    return;
-
-  symbol_str = XSTR (symbol, 0);
-
-  /* Care for TLS variables.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_THREAD_LOCAL (decl))
-    {
-      switch (decl_tls_model (decl))
-       {
-       case TLS_MODEL_GLOBAL_DYNAMIC:
-         encoding = 'G';
-         break;
-       case TLS_MODEL_LOCAL_DYNAMIC:
-         encoding = 'D';
-         break;
-       case TLS_MODEL_INITIAL_EXEC:
-         encoding = 'T';
-         break;
-       case TLS_MODEL_LOCAL_EXEC:
-         encoding = (alpha_tls_size == 64 ? 'T' : 't');
-         break;
-       }
-    }
-  else if (is_local)
-    {
-      /* Determine if DECL will wind up in .sdata/.sbss.  */
-      if (alpha_in_small_data_p (decl))
-       encoding = 'S';
-      else
-       encoding = 'L';
-    }
-
-  /* Finally, encode this into the symbol string.  */
-  if (encoding)
-    {
-      char *newstr;
-      size_t len;
-      char want_prefix = (is_local ? '@' : '%');
-      char other_prefix = (is_local ? '%' : '@');
-
-      if (symbol_str[0] == want_prefix)
-       {
-         if (symbol_str[1] == encoding)
-           return;
-         symbol_str += 2;
-       }
-      else if (symbol_str[0] == other_prefix)
-       symbol_str += 2;
-
-      len = strlen (symbol_str) + 1;
-      newstr = alloca (len + 2);
-
-      newstr[0] = want_prefix;
-      newstr[1] = encoding;
-      memcpy (newstr + 2, symbol_str, len);
-         
-      XSTR (symbol, 0) = ggc_alloc_string (newstr, len + 2 - 1);
-    }
-}
-
-/* Undo the effects of the above.  */
-
-static const char *
-alpha_strip_name_encoding (str)
-     const char *str;
-{
-  if (str[0] == '@' || str[0] == '%')
-    str += 2;
-  if (str[0] == '*')
-    str++;
-  return str;
-}
-
 #if TARGET_ABI_OPEN_VMS
 static bool
 alpha_linkage_symbol_p (symname)
@@ -2144,6 +2029,18 @@ alpha_legitimate_address_p (mode, x, strict)
   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.  */
 
@@ -2211,7 +2108,7 @@ alpha_legitimize_address (x, scratch, mode)
 
          r0 = gen_rtx_REG (Pmode, 0);
          r16 = gen_rtx_REG (Pmode, 16);
-         tga = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+         tga = get_tls_get_addr ();
          dest = gen_reg_rtx (Pmode);
          seq = GEN_INT (alpha_next_sequence_number++);
          
@@ -2232,7 +2129,7 @@ alpha_legitimize_address (x, scratch, mode)
 
          r0 = gen_rtx_REG (Pmode, 0);
          r16 = gen_rtx_REG (Pmode, 16);
-         tga = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
+         tga = get_tls_get_addr ();
          scratch = gen_reg_rtx (Pmode);
          seq = GEN_INT (alpha_next_sequence_number++);
 
@@ -2411,6 +2308,49 @@ split_small_symbolic_operand_1 (px, data)
   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.  */
    
@@ -2469,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
@@ -3982,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;
@@ -5465,7 +5549,7 @@ alpha_gp_save_rtx ()
 {
   rtx r = get_hard_reg_initial_val (DImode, 29);
   if (GET_CODE (r) != MEM)
-    r = gen_mem_addressof (r, NULL_TREE);
+    r = gen_mem_addressof (r, NULL_TREE, /*rescan=*/true);
   return r;
 }
 
@@ -5610,14 +5694,11 @@ get_some_local_dynamic_name_1 (px, data)
 {
   rtx x = *px;
 
-  if (GET_CODE (x) == SYMBOL_REF)
+  if (GET_CODE (x) == SYMBOL_REF
+      && SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
     {
-      const char *str = XSTR (x, 0);
-      if (str[0] == '@' && str[1] == 'D')
-       {
-          cfun->machine->some_ld_name = str;
-          return 1;
-       }
+      cfun->machine->some_ld_name = XSTR (x, 0);
+      return 1;
     }
 
   return 0;
@@ -5665,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++;
@@ -6024,10 +6112,7 @@ print_operand_address (file, addr)
        }
 
       if (offset)
-       {
-         fputc ('+', file);
-         fprintf (file, HOST_WIDE_INT_PRINT_DEC, offset);
-       }
+       fprintf (file, "+" HOST_WIDE_INT_PRINT_DEC, offset);
       
       addr = XEXP (addr, 0);
       if (GET_CODE (addr) == REG)
@@ -6071,8 +6156,7 @@ print_operand_address (file, addr)
   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
@@ -6131,7 +6215,7 @@ alpha_initialize_trampoline (tramp, fnaddr, cxt, fnofs, cxtofs, jmpofs)
     }
 
 #ifdef TRANSFER_FROM_TRAMPOLINE
-  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
+  emit_library_call (init_one_libfunc ("__enable_execute_stack"),
                     0, VOIDmode, 1, tramp, Pmode);
 #endif
 
@@ -6300,6 +6384,53 @@ 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 (valist, nextarg)
      tree valist;
@@ -6321,12 +6452,15 @@ alpha_va_start (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 <= 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)
     {
@@ -6805,7 +6939,7 @@ alpha_sa_mask (imaskP, fmaskP)
     }
 
   if (TARGET_ABI_OPEN_VMS && alpha_procedure_type == PT_STACK)
-    imask |= (1L << HARD_FRAME_POINTER_REGNUM);
+    imask |= (1UL << HARD_FRAME_POINTER_REGNUM);
 
   /* One for every register we have to save.  */
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
@@ -6814,9 +6948,9 @@ alpha_sa_mask (imaskP, fmaskP)
        && (!TARGET_ABI_UNICOSMK || i != HARD_FRAME_POINTER_REGNUM))
       {
        if (i < 32)
-         imask |= (1L << i);
+         imask |= (1UL << i);
        else
-         fmask |= (1L << (i - 32));
+         fmask |= (1UL << (i - 32));
       }
 
   /* We need to restore these for the handler.  */
@@ -6826,14 +6960,14 @@ alpha_sa_mask (imaskP, fmaskP)
        unsigned regno = EH_RETURN_DATA_REGNO (i);
        if (regno == INVALID_REGNUM)
          break;
-       imask |= 1L << regno;
+       imask |= 1UL << regno;
       }
      
   /* If any register spilled, then spill the return address also.  */
   /* ??? This is required by the Digital stack unwind specification
      and isn't needed if we're doing Dwarf2 unwinding.  */
   if (imask || fmask || alpha_ra_ever_killed ())
-    imask |= (1L << REG_RA);
+    imask |= (1UL << REG_RA);
 
   *imaskP = imask;
   *fmaskP = fmask;
@@ -6942,6 +7076,30 @@ 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 ()
 {
@@ -6970,11 +7128,18 @@ const struct attribute_spec vms_attribute_table[] =
 #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
@@ -7003,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;
 }
@@ -7272,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);
@@ -7292,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);
@@ -7308,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));
@@ -7317,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));
@@ -7345,11 +7504,31 @@ alpha_expand_prologue ()
 
       /* 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)
     {
@@ -7393,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);
@@ -7509,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)
@@ -7535,7 +7708,7 @@ 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_procedure_type == PT_REGISTER)
@@ -7545,23 +7718,17 @@ alpha_start_function (file, fnname, decl)
     {
       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
@@ -7695,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;
@@ -7712,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);
@@ -7727,7 +7894,7 @@ alpha_expand_epilogue ()
       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));
@@ -7737,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));
@@ -7858,46 +8025,13 @@ alpha_expand_epilogue ()
     }
 }
 \f
-#if TARGET_ABI_OPEN_VMS
-#include <splay-tree.h>
-
-/* Structure to collect function names for final output
-   in link section.  */
-
-enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
-enum reloc_kind {KIND_LINKAGE, KIND_CODEADDR};
-
-struct alpha_funcs
-{
-  int num;
-  splay_tree links;
-};
-
-struct alpha_links
-{
-  int num;
-  rtx linkage;
-  enum links_kind lkind;
-  enum reloc_kind rkind;
-};
-
-static splay_tree alpha_funcs_tree;
-static splay_tree alpha_links_tree;
-
-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 *));
-
-static int alpha_funcs_num;
-#endif
-
 /* Output the rest of the textual info surrounding the epilogue.  */
 
 void
 alpha_end_function (file, fnname, decl)
      FILE *file;
      const char *fnname;
-     tree decl;
+     tree decl ATTRIBUTE_UNUSED;
 {
   /* End the function.  */
   if (!TARGET_ABI_UNICOSMK && !flag_inhibit_size_directive)
@@ -7912,23 +8046,6 @@ alpha_end_function (file, fnname, decl)
   alpha_write_linkage (file, fnname, decl);
 #endif
 
-  /* Show that we know this function if it is called again.
-     This is only meaningful for symbols that bind locally.  */
-  if ((*targetm.binds_local_p) (decl))
-    {
-      rtx symbol = XEXP (DECL_RTL (decl), 0);
-
-      /* Mark whether the decl is "near".  See the commentary in 
-        alpha_encode_section_info wrt the .text section.  */
-      if (decl_in_text_section (decl))
-       symbol->jump = 1;
-
-      /* Mark whether the decl shares a GP with other functions
-        in this unit of translation.  This is trivially true of
-        local symbols.  */
-      SYMBOL_REF_FLAG (symbol) = 1;
-    }
-
   /* Output jump tables and the static subroutine information block.  */
   if (TARGET_ABI_UNICOSMK)
     {
@@ -8144,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
@@ -8308,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;
@@ -8322,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)
        {
@@ -8470,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)
@@ -8859,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 *));
@@ -8873,7 +8988,7 @@ 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;
@@ -8883,7 +8998,7 @@ alpha_align_insns (insns, max_align, next_group, next_nop)
     align = max_align;
 
   ofs = prev_in_use = 0;
-  i = insns;
+  i = get_insns ();
   if (GET_CODE (i) == NOTE)
     i = next_nonnote_insn (i);
 
@@ -8985,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
@@ -9000,9 +9114,9 @@ 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
@@ -9026,19 +9140,33 @@ alpha_elf_select_rtx_section (mode, x, align)
 
 #endif /* OBJECT_FORMAT_ELF */
 \f
-/* Structure to collect function names for final output
-   in link section.  */
+/* Structure to collect function names for final output in link section.  */
+/* Note that items marked with GTY can't be ifdef'ed out.  */
 
 enum links_kind {KIND_UNUSED, KIND_LOCAL, KIND_EXTERN};
+enum reloc_kind {KIND_LINKAGE, KIND_CODEADDR};
 
 struct alpha_links GTY(())
 {
+  int num;
   rtx linkage;
-  enum links_kind kind;
+  enum links_kind lkind;
+  enum reloc_kind rkind;
+};
+
+struct alpha_funcs GTY(())
+{
+  int num;
+  splay_tree GTY ((param1_is (char *), param2_is (struct alpha_links *)))
+    links;
 };
 
 static GTY ((param1_is (char *), param2_is (struct alpha_links *)))
-  splay_tree alpha_links;
+  splay_tree alpha_links_tree;
+static GTY ((param1_is (tree), param2_is (struct alpha_funcs *)))
+  splay_tree alpha_funcs_tree;
+
+static GTY(()) int alpha_funcs_num;
 
 #if TARGET_ABI_OPEN_VMS
 
@@ -9088,19 +9216,19 @@ alpha_need_linkage (name, is_local)
 {
   splay_tree_node node;
   struct alpha_links *al;
-  struct alpha_funcs *cfaf;
 
   if (name[0] == '*')
     name++;
 
   if (is_local)
     {
-      alpha_funcs_tree = splay_tree_new
-       ((splay_tree_compare_fn) splay_tree_compare_pointers, 
-        (splay_tree_delete_key_fn) free,
-        (splay_tree_delete_key_fn) free);
+      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 *) xmalloc (sizeof (struct alpha_funcs));
+      cfaf = (struct alpha_funcs *) ggc_alloc (sizeof (struct alpha_funcs));
 
       cfaf->links = 0;
       cfaf->num = ++alpha_funcs_num;
@@ -9108,7 +9236,6 @@ alpha_need_linkage (name, is_local)
       splay_tree_insert (alpha_funcs_tree,
                         (splay_tree_key) current_function_decl,
                         (splay_tree_value) cfaf);
-    
     }
 
   if (alpha_links_tree)
@@ -9135,9 +9262,7 @@ alpha_need_linkage (name, is_local)
        }
     }
   else
-    {
-      alpha_links = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp);
-    }
+    alpha_links_tree = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp);
 
   al = (struct alpha_links *) ggc_alloc (sizeof (struct alpha_links));
   name = ggc_strdup (name);
@@ -9194,13 +9319,7 @@ alpha_use_linkage (linkage, cfundecl, lflag, rflag)
        al = (struct alpha_links *) lnode->value;
     }
   else
-    {
-      cfaf->links = splay_tree_new
-       ((splay_tree_compare_fn) strcmp,
-        (splay_tree_delete_key_fn) free,
-        (splay_tree_delete_key_fn) free);
-      ggc_add_root (&cfaf->links, 1, 1, mark_alpha_links);
-    }
+    cfaf->links = splay_tree_new_ggc ((splay_tree_compare_fn) strcmp);
 
   if (!al)
     {
@@ -9216,7 +9335,7 @@ alpha_use_linkage (linkage, cfundecl, lflag, rflag)
 
       name_len = strlen (name);
 
-      al = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
+      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);
@@ -9635,7 +9754,7 @@ unicosmk_unique_section (decl, reloc)
     abort ();
 
   name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
-  name = alpha_strip_name_encoding (name);
+  name = default_strip_name_encoding (name);
   len = strlen (name);
 
   if (TREE_CODE (decl) == FUNCTION_DECL)
@@ -9798,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 ());
 
@@ -9866,7 +9985,7 @@ unicosmk_ssib_name ()
   x = XEXP (x, 0);
   if (GET_CODE (x) != SYMBOL_REF)
     abort ();
-  fnname = alpha_strip_name_encoding (XSTR (x, 0));
+  fnname = default_name_encoding (XSTR (x, 0));
 
   len = strlen (fnname);
   if (len + SSIB_PREFIX_LEN > 255)
@@ -9932,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");
     }
 }
 
@@ -9996,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
 {
@@ -10041,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).  */
-      real_name = alpha_strip_name_encoding (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;
@@ -10078,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;
This page took 0.079599 seconds and 5 git commands to generate.