bfin-protos.h (bfin_longcall_p): Declare.
authorBernd Schmidt <bernd.schmidt@analog.com>
Wed, 20 Jul 2005 09:48:03 +0000 (09:48 +0000)
committerBernd Schmidt <bernds@gcc.gnu.org>
Wed, 20 Jul 2005 09:48:03 +0000 (09:48 +0000)
* config/bfin/bfin-protos.h (bfin_longcall_p): Declare.
* config/bfin/predicates.md (symbol_ref_operand): New.
(call_insn_operand): Delete.  All callers changed to use
register_no_elim_operand.
* config/bfin/bfin.c (init_cumulative_args): Initialize the new
call_cookie field.
(function_arg): Use it to generate the call's operand 2.
(bfin_longcall_p): New function.
(bfin_expand_call): Extra arg "cookie".  All callers and declaration
changed.  Emit extra USE in the pattern.  Use bfin_longcall_p to
determine if the address needs to be in a REG.
(bfin_handle_longcall_attribute): New function.
(bfin_attribute_table): Add "longcall" and "shortcall".
* config/bfin/bfin.h (CALL_NORMAL, CALL_LONG, CALL_SHORT): New macros.
(CUMULATIVE_ARGS): New member call_cookie.
(PREDICATE_CODES): Add symbol_ref_operand.
* config/bfin/bfin.md (call, call_value, sibcall, sibcall_value): Add
extra USE to the pattern.
(call_symbol, sibcall_symbol, call_value_symbol, sibcall_value_symbol):
New patterns, split off call_insn, sibcall_insn, call_value_insn and
sibcall_value_insn; now the new patterns handle direct calls and the
old ones indirect calls.
* doc/extend.texi: Mention Blackfin in longcall/shortcall docs.

From-SVN: r102191

gcc/ChangeLog
gcc/config/bfin/bfin-protos.h
gcc/config/bfin/bfin.c
gcc/config/bfin/bfin.h
gcc/config/bfin/bfin.md
gcc/config/bfin/predicates.md
gcc/doc/extend.texi

index fd08ae3b154f9c6424977a01183471e4ae0432e3..5704cca606acfb648d45266085c0c6fea724b358 100644 (file)
@@ -1,3 +1,29 @@
+2005-07-20  Bernd Schmidt  <bernd.schmidt@analog.com>
+
+       * config/bfin/bfin-protos.h (bfin_longcall_p): Declare.
+       * config/bfin/predicates.md (symbol_ref_operand): New.
+       (call_insn_operand): Delete.  All callers changed to use
+       register_no_elim_operand.
+       * config/bfin/bfin.c (init_cumulative_args): Initialize the new
+       call_cookie field.
+       (function_arg): Use it to generate the call's operand 2.
+       (bfin_longcall_p): New function.
+       (bfin_expand_call): Extra arg "cookie".  All callers and declaration
+       changed.  Emit extra USE in the pattern.  Use bfin_longcall_p to
+       determine if the address needs to be in a REG.
+       (bfin_handle_longcall_attribute): New function.
+       (bfin_attribute_table): Add "longcall" and "shortcall".
+       * config/bfin/bfin.h (CALL_NORMAL, CALL_LONG, CALL_SHORT): New macros.
+       (CUMULATIVE_ARGS): New member call_cookie.
+       (PREDICATE_CODES): Add symbol_ref_operand.
+       * config/bfin/bfin.md (call, call_value, sibcall, sibcall_value): Add
+       extra USE to the pattern.
+       (call_symbol, sibcall_symbol, call_value_symbol, sibcall_value_symbol):
+       New patterns, split off call_insn, sibcall_insn, call_value_insn and
+       sibcall_value_insn; now the new patterns handle direct calls and the
+       old ones indirect calls.
+       * doc/extend.texi: Mention Blackfin in longcall/shortcall docs.
+
 2005-07-20  Zdenek Dvorak  <dvorakz@suse.cz>
 
        * doc/trouble.texi: Update section on handling of empty loops.
index a22b1a1eb775762a5f61a28ffb411565b165161c..7f69a6899b2209bb72bd0079b734080acdda4d36 100644 (file)
@@ -45,7 +45,8 @@ extern int effective_address_32bit_p (rtx, Mmode);
 extern int symbolic_reference_mentioned_p (rtx);
 extern rtx bfin_gen_compare (rtx, Mmode);
 extern void expand_move (rtx *, Mmode);
