Commit 6d459e2b by Bernd Schmidt Committed by Bernd Schmidt

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
parent 67135ef4
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> 2005-07-20 Zdenek Dvorak <dvorakz@suse.cz>
* doc/trouble.texi: Update section on handling of empty loops. * doc/trouble.texi: Update section on handling of empty loops.
......
...@@ -45,7 +45,8 @@ extern int effective_address_32bit_p (rtx, Mmode); ...@@ -45,7 +45,8 @@ extern int effective_address_32bit_p (rtx, Mmode);
extern int symbolic_reference_mentioned_p (rtx); extern int symbolic_reference_mentioned_p (rtx);
extern rtx bfin_gen_compare (rtx, Mmode); extern rtx bfin_gen_compare (rtx, Mmode);
extern void expand_move (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 bool bfin_expand_strmov (rtx, rtx, rtx, rtx);
extern void conditional_register_usage (void); extern void conditional_register_usage (void);
......
...@@ -1146,7 +1146,7 @@ print_operand (FILE *file, rtx x, char code) ...@@ -1146,7 +1146,7 @@ print_operand (FILE *file, rtx x, char code)
*/ */
void void
init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED, init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
rtx libname ATTRIBUTE_UNUSED) rtx libname ATTRIBUTE_UNUSED)
{ {
static CUMULATIVE_ARGS zero_cum; static CUMULATIVE_ARGS zero_cum;
...@@ -1158,6 +1158,13 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED, ...@@ -1158,6 +1158,13 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype ATTRIBUTE_UNUSED,
cum->nregs = max_arg_registers; cum->nregs = max_arg_registers;
cum->arg_regs = arg_regs; 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; return;
} }
...@@ -1211,6 +1218,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type, ...@@ -1211,6 +1218,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
int bytes int bytes
= (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); = (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) if (bytes == -1)
return NULL_RTX; return NULL_RTX;
...@@ -1508,37 +1519,59 @@ split_di (rtx operands[], int num, rtx lo_half[], rtx hi_half[]) ...@@ -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. /* 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. */ SIBCALL is nonzero if this is a sibling call. */
void 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 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. */ /* Static functions and indirect calls don't need the pic register. */
if (flag_pic if (flag_pic
&& GET_CODE (XEXP (fnaddr, 0)) == SYMBOL_REF && GET_CODE (callee) == SYMBOL_REF
&& ! SYMBOL_REF_LOCAL_P (XEXP (fnaddr, 0))) && !SYMBOL_REF_LOCAL_P (callee))
use_reg (&use, pic_offset_table_rtx); 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)); callee = copy_to_mode_reg (Pmode, callee);
fnaddr = gen_rtx_MEM (Pmode, fnaddr); fnaddr = gen_rtx_MEM (Pmode, callee);
} }
call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1); call = gen_rtx_CALL (VOIDmode, fnaddr, callarg1);
if (retval) if (retval)
call = gen_rtx_SET (VOIDmode, retval, call); call = gen_rtx_SET (VOIDmode, retval, call);
XVECEXP (pat, 0, 0) = call;
XVECEXP (pat, 0, 1) = gen_rtx_USE (VOIDmode, cookie);
if (sibcall) if (sibcall)
{ XVECEXP (pat, 0, 2) = gen_rtx_RETURN (VOIDmode);
rtx pat = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2)); call = emit_call_insn (pat);
XVECEXP (pat, 0, 0) = call;
XVECEXP (pat, 0, 1) = gen_rtx_RETURN (VOIDmode);
call = pat;
}
call = emit_call_insn (call);
if (use) if (use)
CALL_INSN_FUNCTION_USAGE (call) = use; CALL_INSN_FUNCTION_USAGE (call) = use;
} }
...@@ -2668,9 +2701,44 @@ bfin_comp_type_attributes (tree type1, tree type2) ...@@ -2668,9 +2701,44 @@ bfin_comp_type_attributes (tree type1, tree type2)
!= !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2))) != !lookup_attribute ("kspisusp", TYPE_ATTRIBUTES (type2)))
return 0; return 0;
if (!lookup_attribute ("longcall", TYPE_ATTRIBUTES (type1))
!= !lookup_attribute ("longcall", TYPE_ATTRIBUTES (type2)))
return 0;
return 1; 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. */ /* Table of valid machine attributes. */
const struct attribute_spec bfin_attribute_table[] = const struct attribute_spec bfin_attribute_table[] =
{ {
...@@ -2681,6 +2749,8 @@ 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 }, { "nesting", 0, 0, false, true, true, NULL },
{ "kspisusp", 0, 0, false, true, true, NULL }, { "kspisusp", 0, 0, false, true, true, NULL },
{ "saveall", 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 } { NULL, 0, 0, false, false, false, NULL }
}; };
......
...@@ -530,10 +530,16 @@ typedef enum { ...@@ -530,10 +530,16 @@ typedef enum {
#define FUNCTION_ARG_REGISTERS { REG_R0, REG_R1, REG_R2, -1 } #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 { typedef struct {
int words; /* # words passed so far */ int words; /* # words passed so far */
int nregs; /* # registers available for passing */ int nregs; /* # registers available for passing */
int *arg_regs; /* array of register -1 terminated */ int *arg_regs; /* array of register -1 terminated */
int call_cookie; /* Do special things for this call */
} CUMULATIVE_ARGS; } CUMULATIVE_ARGS;
/* Define where to put the arguments to a function. /* Define where to put the arguments to a function.
......
...@@ -1304,80 +1304,140 @@ ...@@ -1304,80 +1304,140 @@
;; Call instructions.. ;; Call instructions..
(define_expand "call" (define_expand "call"
[(call (match_operand:SI 0 "" "") [(parallel [(call (match_operand:SI 0 "" "")
(match_operand 1 "" ""))] (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" (define_expand "sibcall"
[(parallel [(call (match_operand:SI 0 "" "") [(parallel [(call (match_operand:SI 0 "" "")
(match_operand 1 "" "")) (match_operand 1 "" ""))
(use (match_operand 2 "" ""))
(return)])] (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" (define_expand "call_value"
[(set (match_operand 0 "register_operand" "") [(parallel [(set (match_operand 0 "register_operand" "")
(call (match_operand:SI 1 "" "") (call (match_operand:SI 1 "" "")
(match_operand 2 "" "")))] (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" (define_expand "sibcall_value"
[(parallel [(set (match_operand 0 "register_operand" "") [(parallel [(set (match_operand 0 "register_operand" "")
(call (match_operand:SI 1 "" "") (call (match_operand:SI 1 "" "")
(match_operand 2 "" ""))) (match_operand 2 "" "")))
(use (match_operand 3 "" ""))
(return)])] (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" (define_insn "*call_symbol"
[(call (mem:SI (match_operand:SI 0 "call_insn_operand" "a,Q")) [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q"))
(match_operand 1 "general_operand" "g,g"))] (match_operand 1 "general_operand" "g"))
(use (match_operand 2 "" ""))]
"! SIBLING_CALL_P (insn) "! SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)" && !flag_pic
"@ && GET_CODE (operands[0]) == SYMBOL_REF
call (%0); && !bfin_longcall_p (operands[0], INTVAL (operands[2]))"
call %G0;" "call %G0;"
[(set_attr "type" "call") [(set_attr "type" "call")
(set_attr "length" "2,4")]) (set_attr "length" "4")])
(define_insn "*sibcall_insn" (define_insn "*sibcall_symbol"
[(call (mem:SI (match_operand:SI 0 "call_insn_operand" "z,Q")) [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "Q"))
(match_operand 1 "general_operand" "g,g")) (match_operand 1 "general_operand" "g"))
(use (match_operand 2 "" ""))
(return)] (return)]
"SIBLING_CALL_P (insn) "SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)" && !flag_pic
"@ && GET_CODE (operands[0]) == SYMBOL_REF
jump (%0); && !bfin_longcall_p (operands[0], INTVAL (operands[2]))"
jump.l %G0;" "jump.l %G0;"
[(set_attr "type" "br") [(set_attr "type" "br")
(set_attr "length" "2,4")]) (set_attr "length" "4")])
(define_insn "*call_value_insn" (define_insn "*call_value_symbol"
[(set (match_operand 0 "register_operand" "=d,d") [(set (match_operand 0 "register_operand" "=d")
(call (mem:SI (match_operand:SI 1 "call_insn_operand" "a,Q")) (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q"))
(match_operand 2 "general_operand" "g,g")))] (match_operand 2 "general_operand" "g")))
(use (match_operand 3 "" ""))]
"! SIBLING_CALL_P (insn) "! SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)" && !flag_pic
"@ && GET_CODE (operands[1]) == SYMBOL_REF
call (%1); && !bfin_longcall_p (operands[1], INTVAL (operands[3]))"
call %G1;" "call %G1;"
[(set_attr "type" "call") [(set_attr "type" "call")
(set_attr "length" "2,4")]) (set_attr "length" "4")])
(define_insn "*sibcall_value_insn" (define_insn "*sibcall_value_symbol"
[(set (match_operand 0 "register_operand" "=d,d") [(set (match_operand 0 "register_operand" "=d")
(call (mem:SI (match_operand:SI 1 "call_insn_operand" "z,Q")) (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "Q"))
(match_operand 2 "general_operand" "g,g"))) (match_operand 2 "general_operand" "g")))
(use (match_operand 3 "" ""))
(return)] (return)]
"SIBLING_CALL_P (insn) "SIBLING_CALL_P (insn)
&& (GET_CODE (operands[0]) == SYMBOL_REF || GET_CODE (operands[0]) == REG)" && !flag_pic
"@ && GET_CODE (operands[1]) == SYMBOL_REF
jump (%1); && !bfin_longcall_p (operands[1], INTVAL (operands[3]))"
jump.l %G1;" "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 "type" "br")
(set_attr "length" "2,4")]) (set_attr "length" "2")])
;; Block move patterns ;; Block move patterns
......
...@@ -106,6 +106,10 @@ ...@@ -106,6 +106,10 @@
(ior (match_code "const_int,const_double") (ior (match_code "const_int,const_double")
(match_operand 0 "symbolic_operand"))) (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 ;; 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. ;; instantiation of such a register may cause the pattern to not be recognized.
(define_predicate "register_no_elim_operand" (define_predicate "register_no_elim_operand"
...@@ -119,14 +123,6 @@ ...@@ -119,14 +123,6 @@
&& REGNO (op) <= LAST_VIRTUAL_REGISTER)); && 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 ;; Test for an operator valid in a conditional branch
(define_predicate "bfin_cbranch_operator" (define_predicate "bfin_cbranch_operator"
(match_code "eq,ne")) (match_code "eq,ne"))
...@@ -1932,12 +1932,12 @@ instruction directly. ...@@ -1932,12 +1932,12 @@ instruction directly.
@item longcall/shortcall @item longcall/shortcall
@cindex functions called via pointer on the RS/6000 and PowerPC @cindex functions called via pointer on the RS/6000 and PowerPC
On the RS/6000 and PowerPC, the @code{longcall} attribute causes the On the Blackfin, RS/6000 and PowerPC, the @code{longcall} attribute causes
compiler to always call this function via a pointer, just as it would if 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} the @option{-mlongcall} option had been specified. The @code{shortcall}
attribute causes the compiler not to do this. These attributes override attribute causes the compiler not to do this. These attributes override
both the @option{-mlongcall} switch and the @code{#pragma longcall} both the @option{-mlongcall} switch and, on the RS/6000 and PowerPC, the
setting. @code{#pragma longcall} setting.
@xref{RS/6000 and PowerPC Options}, for more information on whether long @xref{RS/6000 and PowerPC Options}, for more information on whether long
calls are necessary. calls are necessary.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment