aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorBernd Schmidt <bernd.schmidt@analog.com>2005-07-20 09:48:03 +0000
committerBernd Schmidt <bernds@gcc.gnu.org>2005-07-20 09:48:03 +0000
commit6d459e2baebdc8206fba20befccf8ee13a0366f2 (patch)
treef25b02efbca3753d97500a06c643689dce3058d0 /gcc
parent67135ef48c6a53e06305d1038c4855e887568989 (diff)
downloadgcc-6d459e2baebdc8206fba20befccf8ee13a0366f2.zip
gcc-6d459e2baebdc8206fba20befccf8ee13a0366f2.tar.gz
gcc-6d459e2baebdc8206fba20befccf8ee13a0366f2.tar.bz2
bfin-protos.h (bfin_longcall_p): Declare.
* 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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog26
-rw-r--r--gcc/config/bfin/bfin-protos.h3
-rw-r--r--gcc/config/bfin/bfin.c98
-rw-r--r--gcc/config/bfin/bfin.h6
-rw-r--r--gcc/config/bfin/bfin.md146
-rw-r--r--gcc/config/bfin/predicates.md12
-rw-r--r--gcc/doc/extend.texi8
7 files changed, 229 insertions, 70 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index fd08ae3..5704cca 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/bfin/bfin-protos.h b/gcc/config/bfin/bfin-protos.h
index a22b1a1..7f69a68 100644
--- a/gcc/config/bfin/bfin-protos.h
+++ b/gcc/config/bfin/bfin-protos.h
@@ -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);
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 5be76bb..c4ee58b 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -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[])
}
}
+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 }
};
diff --git a/gcc/config/bfin/bfin.h b/gcc/config/bfin/bfin.h
index 7ced865..cfc6f5b 100644
--- a/gcc/config/bfin/bfin.h
+++ b/gcc/config/bfin/bfin.h
@@ -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.
diff --git a/gcc/config/bfin/bfin.md b/gcc/config/bfin/bfin.md
index 207bdd8..d0c93b4 100644
--- a/gcc/config/bfin/bfin.md
+++ b/gcc/config/bfin/bfin.md
@@ -1304,80 +1304,140 @@
;; 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
diff --git a/gcc/config/bfin/predicates.md b/gcc/config/bfin/predicates.md
index 7abd129..bf9972f 100644
--- a/gcc/config/bfin/predicates.md
+++ b/gcc/config/bfin/predicates.md
@@ -106,6 +106,10 @@
(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"
@@ -119,14 +123,6 @@
&& 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"))
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index f71c520..c5d4fd8 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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.