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
This commit is contained in:
Richard Sandiford 2007-05-25 11:36:06 +00:00 committed by Richard Sandiford
parent aaee3e893d
commit 25a6519845
11 changed files with 580 additions and 175 deletions

View File

@ -1,3 +1,34 @@
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>
PR tree-optimization/31982

View File

@ -45,7 +45,6 @@ extern void arm_output_fn_unwind (FILE *, bool);
#ifdef TREE_CODE
extern int arm_return_in_memory (tree);
extern void arm_encode_call_attribute (tree, int);
#endif
#ifdef RTX_CODE
extern bool arm_vector_mode_supported_p (enum machine_mode);
@ -121,7 +120,7 @@ extern void arm_print_operand (FILE *, rtx, int);
extern void arm_print_operand_address (FILE *, rtx);
extern void arm_final_prescan_insn (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 const char * arm_output_load_gr (rtx *);
extern const char *vfp_output_fstmd (rtx *);

View File

@ -104,7 +104,6 @@ static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
rtx);
static void arm_reorg (void);
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_reg_mask (void);
static unsigned long arm_isr_value (tree);
@ -2782,21 +2781,6 @@ arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
pcum->iwmmxt_nregs = 0;
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.
named_count avoids having to change the way arm handles 'named' */
pcum->named_count = 0;
@ -2867,8 +2851,8 @@ arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
pcum->nregs++;
if (mode == VOIDmode)
/* Compute operand 2 of the call insn. */
return GEN_INT (pcum->call_cookie);
/* Pick an arbitrary value for operand 2 of the call insn. */
return const0_rtx;
/* 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
@ -3121,27 +3105,6 @@ arm_comp_type_attributes (tree type1, tree type2)
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
set short_call/long_call attributes for function types of
functions defined inside corresponding #pragma scopes. */
@ -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
defined within the current compilation unit. If this cannot be
determined, then 0 is returned. */
static int
current_file_function_operand (rtx sym_ref)
/* Return true if DECL is known to be linked into section SECTION. */
static bool
arm_function_in_section_p (tree decl, section *section)
{
/* This is a bit of a fib. A function will have a short call flag
applied to its name if it has the short call attribute, or it has
already been defined within the current compilation unit. */
if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
return 1;
/* We can only be certain about functions defined in the same
compilation unit. */
if (!TREE_STATIC (decl))
return false;
/* The current function is always defined within the current compilation
unit. If it s a weak definition however, then this may not be the real
definition of the function, and so we have to say no. */
if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
&& !DECL_WEAK (current_function_decl))
return 1;
/* Make sure that SYMBOL always binds to the definition in this
compilation unit. */
if (!targetm.binds_local_p (decl))
return false;
/* We cannot make the determination - default to returning 0. */
return 0;
/* If DECL_SECTION_NAME is set, assume it is trustworthy. */
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
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))
or b. is within the scope of a #pragma long_calls
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:
d. has an __attribute__ ((short_call))
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)
bool
arm_is_long_call_p (tree decl)
{
if (!call_symbol)
{
if (GET_CODE (sym_ref) != MEM)
return 0;
tree attrs;
sym_ref = XEXP (sym_ref, 0);
}
if (!decl)
return TARGET_LONG_CALLS;
if (GET_CODE (sym_ref) != SYMBOL_REF)
return 0;
attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl));
if (lookup_attribute ("short_call", attrs))
return false;
if (call_cookie & CALL_SHORT)
return 0;
/* 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_reorder_blocks_and_partition
&& arm_function_in_section_p (decl, current_function_section ()))
return false;
if (TARGET_LONG_CALLS)
{
if (flag_function_sections
|| DECL_SECTION_NAME (current_function_decl))
/* c.3 is handled by the definition of the
ARM_DECLARE_FUNCTION_SIZE macro. */
return 1;
}
if (lookup_attribute ("long_call", attrs))
return true;
if (current_file_function_operand (sym_ref))
return 0;
return (call_cookie & CALL_LONG)
|| ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
|| TARGET_LONG_CALLS;
return TARGET_LONG_CALLS;
}
/* Return nonzero if it is ok to make a tail-call to DECL. */
static bool
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;
if (cfun->machine->sibcall_blocked)
@ -3264,16 +3214,9 @@ arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
if (decl == NULL || TARGET_THUMB)
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
a branch instruction. However, if not compiling PIC, we know
we can reach the symbol if it is in this compilation unit. */
if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
a branch instruction. */
if (arm_is_long_call_p (decl))
return false;
/* 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)
SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
#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);
}
#endif /* !ARM_PE */