-extern void bfin_expand_call (rtx, rtx, rtx, int);
+extern void bfin_expand_call (rtx, rtx, rtx, rtx, int);
+extern bool bfin_longcall_p (rtx, int);
 extern bool bfin_expand_strmov (rtx, rtx, rtx, rtx);
 
 extern void conditional_register_usage (void);
index 5be76bbec5a03c50e63c48376be3ad5f0c9fb71e..c4ee58b4ae59ea2961ff1348bb698d51883abb2e 100644 (file)
@@ -1146,7 +1146,7 @@ print_operand (FILE *file, rtx x, char code)
 */
 
 void
-init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
+init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
                      rtx libname ATTRIBUTE_UNUSED)
 {
   static CUMULATIVE_ARGS zero_cum;
@@ -1158,6 +1158,13 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
   cum->nregs = max_arg_registers;
   cum->arg_regs = arg_regs;
 
+  cum->call_cookie = CALL_NORMAL;
+  /* Check for a longcall attribute.  */
+  if (fntype && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
+    cum->call_cookie |= CALL_SHORT;
+  else if (fntype && lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype)))
+    cum->call_cookie |= CALL_LONG;
+
   return;
 }
 
@@ -1211,6 +1218,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
   int bytes
     = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
 
+  if (mode == VOIDmode)
+    /* Compute operand 2 of the call insn.  */
+    return GEN_INT (cum->call_cookie);
+
   if (bytes == -1)
     return NULL_RTX;
 
@@ -1508,37 +1519,59 @@ split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[])
     }
 }
 \f
+bool
+bfin_longcall_p (rtx op, int call_cookie)
+{
+  gcc_assert (GET_CODE (op) == SYMBOL_REF);
+  if (call_cookie & CALL_SHORT)
+    return 0;
+  if (call_cookie & CALL_LONG)
+    return 1;
+  if (TARGET_LONG_CALLS)
+    return 1;
+  return 0;
+}
+
 /* Expand a call instruction.  FNADDR is the call target, RETVAL the return value.
+   COOKIE is a CONST_INT holding the call_cookie prepared init_cumulative_args.
    SIBCALL is nonzero if this is a sibling call.  */
 
 void
-bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, int sibcall)
+bfin_expand_call (rtx retval, rtx fnaddr, rtx callarg1, rtx cookie, int sibcall)
 {
   rtx use = NULL, call;
+  rtx callee = XEXP (fnaddr, 0);
+  rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (sibcall ? 3 : 2));
+
+  /* In an untyped call, we can get NULL for operand 2.  */
+  if (cookie == NULL_RTX)
+    cookie = const0_rtx;
 
   /* Static functions and indirect calls don't need the pic register.  */
   if (flag_pic
-      && GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF
-      && ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0)))
+      && GET_CODE (callee) == SYMBOL_REF
+      && !SYMBOL_REF_LOCAL_P (callee))
     use_reg (&use, pic_offset_table_rtx);
 
-  if (! call_insn_operand (XEXP (fnaddr, 0), Pmode))
+  if ((!register_no_elim_operand (callee, Pmode)
+       && GET_CODE (callee) != SYMBOL_REF)
+      || (GET_CODE (callee) == SYMBOL_REF
+         && (flag_pic
+             || bfin_longcall_p (callee, INTVAL (cookie)))))
     {
-      fnaddr = copy_to_mode_reg (Pmode, XEXP (fnaddr, 0));
-      fnaddr = gen_rtx_MEM (Pmode, fnaddr);
+      callee = copy_to_mode_reg (Pmode, callee);
+      fnaddr = gen_rtx_MEM (Pmode, callee);
     }
   call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
 
   if (retval)
     call = gen_rtx_SET (VOIDmode, retval, call);
+
+  XVECEXP (pat, 0, 0) = call;
+  XVECEXP (pat, 0, 1) = gen_rtx_USE (VOIDmode, cookie);
   if (sibcall)
