aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Meissner <meissner@gcc.gnu.org>1996-03-04 16:34:29 +0000
committerMichael Meissner <meissner@gcc.gnu.org>1996-03-04 16:34:29 +0000
commit6a4cee5fdb4e3367b77d3bbe700a7e132616037c (patch)
treeb2cea70495238983f6ab5e53aee0d4c5f53d77d8
parentde3a68a106506d13e4429f868c3af140a022c6a3 (diff)
downloadgcc-6a4cee5fdb4e3367b77d3bbe700a7e132616037c.zip
gcc-6a4cee5fdb4e3367b77d3bbe700a7e132616037c.tar.gz
gcc-6a4cee5fdb4e3367b77d3bbe700a7e132616037c.tar.bz2
Add attribute((longcall)) support
From-SVN: r11416
-rw-r--r--gcc/config/rs6000/rs6000.c52
-rw-r--r--gcc/config/rs6000/rs6000.h27
-rw-r--r--gcc/config/rs6000/rs6000.md130
3 files changed, 131 insertions, 78 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 54f552a..401faa6 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -939,6 +939,10 @@ init_cumulative_args (cum, fntype, libname, incoming)
&& lookup_attribute ("dllimport", TYPE_ATTRIBUTES (fntype)))
cum->call_cookie = CALL_NT_DLLIMPORT;
+ /* Also check for longcall's */
+ else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
+ cum->call_cookie = CALL_LONG;
+
if (TARGET_DEBUG_ARG)
{
fprintf (stderr, "\ninit_cumulative_args:");
@@ -952,9 +956,12 @@ init_cumulative_args (cum, fntype, libname, incoming)
if (abi == ABI_V4 && incoming)
fprintf (stderr, " varargs = %d, ", cum->varargs_offset);
- if (cum->call_cookie == CALL_NT_DLLIMPORT)
+ if (cum->call_cookie & CALL_NT_DLLIMPORT)
fprintf (stderr, " dllimport,");
+ if (cum->call_cookie & CALL_LONG)
+ fprintf (stderr, " longcall,");
+
fprintf (stderr, " proto = %d, nargs = %d\n",
cum->prototype, cum->nargs_prototype);
}
@@ -1089,12 +1096,10 @@ function_arg (cum, mode, type, named)
&& cum->nargs_prototype < 0
&& type && (cum->prototype || TARGET_NO_PROTOTYPE))
{
- if (cum->call_cookie != CALL_NORMAL)
- abort ();
-
- return GEN_INT ((cum->fregno == FP_ARG_MIN_REG)
- ? CALL_V4_SET_FP_ARGS
- : CALL_V4_CLEAR_FP_ARGS);
+ return GEN_INT (cum->call_cookie
+ | ((cum->fregno == FP_ARG_MIN_REG)
+ ? CALL_V4_SET_FP_ARGS
+ : CALL_V4_CLEAR_FP_ARGS));
}
return GEN_INT (cum->call_cookie);
@@ -4248,6 +4253,11 @@ rs6000_valid_type_attribute_p (type, attributes, identifier, args)
&& TREE_CODE (type) != TYPE_DECL)
return 0;
+ /* Longcall attribute says that the function is not within 2**26 bytes
+ of the current function, and to do an indirect call. */
+ if (is_attribute_p ("longcall", identifier))
+ return (args == NULL_TREE);
+
if (DEFAULT_ABI == ABI_NT)
{
/* Stdcall attribute says callee is responsible for popping arguments
@@ -4324,6 +4334,34 @@ rs6000_dll_import_ref (call_ref)
return reg2;
}
+/* Return a reference suitable for calling a function with the longcall attribute. */
+struct rtx_def *
+rs6000_longcall_ref (call_ref)
+ rtx call_ref;
+{
+ char *call_name;
+ int len;
+ char *p;
+ rtx reg1, reg2;
+ tree node;
+
+ if (GET_CODE (call_ref) != SYMBOL_REF)
+ return call_ref;
+
+ /* System V adds '.' to the internal name, so skip them. */
+ call_name = XSTR (call_ref, 0);
+ if (*call_name == '.')
+ {
+ while (*call_name == '.')
+ call_name++;
+
+ node = get_identifier (call_name);
+ call_ref = gen_rtx (SYMBOL_REF, VOIDmode, IDENTIFIER_POINTER (node));
+ }
+
+ return force_reg (Pmode, call_ref);
+}
+
/* A C statement or statements to switch to the appropriate section
for output of RTX in mode MODE. You can assume that RTX is some
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 461079a..d2e34a6 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1246,13 +1246,11 @@ extern int rs6000_sysv_varargs_p;
#define FP_ARG_RETURN FP_ARG_MIN_REG
/* Flags for the call/call_value rtl operations set up by function_arg */
-enum rs6000_call_cookie
-{
- CALL_V4_SET_FP_ARGS = -1, /* V4, FP args passed */
- CALL_NORMAL = 0, /* no special processing */
- CALL_V4_CLEAR_FP_ARGS = 1, /* V4, no FP args passed */
- CALL_NT_DLLIMPORT = 2 /* NT, this is a DLL import call */
-};
+#define CALL_NORMAL 0x00000000 /* no special processing */
+#define CALL_NT_DLLIMPORT 0x00000001 /* NT, this is a DLL import call */
+#define CALL_V4_CLEAR_FP_ARGS 0x00000002 /* V.4, no FP args passed */
+#define CALL_V4_SET_FP_ARGS 0x00000004 /* V.4, FP args were passed */
+#define CALL_LONG 0x00000008 /* always call indirect */
/* Define cutoff for using external functions to save floating point */
#define FP_SAVE_INLINE(FIRST_REG) ((FIRST_REG) == 62 || (FIRST_REG) == 63)
@@ -1287,13 +1285,13 @@ enum rs6000_call_cookie
typedef struct rs6000_args
{
- int words; /* # words uses for passing GP registers */
- int fregno; /* next available FP register */
- int nargs_prototype; /* # args left in the current prototype */
- int orig_nargs; /* Original value of nargs_prototype */
- int varargs_offset; /* offset of the varargs save area */
- int prototype; /* Whether a prototype was defined */
- enum rs6000_call_cookie call_cookie; /* Do special things for this call */
+ int words; /* # words uses for passing GP registers */
+ int fregno; /* next available FP register */
+ int nargs_prototype; /* # args left in the current prototype */
+ int orig_nargs; /* Original value of nargs_prototype */
+ int varargs_offset; /* offset of the varargs save area */
+ int prototype; /* Whether a prototype was defined */
+ int call_cookie; /* Do special things for this call */
} CUMULATIVE_ARGS;
/* Define intermediate macro to compute the size (in registers) of an argument
@@ -2879,3 +2877,4 @@ extern int rs6000_valid_decl_attribute_p ();
extern int rs6000_valid_type_attribute_p ();
extern void rs6000_set_default_type_attributes ();
extern struct rtx_def *rs6000_dll_import_ref ();
+extern struct rtx_def *rs6000_longcall_ref ();
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 76f6c2e..24b6cb0 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -6541,27 +6541,29 @@
(define_insn "call_indirect_aix"
[(call (mem:SI (match_operand:SI 0 "register_operand" "b"))
(match_operand 1 "const_int_operand" "n"))
- (use (match_operand 2 "const_int_operand" "O"))
+ (use (match_operand 2 "const_int_operand" "n"))
(use (match_operand 3 "offsettable_addr_operand" "p"))
(use (match_operand 4 "register_operand" "r"))
(clobber (match_operand 5 "register_operand" "=r"))
(clobber (match_scratch:SI 6 "=&r"))
(clobber (match_scratch:SI 7 "=l"))]
- "DEFAULT_ABI == ABI_AIX"
- "{st|stw} %4,%a3\;{l|lwz} %6,0(%0)\;{l|lwz} %4,4(%0);\;mt%7 %6\;{l|lwz} %5,8(%0)\;{brl|blrl}\;{l|lwz} %4,%a3"
+ "DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
+ "{st|stw} %4,%a3\;{l|lwz} %6,0(%0)\;{l|lwz} %4,4(%0)\;mt%7 %6\;{l|lwz} %5,8(%0)\;{brl|blrl}\;{l|lwz} %4,%a3"
[(set_attr "length" "28")])
(define_insn "call_value_indirect_aix"
[(set (match_operand 0 "register_operand" "fg")
(call (mem:SI (match_operand:SI 1 "register_operand" "b"))
(match_operand 2 "const_int_operand" "n")))
- (use (match_operand 3 "const_int_operand" "O"))
+ (use (match_operand 3 "const_int_operand" "n"))
(use (match_operand 4 "offsettable_addr_operand" "p"))
(use (match_operand 5 "register_operand" "r"))
(clobber (match_operand 6 "register_operand" "=r"))
(clobber (match_scratch:SI 7 "=&r"))
(clobber (match_scratch:SI 8 "=l"))]
- "DEFAULT_ABI == ABI_AIX"
+ "DEFAULT_ABI == ABI_AIX
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
"{st|stw} %5,%a4\;{l|lwz} %7,0(%1)\;{l|lwz} %5,4(%1);\;mt%8 %7\;{l|lwz} %6,8(%1)\;{brl|blrl}\;{l|lwz} %5,%a4"
[(set_attr "length" "28")])
@@ -6582,12 +6584,13 @@
(define_insn "call_indirect_nt"
[(call (mem:SI (match_operand:SI 0 "register_operand" "b"))
(match_operand 1 "const_int_operand" "n"))
- (use (match_operand 2 "const_int_operand" "O"))
+ (use (match_operand 2 "const_int_operand" "n"))
(use (match_operand 3 "offsettable_addr_operand" "p"))
(use (match_operand 4 "register_operand" "r"))
(clobber (match_scratch:SI 5 "=&r"))
(clobber (match_scratch:SI 6 "=l"))]
- "DEFAULT_ABI == ABI_NT"
+ "DEFAULT_ABI == ABI_NT
+ && (INTVAL (operands[2]) == CALL_NORMAL || (INTVAL (operands[2]) & CALL_LONG) != 0)"
"{st|stw} %4,%a3\;{l|lwz} %5,0(%0)\;{l|lwz} %4,4(%0)\;mt%6 %5\;{brl|blrl}\;{l|lwz} %4,%a3"
[(set_attr "length" "24")])
@@ -6595,12 +6598,13 @@
[(set (match_operand 0 "register_operand" "fg")
(call (mem:SI (match_operand:SI 1 "register_operand" "b"))
(match_operand 2 "const_int_operand" "n")))
- (use (match_operand 3 "const_int_operand" "O"))
+ (use (match_operand 3 "const_int_operand" "n"))
(use (match_operand 4 "offsettable_addr_operand" "p"))
(use (match_operand 5 "register_operand" "r"))
(clobber (match_scratch:SI 6 "=&r"))
(clobber (match_scratch:SI 7 "=l"))]
- "DEFAULT_ABI == ABI_NT"
+ "DEFAULT_ABI == ABI_NT
+ && (INTVAL (operands[3]) == CALL_NORMAL || (INTVAL (operands[3]) & CALL_LONG) != 0)"
"{st|stw} %5,%a4\;{l|lwz} %6,0(%1)\;{l|lwz} %5,4(%1)\;mt%7 %6\;{brl|blrl}\;{l|lwz} %5,%a4"
[(set_attr "length" "24")])
@@ -6617,11 +6621,11 @@
"DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC"
"*
{
- if (INTVAL (operands[2]) > 0)
- return \"creqv 6,6,6\;{brl|blrl}\";
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
- else if (INTVAL (operands[2]) < 0)
- return \"crxor 6,6,6\;{brl|blrl}\";
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"{brl|blrl}\";
}"
@@ -6636,11 +6640,11 @@
"DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC"
"*
{
- if (INTVAL (operands[3]) > 0)
- return \"creqv 6,6,6\;{brl|blrl}\";
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
- else if (INTVAL (operands[3]) < 0)
- return \"crxor 6,6,6\;{brl|blrl}\";
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"{brl|blrl}\";
}"
@@ -6662,14 +6666,18 @@
/* Convert NT DLL imports into an indirect call. */
if (GET_CODE (operands[0]) == SYMBOL_REF
- && INTVAL (operands[2]) == (int)CALL_NT_DLLIMPORT)
+ && (INTVAL (operands[2]) & CALL_NT_DLLIMPORT) != 0)
{
operands[0] = rs6000_dll_import_ref (operands[0]);
operands[2] = GEN_INT ((int)CALL_NORMAL);
}
- if (GET_CODE (operands[0]) != SYMBOL_REF)
+ if (GET_CODE (operands[0]) != SYMBOL_REF
+ || (INTVAL (operands[2]) & CALL_LONG) != 0)
{
+ if (INTVAL (operands[2]) & CALL_LONG)
+ operands[0] = rs6000_longcall_ref (operands[0]);
+
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC)
emit_call_insn (gen_call_indirect_sysv (force_reg (Pmode, operands[0]),
operands[1], operands[2]));
@@ -6717,14 +6725,18 @@
/* Convert NT DLL imports into an indirect call. */
if (GET_CODE (operands[1]) == SYMBOL_REF
- && INTVAL (operands[3]) == (int)CALL_NT_DLLIMPORT)
+ && (INTVAL (operands[3]) & CALL_NT_DLLIMPORT) != 0)
{
operands[1] = rs6000_dll_import_ref (operands[1]);
operands[3] = GEN_INT ((int)CALL_NORMAL);
}
- if (GET_CODE (operands[1]) != SYMBOL_REF)
+ if (GET_CODE (operands[1]) != SYMBOL_REF
+ || (INTVAL (operands[3]) & CALL_LONG) != 0)
{
+ if (INTVAL (operands[2]) & CALL_LONG)
+ operands[1] = rs6000_longcall_ref (operands[1]);
+
if (DEFAULT_ABI == ABI_V4 || DEFAULT_ABI == ABI_AIX_NODESC)
emit_call_insn (gen_call_value_indirect_sysv (operands[0], operands[1],
operands[2], operands[3]));
@@ -6769,14 +6781,14 @@
(match_operand 1 "" "g,g"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 3 "=l,l"))]
- ""
+ "INTVAL (operands[2]) != CALL_LONG"
"*
{
- switch ((enum rs6000_call_cookie)INTVAL (operands[2]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"bl %z0\";
}"
@@ -6794,18 +6806,19 @@
(match_operand 1 "" "fg,fg"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 3 "=l,l"))]
- "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT"
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && INTVAL (operands[2]) != CALL_LONG"
"*
{
/* Indirect calls should go through call_indirect */
if (GET_CODE (operands[0]) == REG)
abort ();
- switch ((enum rs6000_call_cookie)INTVAL (operands[2]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return (TARGET_WINDOWS_NT) ? \"bl %z0\;.znop %z0\" : \"bl %z0\;%.\";
}"
@@ -6816,18 +6829,19 @@
(match_operand 1 "" "fg,fg"))
(use (match_operand:SI 2 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 3 "=l,l"))]
- "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4"
+ "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4)
+ && INTVAL (operands[2]) != CALL_LONG"
"*
{
/* Indirect calls should go through call_indirect */
if (GET_CODE (operands[0]) == REG)
abort ();
- switch ((enum rs6000_call_cookie)INTVAL (operands[2]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"bl %z0\";
}"
@@ -6839,14 +6853,14 @@
(match_operand 2 "" "g,g")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
- ""
+ "INTVAL (operands[3]) != CALL_LONG"
"*
{
- switch ((enum rs6000_call_cookie)INTVAL (operands[3]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"bl %z1\";
}"
@@ -6858,18 +6872,19 @@
(match_operand 2 "" "fg,fg")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
- "DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT"
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_NT)
+ && INTVAL (operands[3]) != CALL_LONG"
"*
{
/* This should be handled by call_value_indirect */
if (GET_CODE (operands[1]) == REG)
abort ();
- switch ((enum rs6000_call_cookie)INTVAL (operands[3]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return (TARGET_WINDOWS_NT) ? \"bl %z1\;.znop %z1\" : \"bl %z1\;%.\";
}"
@@ -6881,18 +6896,19 @@
(match_operand 2 "" "fg,fg")))
(use (match_operand:SI 3 "immediate_operand" "O,n"))
(clobber (match_scratch:SI 4 "=l,l"))]
- "DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4"
+ "(DEFAULT_ABI == ABI_AIX_NODESC || DEFAULT_ABI == ABI_V4)
+ && INTVAL (operands[3]) != CALL_LONG"
"*
{
/* This should be handled by call_value_indirect */
if (GET_CODE (operands[1]) == REG)
abort ();
- switch ((enum rs6000_call_cookie)INTVAL (operands[3]))
- {
- case CALL_V4_SET_FP_ARGS: output_asm_insn (\"crxor 6,6,6\", operands); break;
- case CALL_V4_CLEAR_FP_ARGS: output_asm_insn (\"creqv 6,6,6\", operands); break;
- }
+ if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS)
+ output_asm_insn (\"crxor 6,6,6\", operands);
+
+ else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS)
+ output_asm_insn (\"creqv 6,6,6\", operands);
return \"bl %z1\";
}"