Add attribute((longcall)) support
authorMichael Meissner <meissner@gcc.gnu.org>
Mon, 4 Mar 1996 16:34:29 +0000 (16:34 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Mon, 4 Mar 1996 16:34:29 +0000 (16:34 +0000)
From-SVN: r11416

gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md

index 54f552a4de7b932ecfa7ada7b0da01e216d6ab2d..401faa62b3cecc6caa79e29ecace6c261f47b4b9 100644 (file)
@@ -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);
+}
+
 \f
 /* 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
index 461079aa54ca2625db6280b08794e15597b2ed2a..d2e34a6848d1c331a00382be8ea40ccee354cbb3 100644 (file)
@@ -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 ();
index 76f6c2e683a84a1bc3073fdea511431190a392c3..24b6cb095695834f326122fdaebed80677d324bd 100644 (file)
 (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")])
 
 (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")])
 
   [(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")])
 
   "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}\";
 }"
   "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}\";
 }"
 
   /* 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]));
 
   /* 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]));
         (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\";
 }"
         (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\;%.\";
 }"
         (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\";
 }"
              (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\";
 }"
              (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\;%.\";
 }"
              (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\";
 }"