diff options
author | Richard Sandiford <richard@codesourcery.com> | 2007-05-25 11:36:06 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2007-05-25 11:36:06 +0000 |
commit | 25a651984517d4d275aac921c97ff1e7eb986dda (patch) | |
tree | 32f0047c9c52a73554ca9691e5f1d307f3ff645f | |
parent | aaee3e893d94e72bc81464c88d8e739a0f220969 (diff) | |
download | gcc-25a651984517d4d275aac921c97ff1e7eb986dda.zip gcc-25a651984517d4d275aac921c97ff1e7eb986dda.tar.gz gcc-25a651984517d4d275aac921c97ff1e7eb986dda.tar.bz2 |
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
-rw-r--r-- | gcc/ChangeLog | 31 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 168 | ||||
-rw-r--r-- | gcc/config/arm/arm.h | 30 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 43 | ||||
-rw-r--r-- | gcc/config/arm/elf.h | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/long-calls-1.c | 126 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/long-calls-2.c | 121 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/long-calls-3.c | 117 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/arm/long-calls-4.c | 110 |
11 files changed, 581 insertions, 176 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2342dad..bebad9a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index 9d24cd2..d9ec19a 100644 --- a/gcc/config/arm/arm-protos.h +++ b/gcc/config/arm/arm-protos.h @@ -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 *); diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index c6b06da..dd75551 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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. - - 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; + or f. is defined in the same section as the current function. */ - sym_ref = XEXP (sym_ref, 0); - } +bool +arm_is_long_call_p (tree decl) +{ + tree attrs; - if (GET_CODE (sym_ref) != SYMBOL_REF) - return 0; + if (!decl) + return TARGET_LONG_CALLS; - if (call_cookie & CALL_SHORT) - return 0; + attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + if (lookup_attribute ("short_call", attrs)) + 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; - } + /* 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 (current_file_function_operand (sym_ref)) - return 0; + if (lookup_attribute ("long_call", attrs)) + return true; - 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 */ diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index d09bb73..e73b576 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -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 diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 37bfe88..2ae732a 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -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")] diff --git a/gcc/config/arm/elf.h b/gcc/config/arm/elf.h index 89584ce..bce5ad6 100644 --- a/gcc/config/arm/elf.h +++ b/gcc/config/arm/elf.h @@ -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); \ } \ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c0cbf9b..499acb2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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> diff --git a/gcc/testsuite/gcc.target/arm/long-calls-1.c b/gcc/testsuite/gcc.target/arm/long-calls-1.c new file mode 100644 index 0000000..7c2e7fe --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/long-calls-1.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.target/arm/long-calls-2.c b/gcc/testsuite/gcc.target/arm/long-calls-2.c new file mode 100644 index 0000000..c63f8ab --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/long-calls-2.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.target/arm/long-calls-3.c b/gcc/testsuite/gcc.target/arm/long-calls-3.c new file mode 100644 index 0000000..9281715 --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/long-calls-3.c @@ -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" } } */ diff --git a/gcc/testsuite/gcc.target/arm/long-calls-4.c b/gcc/testsuite/gcc.target/arm/long-calls-4.c new file mode 100644 index 0000000..facf85c --- /dev/null +++ b/gcc/testsuite/gcc.target/arm/long-calls-4.c @@ -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" } } */ |