View File

@ -1368,11 +1368,6 @@ do { \
than a word, or if they contain elements offset from zero in the struct. */
#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
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
@ -1471,8 +1466,6 @@ typedef struct
int iwmmxt_nregs;
int named_count;
int nargs;
/* One of CALL_NORMAL, CALL_LONG or CALL_SHORT. */
int call_cookie;
int can_split;
} CUMULATIVE_ARGS;
@ -1853,18 +1846,6 @@ typedef struct
&& (TARGET_32BIT ? ARM_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
#define SUBTARGET_NAME_ENCODING_LENGTHS
#endif
@ -1874,8 +1855,6 @@ typedef struct
be stripped from the start of a function's name, if that
name starts with the indicated character. */
#define ARM_NAME_ENCODING_LENGTHS \
case SHORT_CALL_FLAG_CHAR: return 1; \
case LONG_CALL_FLAG_CHAR: return 1; \
case '*': return 1; \
SUBTARGET_NAME_ENCODING_LENGTHS
@ -1942,15 +1921,6 @@ typedef struct
#define TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P true
#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)
#ifdef TARGET_UNWIND_INFO

View File

@ -8151,22 +8151,13 @@
if (operands[2] == NULL_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
branch and link. operand[2] encodes the long_call/short_call
attribute of the function being called. This attribute is set whenever
__attribute__((long_call/short_call)) or #pragma long_call/no_long_call
is used, and the short_call attribute can also be set if function is
declared as static or if it has already been defined in the current
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))
branch and link. */
callee = XEXP (operands[0], 0);
if (GET_CODE (callee) == SYMBOL_REF
? arm_is_long_call_p (SYMBOL_REF_DECL (callee))
: !REG_P (callee))
XEXP (operands[0], 0) = force_reg (Pmode, callee);
}"
)
@ -8248,17 +8239,19 @@
"TARGET_EITHER"
"
{
rtx callee = XEXP (operands[1], 0);
rtx callee;
/* In an untyped call, we can get NULL for operand 2. */
if (operands[3] == 0)
operands[3] = const0_rtx;
/* See the comment in define_expand \"call\". */
if ((GET_CODE (callee) == SYMBOL_REF
&& arm_is_longcall_p (operands[1], INTVAL (operands[3]), 0))
|| (GET_CODE (callee) != SYMBOL_REF
&& GET_CODE (callee) != REG))
/* Decide if we should generate indirect calls by loading the
32-bit address of the callee into a register before performing the
branch and link. */
callee = XEXP (operands[1], 0);
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);
}"
)
@ -8345,7 +8338,7 @@
(clobber (reg:SI LR_REGNUM))]
"TARGET_ARM
&& (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\";
@ -8361,7 +8354,7 @@
(clobber (reg:SI LR_REGNUM))]
"TARGET_ARM
&& (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\";
@ -8376,7 +8369,7 @@
(clobber (reg:SI LR_REGNUM))]
"TARGET_THUMB
&& 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"
[(set_attr "length" "4")
(set_attr "type" "call")]
@ -8390,7 +8383,7 @@
(clobber (reg:SI LR_REGNUM))]
"TARGET_THUMB
&& 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"
[(set_attr "length" "4")
(set_attr "type" "call")]

View File

@ -87,7 +87,6 @@
do \
{ \
ARM_OUTPUT_FN_UNWIND (FILE, FALSE); \
ARM_DECLARE_FUNCTION_SIZE (FILE, FNAME, DECL); \
if (!flag_inhibit_size_directive) \
ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \
} \

View File

@ -1,3 +1,10 @@
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>
Andrew Pinski <andrew_pinski@playstation.sony.com>

View File

@ -0,0 +1,126 @@
/* 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" } } */

View File

@ -0,0 +1,121 @@
/* 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" } } */

View File

@ -0,0 +1,117 @@
/* 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" } } */

View File

@ -0,0 +1,110 @@
/* 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" } } */