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
This commit is contained in:
Bernd Schmidt 2005-07-20 09:48:03 +00:00 committed by Bernd Schmidt
parent 67135ef48c
commit 6d459e2bae
7 changed files with 229 additions and 70 deletions

View 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.

View 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);

View 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[])
}
}
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 }
};

View 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.

View File

@ -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_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)
&& !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" "4")])
(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)
&& !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" "4")])
(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)
&& !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" "4")])
(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)
&& !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 "call_insn_operand" "a,Q"))
(match_operand 1 "general_operand" "g,g"))]
"! SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
"@
call (%0);
call %G0;"
[(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,4")])
(set_attr "length" "2")])
(define_insn "*sibcall_insn"
[(call (mem:SI (match_operand:SI 0 "call_insn_operand" "z,Q"))
(match_operand 1 "general_operand" "g,g"))
[(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)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
"@
jump (%0);
jump.l %G0;"
"SIBLING_CALL_P (insn)"
"jump (%0);"
[(set_attr "type" "br")
(set_attr "length" "2,4")])
(set_attr "length" "2")])
(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")))]
"! SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
"@
call (%1);
call %G1;"
[(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,4")])
(set_attr "length" "2")])
(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")))
[(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)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)"
"@
jump (%1);
jump.l %G1;"
"SIBLING_CALL_P (insn)"
"jump (%1);"
[(set_attr "type" "br")
(set_attr "length" "2,4")])
(set_attr "length" "2")])
;; Block move patterns

View File

@ -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"))

View 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.