Commit 25a65198 by Richard Sandiford Committed by Richard Sandiford

arm-protos.h (arm_encode_call_attribute): Delete.

gcc/
	* config/arm/arm-protos.h (arm_encode_call_attribute): Delete.
	(arm_is_longcall_p): Rename to...
	(arm_is_long_call_p): ...this.  Take a single tree argument and
	return a bool.
	* config/arm/arm.h (CALL_SHORT, CALL_LONG, CALL_NORMAL): Delete.
	(CUMULATIVE_ARGS): Remove call_cookie.
	(SHORT_CALL_FLAG_CHAR, LONG_CALL_FLAG_CHAR, ENCODED_SHORT_CALL_ATTR_P)
	(ENCODED_LONG_CALL_ATTR_P): Delete.
	(ARM_NAME_ENCODING_LENGTHS): Remove SHORT_CALL_FLAG_CHAR and
	LONG_CALL_FLAG_CHAR cases.
	(ARM_DECLARE_FUNCTION_SIZE): Delete.
	* config/arm/elf.h (ASM_DECLARE_FUNCTION_SIZE): Don't use
	ARM_DECLARE_FUNCTION_SIZE.
	* config/arm/arm.c (arm_init_cumulative_args): Don't set call_cookie.
	(arm_function_arg): Return const0_rtx for VOIDmode arguments.
	(arm_encode_call_attribute, current_file_function_operand): Delete.
	(arm_function_in_section_p): New function.
	(arm_is_longcall_p): Rename to...
	(arm_is_long_call_p): ...this.  Take the target function as a single
	argument and return a bool.  Do not rely on call cookies.  Check
	whether the target symbol is in the same section as the current
	function, not just the same compilation unit.
	(arm_function_ok_for_sibcall): Use arm_is_long_call_p.
	(arm_encode_section_info): Don't encode a call type.
	* config/arm/arm.md (call, call_value): Update calls to
	arm_is_long(_)call_p.  Simplify logic.
	(*call_symbol, *call_value_symbol, *call_insn, *call_value_insn):
	Update calls to arm_is_long(_)call_p.

gcc/testsuite/
	* gcc.target/arm/long-calls-1.c: New test.
	* gcc.target/arm/long-calls-2.c: Likewise.
	* gcc.target/arm/long-calls-3.c: Likewise.
	* gcc.target/arm/long-calls-4.c: Likewise.

