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 void alpha_write_linkage
+ PARAMS ((FILE *, const char *, tree));
+#endif
+
static struct machine_function * alpha_init_machine_status
PARAMS ((void));
return str;
}
+#if TARGET_ABI_OPEN_VMS
+static bool
+alpha_linkage_symbol_p (symname)
+ const char *symname;
+{
+ int symlen = strlen (symname);
+
+ if (symlen > 4)
+ return strcmp (&symname [symlen - 4], "..lk") == 0;
+
+ 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.
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)
{
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 ();
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_procedure_type == PT_STACK ? "stack"
- : alpha_procedure_type == PT_REGISTER ? "reg" : "null");
alpha_need_linkage (fnname, 1);
text_section ();
#endif
}
}
}
+\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. */
}
inside_function = FALSE;
+#if TARGET_ABI_OPEN_VMS
+ alpha_write_linkage (file, fnname, decl);
+#endif
+
/* Show that we know this function if it is called again.
Do this only for functions whose symbols bind locally.
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
{
splay_tree_node node;
struct alpha_links *al;
+ struct alpha_funcs *cfaf;
if (name[0] == '*')
name++;
- if (alpha_links)
+ 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);
+
+ cfaf = (struct alpha_funcs *) xmalloc (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
+ ((splay_tree_compare_fn) strcmp,
+ (splay_tree_delete_key_fn) free,
+ (splay_tree_delete_key_fn) free);
+
+ ggc_add_root (&alpha_links_tree, 1, 1, mark_alpha_links);
}
al = (struct alpha_links *) xmalloc (sizeof (struct alpha_links));
name = xstrdup (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);
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
+ ((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);
+ }
+
+ 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 *) xmalloc (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;
{
- if (alpha_links)
+ splay_tree_node node;
+ struct alpha_funcs *func;
+
+ link_section ();
+ fprintf (stream, "\t.align 3\n");
+ 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)
{
- readonly_data_section ();
- fprintf (stream, "\t.align 3\n");
- splay_tree_foreach (alpha_links, alpha_write_one_linkage, stream);
+ splay_tree_foreach (func->links, alpha_write_one_linkage, stream);
+ /* splay_tree_delete (func->links); */
}
}
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
emit_move_insn (gen_rtx_REG (DImode, 25), operands[1]);
if (GET_CODE (operands[0]) == SYMBOL_REF)
{
- rtx linkage = alpha_need_linkage (XSTR (operands[0], 0), 0);
+ alpha_need_linkage (XSTR (operands[0], 0), 0);
- emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
- operands[2]
- = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
+ operands[2] = const0_rtx;
}
else
{
emit_move_insn (gen_rtx_REG (DImode, 25), operands[2]);
if (GET_CODE (operands[1]) == SYMBOL_REF)
{
- rtx linkage = alpha_need_linkage (XSTR (operands[1], 0), 0);
+ alpha_need_linkage (XSTR (operands[1], 0), 0);
- emit_move_insn (gen_rtx_REG (Pmode, 26), gen_rtx_MEM (Pmode, linkage));
- operands[3]
- = validize_mem (gen_rtx_MEM (Pmode, plus_constant (linkage, 8)));
+ operands[3] = const0_rtx;
}
else
{
[(set_attr "type" "jsr")
(set_attr "length" "*,*,12")])
+; GAS relies on the order and position of instructions output below in order
+; to generate relocs for VMS link to potentially optimize the call.
+; Please do not molest.
(define_insn "*call_vms_1"
[(call (mem:DI (match_operand:DI 0 "call_operand" "r,s"))
(match_operand 1 "" ""))
- (use (match_operand:DI 2 "nonimmediate_operand" "r,m"))
+ (use (match_operand:DI 2 "nonmemory_operand" "r,n"))
(use (reg:DI 25))
(use (reg:DI 26))
(clobber (reg:DI 27))]
"TARGET_ABI_OPEN_VMS"
- "@
- mov %2,$27\;jsr $26,0\;ldq $27,0($29)
- ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"mov %2,$27\;jsr $26,0\;ldq $27,0($29)\";
+ case 1:
+ operands [2] = alpha_use_linkage (operands [0], cfun->decl, 1, 0);
+ operands [3] = alpha_use_linkage (operands [0], cfun->decl, 0, 0);
+ return \"ldq $26,%3\;ldq $27,%2\;jsr $26,%0\;ldq $27,0($29)\";
+ default:
+ abort();
+ }
+}"
[(set_attr "type" "jsr")
(set_attr "length" "12,16")])
[(set_attr "type" "jsr")
(set_attr "length" "*,*,12")])
+; GAS relies on the order and position of instructions output below in order
+; to generate relocs for VMS link to potentially optimize the call.
+; Please do not molest.
(define_insn "*call_value_vms_1"
[(set (match_operand 0 "" "")
(call (mem:DI (match_operand:DI 1 "call_operand" "r,s"))
(match_operand 2 "" "")))
- (use (match_operand:DI 3 "nonimmediate_operand" "r,m"))
+ (use (match_operand:DI 3 "nonmemory_operand" "r,n"))
(use (reg:DI 25))
(use (reg:DI 26))
(clobber (reg:DI 27))]
"TARGET_ABI_OPEN_VMS"
- "@
- mov %3,$27\;jsr $26,0\;ldq $27,0($29)
- ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)"
+ "*
+{
+ switch (which_alternative)
+ {
+ case 0:
+ return \"mov %3,$27\;jsr $26,0\;ldq $27,0($29)\";
+ case 1:
+ operands [3] = alpha_use_linkage (operands [1], cfun->decl, 1, 0);
+ operands [4] = alpha_use_linkage (operands [1], cfun->decl, 0, 0);
+ return \"ldq $26,%4\;ldq $27,%3\;jsr $26,%1\;ldq $27,0($29)\";
+ default:
+ abort();
+ }
+}"
[(set_attr "type" "jsr")
(set_attr "length" "12,16")])