-    {
-      rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
-      XVECEXP (pat, 0, 0) = call;
-      XVECEXP (pat, 0, 1) = gen_rtx_RETURN (VOIDmode);
-      call = pat;
-    }
-  call = emit_call_insn (call);
+    XVECEXP (pat, 0, 2) = gen_rtx_RETURN (VOIDmode);
+  call = emit_call_insn (pat);
   if (use)
     CALL_INSN_FUNCTION_USAGE (call) = use;
 }
@@ -2668,9 +2701,44 @@ bfin_comp_type_attributes (tree type1, tree type2)
       != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
     return 0;
 
+  if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
+      != !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
+    return 0;
+
   return 1;
 }
 
+/* Handle a "longcall" or "shortcall" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+bfin_handle_longcall_attribute (tree *node, tree name, 
+                               tree args ATTRIBUTE_UNUSED, 
+                               int flags ATTRIBUTE_UNUSED, 
+                               bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_TYPE
+      && TREE_CODE (*node) != FIELD_DECL
+      && TREE_CODE (*node) != TYPE_DECL)
+    {
+      warning (OPT_Wattributes, "`%s' attribute only applies to functions",
+              IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  if ((strcmp (IDENTIFIER_POINTER (name), "longcall") == 0
+       && lookup_attribute ("shortcall", TYPE_ATTRIBUTES (*node)))
+      || (strcmp (IDENTIFIER_POINTER (name), "shortcall") == 0
+         && lookup_attribute ("longcall", TYPE_ATTRIBUTES (*node))))
+    {
+      warning (OPT_Wattributes,
+              "can't apply both longcall and shortcall attributes to the same function");
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Table of valid machine attributes.  */
 const struct attribute_spec bfin_attribute_table[] =
 {
@@ -2681,6 +2749,8 @@ const struct attribute_spec bfin_attribute_table[] =
   { "nesting", 0, 0, false, true,  true, NULL },
   { "kspisusp", 0, 0, false, true,  true, NULL },
   { "saveall", 0, 0, false, true,  true, NULL },
+  { "longcall",  0, 0, false, true,  true,  bfin_handle_longcall_attribute },
+  { "shortcall", 0, 0, false, true,  true,  bfin_handle_longcall_attribute },
   { NULL, 0, 0, false, false, false, NULL }
 };
 \f