From-SVN: r125060
parent aaee3e89
2007-05-25 Richard Sandiford <richard@codesourcery.com>
* config/arm/arm-protos.h (arm_encode_call_attribute): Delete.
(arm_is_longcall_p): Rename to...
(arm_is_long_call_p): ...this. Take a single tree argument and
return a bool.
* config/arm/arm.h (CALL_SHORT, CALL_LONG, CALL_NORMAL): Delete.
(CUMULATIVE_ARGS): Remove call_cookie.
(SHORT_CALL_FLAG_CHAR, LONG_CALL_FLAG_CHAR, ENCODED_SHORT_CALL_ATTR_P)
(ENCODED_LONG_CALL_ATTR_P): Delete.
(ARM_NAME_ENCODING_LENGTHS): Remove SHORT_CALL_FLAG_CHAR and
LONG_CALL_FLAG_CHAR cases.
(ARM_DECLARE_FUNCTION_SIZE): Delete.
* config/arm/elf.h (ASM_DECLARE_FUNCTION_SIZE): Don't use
ARM_DECLARE_FUNCTION_SIZE.
* config/arm/arm.c (arm_init_cumulative_args): Don't set call_cookie.
(arm_function_arg): Return const0_rtx for VOIDmode arguments.
(arm_encode_call_attribute, current_file_function_operand): Delete.
(arm_function_in_section_p): New function.
(arm_is_longcall_p): Rename to...
(arm_is_long_call_p): ...this. Take the target function as a single
argument and return a bool. Do not rely on call cookies. Check
whether the target symbol is in the same section as the current
function, not just the same compilation unit.
(arm_function_ok_for_sibcall): Use arm_is_long_call_p.
(arm_encode_section_info): Don't encode a call type.
* config/arm/arm.md (call, call_value): Update calls to
arm_is_long(_)call_p. Simplify logic.
(*call_symbol, *call_value_symbol, *call_insn, *call_value_insn):
Update calls to arm_is_long(_)call_p.
2007-05-25 Richard Guenther <rguenther@suse.de> 2007-05-25 Richard Guenther <rguenther@suse.de>
PR tree-optimization/31982 PR tree-optimization/31982
......
...@@ -45,7 +45,6 @@ extern void arm_output_fn_unwind (FILE *, bool); ...@@ -45,7 +45,6 @@ extern void arm_output_fn_unwind (FILE *, bool);
#ifdef TREE_CODE #ifdef TREE_CODE
extern int arm_return_in_memory (tree); extern int arm_return_in_memory (tree);
extern void arm_encode_call_attribute (tree, int);
#endif #endif
#ifdef RTX_CODE #ifdef RTX_CODE
extern bool arm_vector_mode_supported_p (enum machine_mode); extern bool arm_vector_mode_supported_p (enum machine_mode);
...@@ -121,7 +120,7 @@ extern void arm_print_operand (FILE *, rtx, int); ...@@ -121,7 +120,7 @@ extern void arm_print_operand (FILE *, rtx, int);
extern void arm_print_operand_address (FILE *, rtx); extern void arm_print_operand_address (FILE *, rtx);
extern void arm_final_prescan_insn (rtx); extern void arm_final_prescan_insn (rtx);
extern int arm_debugger_arg_offset (int, rtx); extern int arm_debugger_arg_offset (int, rtx);
extern int arm_is_longcall_p (rtx, int, int); extern bool arm_is_long_call_p (tree);
extern int arm_emit_vector_const (FILE *, rtx); extern int arm_emit_vector_const (FILE *, rtx);
extern const char * arm_output_load_gr (rtx *); extern const char * arm_output_load_gr (rtx *);
extern const char *vfp_output_fstmd (rtx *); extern const char *vfp_output_fstmd (rtx *);
......
...@@ -104,7 +104,6 @@ static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode, ...@@ -104,7 +104,6 @@ static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
rtx); rtx);
static void arm_reorg (void); static void arm_reorg (void);
static bool note_invalid_constants (rtx, HOST_WIDE_INT, int); static bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
static int current_file_function_operand (rtx);
static unsigned long arm_compute_save_reg0_reg12_mask (void); static unsigned long arm_compute_save_reg0_reg12_mask (void);
static unsigned long arm_compute_save_reg_mask (void); static unsigned long arm_compute_save_reg_mask (void);
static unsigned long arm_isr_value (tree); static unsigned long arm_isr_value (tree);
...@@ -2782,21 +2781,6 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype, ...@@ -2782,21 +2781,6 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
pcum->iwmmxt_nregs = 0; pcum->iwmmxt_nregs = 0;
pcum->can_split = true; pcum->can_split = true;
pcum->call_cookie = CALL_NORMAL;
if (TARGET_LONG_CALLS)
pcum->call_cookie = CALL_LONG;
/* Check for long call/short call attributes. The attributes
override any command line option. */
if (fntype)
{
if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
pcum->call_cookie = CALL_SHORT;
else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
pcum->call_cookie = CALL_LONG;
}
/* Varargs vectors are treated the same as long long. /* Varargs vectors are treated the same as long long.
named_count avoids having to change the way arm handles 'named' */ named_count avoids having to change the way arm handles 'named' */
pcum->named_count = 0; pcum->named_count = 0;
...@@ -2867,8 +2851,8 @@ arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode, ...@@ -2867,8 +2851,8 @@ arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
pcum->nregs++; pcum->nregs++;
if (mode == VOIDmode) if (mode == VOIDmode)
/* Compute operand 2 of the call insn. */ /* Pick an arbitrary value for operand 2 of the call insn. */
return GEN_INT (pcum->call_cookie); return const0_rtx;
/* Only allow splitting an arg between regs and memory if all preceding /* Only allow splitting an arg between regs and memory if all preceding
args were allocated to regs. For args passed by reference we only count args were allocated to regs. For args passed by reference we only count
...@@ -3121,27 +3105,6 @@ arm_comp_type_attributes (tree type1, tree type2) ...@@ -3121,27 +3105,6 @@ arm_comp_type_attributes (tree type1, tree type2)
return 1; return 1;
} }
/* Encode long_call or short_call attribute by prefixing
symbol name in DECL with a special character FLAG. */
void
arm_encode_call_attribute (tree decl, int flag)
{
const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
int len = strlen (str);
char * newstr;
/* Do not allow weak functions to be treated as short call. */
if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
return;
newstr = alloca (len + 2);
newstr[0] = flag;
strcpy (newstr + 1, str);
newstr = (char *) ggc_alloc_string (newstr, len + 1);
XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
}
/* Assigns default attributes to newly defined type. This is used to /* Assigns default attributes to newly defined type. This is used to
set short_call/long_call attributes for function types of set short_call/long_call attributes for function types of
functions defined inside corresponding #pragma scopes. */ functions defined inside corresponding #pragma scopes. */
...@@ -3168,92 +3131,79 @@ arm_set_default_type_attributes (tree type) ...@@ -3168,92 +3131,79 @@ arm_set_default_type_attributes (tree type)
} }
} }
/* Return 1 if the operand is a SYMBOL_REF for a function known to be /* Return true if DECL is known to be linked into section SECTION. */
defined within the current compilation unit. If this cannot be
determined, then 0 is returned. */ static bool
static int arm_function_in_section_p (tree decl, section *section)
current_file_function_operand (rtx sym_ref)
{ {
/* This is a bit of a fib. A function will have a short call flag /* We can only be certain about functions defined in the same
applied to its name if it has the short call attribute, or it has compilation unit. */
already been defined within the current compilation unit. */ if (!TREE_STATIC (decl))
if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0))) return false;
return 1;
/* The current function is always defined within the current compilation /* Make sure that SYMBOL always binds to the definition in this
unit. If it s a weak definition however, then this may not be the real compilation unit. */
definition of the function, and so we have to say no. */ if (!targetm.binds_local_p (decl))
if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0) return false;
&& !DECL_WEAK (current_function_decl))
return 1;
/* We cannot make the determination - default to returning 0. */ /* If DECL_SECTION_NAME is set, assume it is trustworthy. */
return 0; if (!DECL_SECTION_NAME (decl))
{
/* Only cater for unit-at-a-time mode, where we know that the user
cannot later specify a section for DECL. */
if (!flag_unit_at_a_time)
return false;
/* Make sure that we will not create a unique section for DECL. */
if (flag_function_sections || DECL_ONE_ONLY (decl))
return false;
}
return function_section (decl) == section;
} }
/* Return nonzero if a 32-bit "long_call" should be generated for /* Return nonzero if a 32-bit "long_call" should be generated for
this call. We generate a long_call if the function: a call from the current function to DECL. We generate a long_call
if the function:
a. has an __attribute__((long call)) a. has an __attribute__((long call))
or b. is within the scope of a #pragma long_calls or b. is within the scope of a #pragma long_calls
or c. the -mlong-calls command line switch has been specified or c. the -mlong-calls command line switch has been specified
. and either:
1. -ffunction-sections is in effect
or 2. the current function has __attribute__ ((section))
or 3. the target function has __attribute__ ((section))
However we do not generate a long call if the function: However we do not generate a long call if the function:
d. has an __attribute__ ((short_call)) d. has an __attribute__ ((short_call))
or e. is inside the scope of a #pragma no_long_calls or e. is inside the scope of a #pragma no_long_calls
or f. is defined within the current compilation unit. or f. is defined in the same section as the current function. */
This function will be called by C fragments contained in the machine
description file. SYM_REF and CALL_COOKIE correspond to the matched
rtl operands. CALL_SYMBOL is used to distinguish between
two different callers of the function. It is set to 1 in the
"call_symbol" and "call_symbol_value" patterns and to 0 in the "call"
and "call_value" patterns. This is because of the difference in the
SYM_REFs passed by these patterns. */
int
arm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
{
if (!call_symbol)
{
if (GET_CODE (sym_ref) != MEM)
return 0;
sym_ref = XEXP (sym_ref, 0); bool
} arm_is_long_call_p (tree decl)
{
tree attrs;
if (GET_CODE (sym_ref) != SYMBOL_REF) if (!decl)
return 0; return TARGET_LONG_CALLS;
if (call_cookie & CALL_SHORT) attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
return 0; if (lookup_attribute ("short_call", attrs))
return false;
if (TARGET_LONG_CALLS) /* For "f", be conservative, and only cater for cases in which the
{ whole of the current function is placed in the same section. */
if (flag_function_sections if (!flag_reorder_blocks_and_partition
|| DECL_SECTION_NAME (current_function_decl)) && arm_function_in_section_p (decl, current_function_section ()))
/* c.3 is handled by the definition of the return false;
ARM_DECLARE_FUNCTION_SIZE macro. */
return 1;
}
if (current_file_function_operand (sym_ref)) if (lookup_attribute ("long_call", attrs))
return 0; return true;
return (call_cookie & CALL_LONG) return TARGET_LONG_CALLS;
|| ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
|| TARGET_LONG_CALLS;
} }
/* Return nonzero if it is ok to make a tail-call to DECL. */ /* Return nonzero if it is ok to make a tail-call to DECL. */
static bool static bool
arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
{ {
int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
unsigned long func_type; unsigned long func_type;
if (cfun->machine->sibcall_blocked) if (cfun->machine->sibcall_blocked)
...@@ -3264,16 +3214,9 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED) ...@@ -3264,16 +3214,9 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
if (decl == NULL || TARGET_THUMB) if (decl == NULL || TARGET_THUMB)
return false; return false;
/* Get the calling method. */
if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
call_type = CALL_SHORT;
else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
call_type = CALL_LONG;
/* Cannot tail-call to long calls, since these are out of range of /* Cannot tail-call to long calls, since these are out of range of
a branch instruction. However, if not compiling PIC, we know a branch instruction. */
we can reach the symbol if it is in this compilation unit. */ if (arm_is_long_call_p (decl))
if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
return false; return false;
/* If we are interworking and the function is not declared static /* If we are interworking and the function is not declared static
...@@ -15603,17 +15546,6 @@ arm_encode_section_info (tree decl, rtx rtl, int first) ...@@ -15603,17 +15546,6 @@ arm_encode_section_info (tree decl, rtx rtl, int first)
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
#endif #endif
/* If we are referencing a function that is weak then encode a long call
flag in the function name, otherwise if the function is static or
or known to be defined in this file then encode a short call flag. */
if (first && DECL_P (decl))
{
if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
else if (! TREE_PUBLIC (decl))
arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
}
default_encode_section_info (decl, rtl, first); default_encode_section_info (decl, rtl, first);
} }
#endif /* !ARM_PE */ #endif /* !ARM_PE */
......
...@@ -1368,11 +1368,6 @@ do { \ ...@@ -1368,11 +1368,6 @@ do { \
than a word, or if they contain elements offset from zero in the struct. */ than a word, or if they contain elements offset from zero in the struct. */
#define DEFAULT_PCC_STRUCT_RETURN 0 #define DEFAULT_PCC_STRUCT_RETURN 0
/* 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 /* Never call indirect. */
/* These bits describe the different types of function supported /* These bits describe the different types of function supported
by the ARM backend. They are exclusive. i.e. a function cannot be both a by the ARM backend. They are exclusive. i.e. a function cannot be both a
normal function and an interworked function, for example. Knowing the normal function and an interworked function, for example. Knowing the
...@@ -1471,8 +1466,6 @@ typedef struct ...@@ -1471,8 +1466,6 @@ typedef struct
int iwmmxt_nregs; int iwmmxt_nregs;
int named_count; int named_count;
int nargs; int nargs;
/* One of CALL_NORMAL, CALL_LONG or CALL_SHORT. */
int call_cookie;
int can_split; int can_split;
} CUMULATIVE_ARGS; } CUMULATIVE_ARGS;
...@@ -1853,18 +1846,6 @@ typedef struct ...@@ -1853,18 +1846,6 @@ typedef struct
&& (TARGET_32BIT ? ARM_LEGITIMATE_CONSTANT_P (X) \ && (TARGET_32BIT ? ARM_LEGITIMATE_CONSTANT_P (X) \
: THUMB_LEGITIMATE_CONSTANT_P (X))) : THUMB_LEGITIMATE_CONSTANT_P (X)))
/* Special characters prefixed to function names
in order to encode attribute like information.
Note, '@' and '*' have already been taken. */
#define SHORT_CALL_FLAG_CHAR '^'
#define LONG_CALL_FLAG_CHAR '#'
#define ENCODED_SHORT_CALL_ATTR_P(SYMBOL_NAME) \
(*(SYMBOL_NAME) == SHORT_CALL_FLAG_CHAR)
#define ENCODED_LONG_CALL_ATTR_P(SYMBOL_NAME) \
(*(SYMBOL_NAME) == LONG_CALL_FLAG_CHAR)
#ifndef SUBTARGET_NAME_ENCODING_LENGTHS #ifndef SUBTARGET_NAME_ENCODING_LENGTHS
#define SUBTARGET_NAME_ENCODING_LENGTHS #define SUBTARGET_NAME_ENCODING_LENGTHS
#endif #endif
...@@ -1874,8 +1855,6 @@ typedef struct ...@@ -1874,8 +1855,6 @@ typedef struct
be stripped from the start of a function's name, if that be stripped from the start of a function's name, if that
name starts with the indicated character. */ name starts with the indicated character. */
#define ARM_NAME_ENCODING_LENGTHS \ #define ARM_NAME_ENCODING_LENGTHS \
case SHORT_CALL_FLAG_CHAR: return 1; \
case LONG_CALL_FLAG_CHAR: return 1; \
case '*': return 1; \ case '*': return 1; \
SUBTARGET_NAME_ENCODING_LENGTHS SUBTARGET_NAME_ENCODING_LENGTHS
...@@ -1942,15 +1921,6 @@ typedef struct ...@@ -1942,15 +1921,6 @@ typedef struct
#define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P true #define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P true
#endif #endif
/* Set the short-call flag for any function compiled in the current
compilation unit. We skip this for functions with the section
attribute when long-calls are in effect as this tells the compiler
that the section might be placed a long way from the caller.
See arm_is_longcall_p() for more information. */
#define ARM_DECLARE_FUNCTION_SIZE(STREAM, NAME, DECL) \
if (!TARGET_LONG_CALLS || ! DECL_SECTION_NAME (DECL)) \
arm_encode_call_attribute (DECL, SHORT_CALL_FLAG_CHAR)
#define ARM_OUTPUT_FN_UNWIND(F, PROLOGUE) arm_output_fn_unwind (F, PROLOGUE) #define ARM_OUTPUT_FN_UNWIND(F, PROLOGUE) arm_output_fn_unwind (F, PROLOGUE)
#ifdef TARGET_UNWIND_INFO #ifdef TARGET_UNWIND_INFO
......
...@@ -8151,22 +8151,13 @@ ...@@ -8151,22 +8151,13 @@
if (operands[2] == NULL_RTX) if (operands[2] == NULL_RTX)
operands[2] = const0_rtx; operands[2] = const0_rtx;
/* This is to decide if we should generate indirect calls by loading the /* Decide if we should generate indirect calls by loading the
32-bit address of the callee into a register before performing the 32-bit address of the callee into a register before performing the
branch and link. operand[2] encodes the long_call/short_call branch and link. */
attribute of the function being called. This attribute is set whenever callee = XEXP (operands[0], 0);
__attribute__((long_call/short_call)) or #pragma long_call/no_long_call if (GET_CODE (callee) == SYMBOL_REF
is used, and the short_call attribute can also be set if function is ? arm_is_long_call_p (SYMBOL_REF_DECL (callee))
declared as static or if it has already been defined in the current : !REG_P (callee))
compilation unit. See arm.c and arm.h for info about this. The third
parameter to arm_is_longcall_p is used to tell it which pattern
invoked it. */
callee = XEXP (operands[0], 0);
if ((GET_CODE (callee) == SYMBOL_REF
&& arm_is_longcall_p (operands[0], INTVAL (operands[2]), 0))
|| (GET_CODE (callee) != SYMBOL_REF
&& GET_CODE (callee) != REG))
XEXP (operands[0], 0) = force_reg (Pmode, callee); XEXP (operands[0], 0) = force_reg (Pmode, callee);
}" }"
) )
...@@ -8248,17 +8239,19 @@ ...@@ -8248,17 +8239,19 @@
"TARGET_EITHER" "TARGET_EITHER"
" "
{ {
rtx callee = XEXP (operands[1], 0); rtx callee;
/* In an untyped call, we can get NULL for operand 2. */ /* In an untyped call, we can get NULL for operand 2. */
if (operands[3] == 0) if (operands[3] == 0)
operands[3] = const0_rtx; operands[3] = const0_rtx;
/* See the comment in define_expand \"call\". */ /* Decide if we should generate indirect calls by loading the
if ((GET_CODE (callee) == SYMBOL_REF 32-bit address of the callee into a register before performing the
&& arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0)) branch and link. */
|| (GET_CODE (callee) != SYMBOL_REF callee = XEXP (operands[1], 0);
&& GET_CODE (callee) != REG)) if (GET_CODE (callee) == SYMBOL_REF
? arm_is_long_call_p (SYMBOL_REF_DECL (callee))
: !REG_P (callee))
XEXP (operands[1], 0) = force_reg (Pmode, callee); XEXP (operands[1], 0) = force_reg (Pmode, callee);
}" }"
) )
...@@ -8345,7 +8338,7 @@ ...@@ -8345,7 +8338,7 @@
(clobber (reg:SI LR_REGNUM))] (clobber (reg:SI LR_REGNUM))]
"TARGET_ARM "TARGET_ARM
&& (GET_CODE (operands[0]) == SYMBOL_REF) && (GET_CODE (operands[0]) == SYMBOL_REF)
&& !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
"* "*
{ {
return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\"; return NEED_PLT_RELOC ? \"bl%?\\t%a0(PLT)\" : \"bl%?\\t%a0\";
...@@ -8361,7 +8354,7 @@ ...@@ -8361,7 +8354,7 @@
(clobber (reg:SI LR_REGNUM))] (clobber (reg:SI LR_REGNUM))]
"TARGET_ARM "TARGET_ARM
&& (GET_CODE (operands[1]) == SYMBOL_REF) && (GET_CODE (operands[1]) == SYMBOL_REF)
&& !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
"* "*
{ {
return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\"; return NEED_PLT_RELOC ? \"bl%?\\t%a1(PLT)\" : \"bl%?\\t%a1\";
...@@ -8376,7 +8369,7 @@ ...@@ -8376,7 +8369,7 @@
(clobber (reg:SI LR_REGNUM))] (clobber (reg:SI LR_REGNUM))]
"TARGET_THUMB "TARGET_THUMB
&& GET_CODE (operands[0]) == SYMBOL_REF && GET_CODE (operands[0]) == SYMBOL_REF
&& !arm_is_longcall_p (operands[0], INTVAL (operands[2]), 1)" && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[0]))"
"bl\\t%a0" "bl\\t%a0"
[(set_attr "length" "4") [(set_attr "length" "4")
(set_attr "type" "call")] (set_attr "type" "call")]
...@@ -8390,7 +8383,7 @@ ...@@ -8390,7 +8383,7 @@
(clobber (reg:SI LR_REGNUM))] (clobber (reg:SI LR_REGNUM))]
"TARGET_THUMB "TARGET_THUMB
&& GET_CODE (operands[1]) == SYMBOL_REF && GET_CODE (operands[1]) == SYMBOL_REF
&& !arm_is_longcall_p (operands[1], INTVAL (operands[3]), 1)" && !arm_is_long_call_p (SYMBOL_REF_DECL (operands[1]))"
"bl\\t%a1" "bl\\t%a1"
[(set_attr "length" "4") [(set_attr "length" "4")
(set_attr "type" "call")] (set_attr "type" "call")]
......
...@@ -87,7 +87,6 @@ ...@@ -87,7 +87,6 @@
do \ do \
{ \ { \
ARM_OUTPUT_FN_UNWIND (FILE, FALSE); \ ARM_OUTPUT_FN_UNWIND (FILE, FALSE); \
ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL); \
if (!flag_inhibit_size_directive) \ if (!flag_inhibit_size_directive) \
ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \ ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \
} \ } \
......
2007-05-25 Richard Sandiford <richard@codesourcery.com>
* gcc.target/arm/long-calls-1.c: New test.
* gcc.target/arm/long-calls-2.c: Likewise.
* gcc.target/arm/long-calls-3.c: Likewise.
* gcc.target/arm/long-calls-4.c: Likewise.
2007-05-25 Richard Guenther <rguenther@suse.de> 2007-05-25 Richard Guenther <rguenther@suse.de>
Andrew Pinski <andrew_pinski@playstation.sony.com> Andrew Pinski <andrew_pinski@playstation.sony.com>
/* Check that long calls to different sections are not optimized to "bl". */
/* { dg-do compile { target { arm32 && nonpic } } } */
/* { dg-options "-O2" } */
#define section(S) __attribute__((section(S)))
#define weak __attribute__((weak))
#define noinline __attribute__((noinline))
#define long_call __attribute__((long_call))
#define short_call __attribute__((short_call))
#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS ID (void); \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
static const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS) \
TEST (ID##1, TARGET_ATTRS, ) \
TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b")) \
TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call) \
DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
/* Calls to remote_* should honor the call type sttribute,
with "short" being the default. */
/* { dg-final { scan-assembler "\tbl\tremote_n1\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_n3\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l2\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s3\n" } } */
/* Calls to strong_*2 calls should honor the call type attribute,
with "short" being the default. Calls to other strong_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstrong_n1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n2\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_l1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_l3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s3\n" } } */
/* Calls to weak_* should honor the call type sttribute,
with "short" being the default. */
/* { dg-final { scan-assembler "\tbl\tweak_n1\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n1\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_n2\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_n3\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n3\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s3\n" } } */
/* Calls to static_*2 calls should honor the call type attribute,
with "short" being the default. Calls to other static_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstatic_n1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n2\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s3\n" } } */
/* Check that long calls to different sections are not optimized to "bl". */
/* { dg-do compile { target { arm32 && nonpic } } } */
/* { dg-options "-O2 -mlong-calls" } */
#define section(S) __attribute__((section(S)))
#define weak __attribute__((weak))
#define noinline __attribute__((noinline))
#define long_call __attribute__((long_call))
#define short_call __attribute__((short_call))
#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS ID (void); \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
static const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS) \
TEST (ID##1, TARGET_ATTRS, ) \
TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b")) \
TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call) \
DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
/* Calls to remote_* should honor the call type sttribute,
with "long" being the default. */
/* { dg-final { scan-assembler-not "\tbl\tremote_n1\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_n2\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_n3\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l2\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s3\n" } } */
/* Calls to strong_*2 calls should honor the call type attribute,
with "long" being the default. Calls to other strong_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstrong_n1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n1\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tstrong_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_l1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_l3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s3\n" } } */
/* Calls to weak_* should honor the call type sttribute,
with "long" being the default. */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n2\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n3\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s3\n" } } */
/* Calls to static_*2 calls should honor the call type attribute,
with "long" being the default. Calls to other static_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstatic_n1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_n2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l1\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l3\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s1\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s1\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s2\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s2\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s3\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s3\n" } } */
/* Check that long calls to different sections are not optimized to "bl". */
/* { dg-do compile { target { arm32 && fpic } } } */
/* { dg-options "-O2 -fpic" } */
#define section(S) __attribute__((section(S)))
#define weak __attribute__((weak))
#define noinline __attribute__((noinline))
#define long_call __attribute__((long_call))
#define short_call __attribute__((short_call))
#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS ID (void); \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
static const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS) \
TEST (ID##1, TARGET_ATTRS, ) \
TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b")) \
TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call) \
DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
/* Calls to remote_*, strong_* and weak_* should honor the call type
sttribute, with "short" being the default. */
/* { dg-final { scan-assembler "\tbl\tremote_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tstrong_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tstrong_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s3\\(PLT\\)\n" } } */
/* Calls to static_*2 calls should honor the call type attribute,
with "short" being the default. Calls to other static_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstatic_n1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s3(\\(PLT\\))\n" } } */
/* Check that long calls to different sections are not optimized to "bl". */
/* { dg-do compile { target { arm32 && fpic } } } */
/* { dg-options "-O2 -fpic -mlong-calls" } */
#define section(S) __attribute__((section(S)))
#define weak __attribute__((weak))
#define noinline __attribute__((noinline))
#define long_call __attribute__((long_call))
#define short_call __attribute__((short_call))
#define REMOTE_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS ID (void); \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; }
#define EXTERN_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define STATIC_CALL(ID, TARGET_ATTRS, CALL_ATTRS) \
static const char *TARGET_ATTRS noinline ID (void) { return #ID; } \
const char *CALL_ATTRS call_##ID (void) { return ID () + 1; } \
const char *CALL_ATTRS sibcall_##ID (void) { return ID (); }
#define DO_TESTS_SECTION(ID, TEST, TARGET_ATTRS) \
TEST (ID##1, TARGET_ATTRS, ) \
TEST (ID##2, TARGET_ATTRS section (".test.a"), section (".test.b")) \
TEST (ID##3, TARGET_ATTRS section (".test.c"), section (".test.c"))
#define DO_TESTS_CALL_ATTR(ID, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##n, TEST, TARGET_ATTRS) \
DO_TESTS_SECTION (ID##l, TEST, TARGET_ATTRS long_call) \
DO_TESTS_SECTION (ID##s, TEST, TARGET_ATTRS short_call)
DO_TESTS_CALL_ATTR (remote_, REMOTE_CALL,)
DO_TESTS_CALL_ATTR (strong_, EXTERN_CALL,)
DO_TESTS_CALL_ATTR (weak_, EXTERN_CALL, weak)
DO_TESTS_CALL_ATTR (static_, STATIC_CALL,)
/* Calls to remote_*, strong_* and weak_* should honor the call type
sttribute, with "long" being the default. */
/* { dg-final { scan-assembler-not "\tbl\tremote_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl\tremote_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tremote_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstrong_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tstrong_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tstrong_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_n3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tweak_l3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s1\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s2\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tbl\tweak_s3\\(PLT\\)\n" } } */
/* { dg-final { scan-assembler "\tb\tweak_s3\\(PLT\\)\n" } } */
/* Calls to static_*2 calls should honor the call type attribute,
with "long" being the default. Calls to other static_* functions
should be short. */
/* { dg-final { scan-assembler "\tbl\tstatic_n1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_n2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_n3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_n3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_l3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_l3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s1(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s2(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tbl\tstatic_s3(\\(PLT\\))\n" } } */
/* { dg-final { scan-assembler "\tb\tstatic_s3(\\(PLT\\))\n" } } */
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