diff options
author | Bernd Schmidt <bernd.schmidt@analog.com> | 2005-07-20 09:48:03 +0000 |
---|---|---|
committer | Bernd Schmidt <bernds@gcc.gnu.org> | 2005-07-20 09:48:03 +0000 |
commit | 6d459e2baebdc8206fba20befccf8ee13a0366f2 (patch) | |
tree | f25b02efbca3753d97500a06c643689dce3058d0 /gcc | |
parent | 67135ef48c6a53e06305d1038c4855e887568989 (diff) | |
download | gcc-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/ChangeLog | 26 | ||||
-rw-r--r-- | gcc/config/bfin/bfin-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.c | 98 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.h | 6 | ||||
-rw-r--r-- | gcc/config/bfin/bfin.md | 146 | ||||
-rw-r--r-- | gcc/config/bfin/predicates.md | 12 | ||||
-rw-r--r-- | gcc/doc/extend.texi | 8 |
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. |