index 7ced865f997c45fa31da957cbea46617d5646c03..cfc6f5bc50b98669ccfeea33d2460129771b5409 100644 (file)
@@ -530,10 +530,16 @@ typedef enum {
 
 #define FUNCTION_ARG_REGISTERS { REG_R0, REG_R1, REG_R2, -1 }
 
+/* Flags for the call/call_value rtl operations set up by function_arg */
+#define CALL_NORMAL            0x00000000      /* no special processing */
+#define CALL_LONG              0x00000001      /* always call indirect */
+#define CALL_SHORT             0x00000002      /* always call by symbol */
+
 typedef struct {
   int words;                   /* # words passed so far */
   int nregs;                   /* # registers available for passing */
   int *arg_regs;               /* array of register -1 terminated */
+  int call_cookie;             /* Do special things for this call */
 } CUMULATIVE_ARGS;
 
 /* Define where to put the arguments to a function.
index 207bdd8ee7f43954541e55c3ddd8e36a7d59e99d..d0c93b4b42fab5c7630646d6c69e5a1deb8e1a83 100644 (file)
 ;;  Call instructions..
 
 (define_expand "call"
-  [(call (match_operand:SI 0 "" "")
-        (match_operand 1 "" ""))]
+  [(parallel [(call (match_operand:SI 0 "" "")
+                   (match_operand 1 "" ""))
+             (use (match_operand 2 "" ""))])]
   ""
-  "bfin_expand_call (NULL_RTX, operands[0], operands[1], 0); DONE;")
+{
+  bfin_expand_call (NULL_RTX, operands[0], operands[1], operands[2], 0);
+  DONE;
+})
 
 (define_expand "sibcall"
   [(parallel [(call (match_operand:SI 0 "" "")
                    (match_operand 1 "" ""))
+             (use (match_operand 2 "" ""))
              (return)])]
   ""
-  "bfin_expand_call (NULL_RTX, operands[0], operands[1], 1); DONE;")
+{
+  bfin_expand_call (NULL_RTX, operands[0], operands[1], operands[2], 1);
+  DONE;
+})
 
 (define_expand "call_value"
-  [(set (match_operand 0 "register_operand" "")
-         (call (match_operand:SI 1 "" "")
-              (match_operand 2 "" "")))]
+  [(parallel [(set (match_operand 0 "register_operand" "")
+                  (call (match_operand:SI 1 "" "")
+                        (match_operand 2 "" "")))
+             (use (match_operand 3 "" ""))])]
   ""
-  "bfin_expand_call (operands[0], operands[1], operands[2], 0); DONE;")
+{
+  bfin_expand_call (operands[0], operands[1], operands[2], operands[3], 0);
+  DONE;
+})
 
 (define_expand "sibcall_value"
   [(parallel [(set (match_operand 0 "register_operand" "")
                   (call (match_operand:SI 1 "" "")
                         (match_operand 2 "" "")))
+             (use (match_operand 3 "" ""))
              (return)])]
   ""
-  "bfin_expand_call (operands[0], operands[1], operands[2], 1); DONE;")
+{
+  bfin_expand_call (operands[0], operands[1], operands[2], operands[3], 1);
+  DONE;
+})
 
-(define_insn "*call_insn"
-  [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "a,Q"))
-        (match_operand 1 "general_operand" "g,g"))]
+(define_insn "*call_symbol"
+  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q"))
+        (match_operand 1 "general_operand" "g"))
+   (use (match_operand 2 "" ""))]
   "! SIBLING_CALL_P (insn)
-   && (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
-  "@
-  call (%0);
-  call %G0;"
+   && !flag_pic
+   && GET_CODE (operands[0]) == SYMBOL_REF
+   && !bfin_longcall_p (operands[0], INTVAL (operands[2]))"
+  "call %G0;"
   [(set_attr "type" "call")
-   (set_attr "length" "2,4")])
+   (set_attr "length" "4")])
 
-(define_insn "*sibcall_insn"
-  [(call (mem:SI (match_operand:SI 0 "call_insn_operand" "z,Q"))
-        (match_operand 1 "general_operand" "g,g"))
+(define_insn "*sibcall_symbol"
+  [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q"))
+        (match_operand 1 "general_operand" "g"))
+   (use (match_operand 2 "" ""))
    (return)]
   "SIBLING_CALL_P (insn)
-   && (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
-  "@
-  jump (%0);
-  jump.l %G0;"
+   && !flag_pic
+   && GET_CODE (operands[0]) == SYMBOL_REF
+   && !bfin_longcall_p (operands[0], INTVAL (operands[2]))"
+  "jump.l %G0;"
   [(set_attr "type" "br")
-   (set_attr "length" "2,4")])
+   (set_attr "length" "4")])
 
-(define_insn "*call_value_insn"
-  [(set (match_operand 0 "register_operand" "=d,d")
-        (call (mem:SI (match_operand:SI 1 "call_insn_operand" "a,Q"))
-             (match_operand 2 "general_operand" "g,g")))]
+(define_insn "*call_value_symbol"
+  [(set (match_operand 0 "register_operand" "=d")
+        (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q"))
+             (match_operand 2 "general_operand" "g")))
+   (use (match_operand 3 "" ""))]
   "! SIBLING_CALL_P (insn)
-   && (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
-  "@
-  call (%1);
-  call %G1;"
+   && !flag_pic
+   && GET_CODE (operands[1]) == SYMBOL_REF
+   && !bfin_longcall_p (operands[1], INTVAL (operands[3]))"
+  "call %G1;"
   [(set_attr "type" "call")
-   (set_attr "length" "2,4")])
+   (set_attr "length" "4")])
 
-(define_insn "*sibcall_value_insn"
-  [(set (match_operand 0 "register_operand" "=d,d")
-         (call (mem:SI (match_operand:SI 1 "call_insn_operand" "z,Q"))
-              (match_operand 2 "general_operand" "g,g")))
+(define_insn "*sibcall_value_symbol"
+  [(set (match_operand 0 "register_operand" "=d")
+         (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q"))
+              (match_operand 2 "general_operand" "g")))
+   (use (match_operand 3 "" ""))
    (return)]
   "SIBLING_CALL_P (insn)
-   && (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
-  "@
-  jump (%1);
-  jump.l %G1;"
+   && !flag_pic
+   && GET_CODE (operands[1]) == SYMBOL_REF
+   && !bfin_longcall_p (operands[1], INTVAL (operands[3]))"
+  "jump.l %G1;"
+  [(set_attr "type" "br")
+   (set_attr "length" "4")])
+
+(define_insn "*call_insn"
+  [(call (mem:SI (match_operand:SI 0 "register_no_elim_operand" "a"))
+        (match_operand 1 "general_operand" "g"))
+   (use (match_operand 2 "" ""))]
+  "! SIBLING_CALL_P (insn)"
+  "call (%0);"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")])
+
+(define_insn "*sibcall_insn"
+  [(call (mem:SI (match_operand:SI 0 "register_no_elim_operand" "z"))
+        (match_operand 1 "general_operand" "g"))
+   (use (match_operand 2 "" ""))
+   (return)]
+  "SIBLING_CALL_P (insn)"
+  "jump (%0);"
+  [(set_attr "type" "br")
+   (set_attr "length" "2")])
+
+(define_insn "*call_value_insn"
+  [(set (match_operand 0 "register_operand" "=d")
+        (call (mem:SI (match_operand:SI 1 "register_no_elim_operand" "a"))
+             (match_operand 2 "general_operand" "g")))
+   (use (match_operand 3 "" ""))]
+  "! SIBLING_CALL_P (insn)"
+  "call (%1);"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")])
+
+(define_insn "*sibcall_value_insn"
+  [(set (match_operand 0 "register_operand" "=d")
+         (call (mem:SI (match_operand:SI 1 "register_no_elim_operand" "z"))
+              (match_operand 2 "general_operand" "g")))
+   (use (match_operand 3 "" ""))
+   (return)]
+  "SIBLING_CALL_P (insn)"
+  "jump (%1);"
   [(set_attr "type" "br")
-   (set_attr "length" "2,4")])
+   (set_attr "length" "2")])
 
 ;; Block move patterns
 
index 7abd129d9f3bbd3123b3821d39b439e5bcd5fdc5..bf9972f76670a5abe9de5ab1bbf90002ac524f3c 100644 (file)
   (ior (match_code "const_int,const_double")
        (match_operand 0 "symbolic_operand")))
 
+;; Returns 1 if OP is a SYMBOL_REF.
+(define_predicate "symbol_ref_operand"
+  (match_code "symbol_ref"))
+
 ;; True for any non-virtual or eliminable register.  Used in places where
 ;; instantiation of such a register may cause the pattern to not be recognized.
 (define_predicate "register_no_elim_operand"
               && REGNO (op) <= LAST_VIRTUAL_REGISTER));
 })
 
-;; Test for a valid operand for a call instruction.  Don't allow the
-;; arg pointer register or virtual regs since they may decay into
-;; reg + const, which the patterns can't handle.
-;; We only allow SYMBOL_REF if !flag_pic.
-(define_predicate "call_insn_operand"
-  (ior (and (match_test "!flag_pic && !TARGET_LONG_CALLS") (match_code "symbol_ref"))
-       (match_operand 0 "register_no_elim_operand")))
-
 ;; Test for an operator valid in a conditional branch
 (define_predicate "bfin_cbranch_operator"
   (match_code "eq,ne"))
index f71c5200a0ae102c1ab6dbaaff5e199dba6c7dfb..c5d4fd833004ce6a9f47976c454d658dae23882c 100644 (file)
@@ -1932,12 +1932,12 @@ instruction directly.
 
 @item longcall/shortcall
 @cindex functions called via pointer on the RS/6000 and PowerPC
-On the RS/6000 and PowerPC, the @code{longcall} attribute causes the
-compiler to always call this function via a pointer, just as it would if
+On the Blackfin, RS/6000 and PowerPC, the @code{longcall} attribute causes
+the compiler to always call this function via a pointer, just as it would if
 the @option{-mlongcall} option had been specified.  The @code{shortcall}
 attribute causes the compiler not to do this.  These attributes override
-both the @option{-mlongcall} switch and the @code{#pragma longcall}
-setting.
+both the @option{-mlongcall} switch and, on the RS/6000 and PowerPC, the
+@code{#pragma longcall} setting.
 
 @xref{RS/6000 and PowerPC Options}, for more information on whether long
 calls are necessary.