On 18/11/14 12:51, Yangfei (Felix) wrote:
On Tue, Nov 18, 2014 at 11:51 AM, Yangfei (Felix) <felix.y...@huawei.com> wrote:Ping again? Any comment please?Pinging daily is only going to irritate people. Please desist from doing so. RamanaOh, thanks for reminding me. And sorry if this bothers you guys. The end of stage1 of GCC 5.0 causes me to push this a little bit :-)
You've posted this patch before stage1 closed. In any case IIRC the policy in the contribute pages used to suggest a weekly ping.
Ramana
Ping? I hope this patch can catch up with stage 1 of GCC-5.0. Thanks.Hi Felix, Sorry for the delay responding, I've been out of the office recently and I'm only just catching up on a backlog of GCC related emails. I'm in two minds about this; I can potentially see the need for attributes to enable long calls for specific calls, and maybe also for pragmas that can be used to efficiently mark a group of functions in that way; but I don't really see the value in adding a -mlong-calls option to dothis globally.The reasoning is as follows: long calls are generally very expensive and relatively few functions should need them in most applications (since code that needs to span more than a single block of 128Mbytes - the span of a BL or B instruction - will be very rare in reality). The best way to handle very large branches for those rare cases where you do have a very large contiguous block of code more than 128MB is by having the linker insert veneers when needed; the code will branch to the veneer which will insert an indirect branch at that point (the ABI guarantees that at function call boundaries IP0 and IP1 will not contain live values, making them availablefor such purposes).In a very small number of cases it might be desirable to mark specific functions as being too far away to reach; in those cases the attributes and pragma methods can be used to mark such calls as beingfar calls.Aside: The reason -mlong-calls was added to GCC for ARM is that the code there pre-dates the EABI, which introduced the concept of link-time veneering of calls - the option should be unnecessary now that almost everyone uses the EABI as the basis for their platform ABI. We don't have such a legacy for AArch64 and I'd need to see strongjustification for its use before adding the option there as well.So please can you rework the patch to remove the -mlong-calls option and just leave the attribute and pragma interfaces. R.Hello Richard, Thanks for the comments. I agree with the idea. And I updated the patch with the -mlong-calls option removed and use short call by default. Reg-tested for aarch64-linux-gnu with qemu. Is it OK for trunk? Index: gcc/ChangeLog=================================================================== --- gcc/ChangeLog (revision 217394) +++ gcc/ChangeLog (working copy) @@ -1,3 +1,25 @@ +2014-11-12 Felix Yang <felix.y...@huawei.com> + Haijian Zhang <z.zhanghaij...@huawei.com> + + * config/aarch64/aarch64.h (REGISTER_TARGET_PRAGMAS): Define. + * config/aarch64/aarch64.c (aarch64_set_default_type_attributes, + aarch64_attribute_table, aarch64_comp_type_attributes, + aarch64_decl_is_long_call_p, aarch64_function_in_section_p, + aarch64_pr_long_calls, aarch64_pr_no_long_calls, + aarch64_pr_long_calls_off): New functions. + (TARGET_SET_DEFAULT_TYPE_ATTRIBUTES): Define as + aarch64_set_default_type_attributes. + (TARGET_ATTRIBUTE_TABLE): Define as aarch64_attribute_table. + (TARGET_COMP_TYPE_ATTRIBUTES): Define as aarch64_comp_type_attribute. + (aarch64_pragma_enum): New enum. + (aarch64_attribute_table): New attribute table. + * config/aarch64/aarch64-protos.h (aarch64_pr_long_calls, + aarch64_pr_no_long_calls, aarch64_pr_long_calls_off): Newdeclarations.+ * config/aarch64/aarch64.md (sibcall, sibcall_value): Modified to + generate indirect call for sibling call when needed. + * config/aarch64/predicate.md (aarch64_call_insn_operand): Modifiedto+ exclude a symbol_ref for an indirect call. + 2014-11-11 Andrew Pinski <apin...@cavium.com> Bug target/61997 Index: gcc/testsuite/gcc.target/aarch64/long-calls-1.c=================================================================== --- gcc/testsuite/gcc.target/aarch64/long-calls-1.c (revision 0) +++ gcc/testsuite/gcc.target/aarch64/long-calls-1.c (revision 0) @@ -0,0 +1,133 @@ +/* Check that long calls to different sections are not optimized +to "bl". */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* This test expects that short calls are the default. */ +/* { dg-skip-if "-mlong-calls in use" { "*-*-*" } { "-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 attribute, + with "short" being the default. + + In the regular expressions below: + + * We allow both "b" and "bl" in some cases to allow for the + possibility of sibling calls. */ + +/* { 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 "\tbl?\tstrong_n1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstrong_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstrong_n3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_n3\n" } } */ + +/* { dg-final { scan-assembler "\tbl\tstrong_l1\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_l1\n" } } */ +/* { dg-final { scan-assembler-not "\tbl?\tstrong_l2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstrong_l3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_l3\n" } } */ + +/* { dg-final { scan-assembler "\tbl\tstrong_s1\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_s1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstrong_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstrong_s3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstrong_s3\n" } } */ + + +/* Calls to weak_* should honor the call type attribute, + with "short" being the default. */ + +/* { dg-final { scan-assembler "\tbl\tweak_n1\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tweak_n1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tweak_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tweak_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tweak_n3\n" } } */ +/* { dg-final { scan-assembler "\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 "\tbl?\tweak_s1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tweak_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tweak_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tweak_s3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\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 "\tbl?\tstatic_n1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstatic_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_n2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstatic_n3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_n3\n" } } */ + +/* { dg-final { scan-assembler "\tbl\tstatic_l1\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_l1\n" } } */ +/* { dg-final { scan-assembler-not "\tbl?\tstatic_l2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstatic_l3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_l3\n" } } */ + +/* { dg-final { scan-assembler "\tbl\tstatic_s1\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s1\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstatic_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s2\n" } } */ +/* { dg-final { scan-assembler "\tbl\tstatic_s3\n" } } */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s3\n" } } */ Index: gcc/testsuite/gcc.target/aarch64/long-calls-2.c=================================================================== --- gcc/testsuite/gcc.target/aarch64/long-calls-2.c (revision 0) +++ gcc/testsuite/gcc.target/aarch64/long-calls-2.c (revision 0) @@ -0,0 +1,125 @@ +/* Check that long calls to different sections are not optimized +to "bl". */ +/* { dg-do compile } */ +/* { 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 + attribute, with "short" being the default. + + In the regular expressions below: + + * The PLT marker is optional, even though we are using -fpic, + because it is not used (or required) on some targets. + + * We allow both "b" and "bl" in some cases to allow for the + possibility of sibling calls. */ + +/* { 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 "\tbl?\tstrong_n1(\\(PLT\\))?\n" } +} */ +/* { dg-final { scan-assembler "\tbl\tstrong_n2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tstrong_n2(\\(PLT\\))?\n" } +} */ +/* { dg-final { scan-assembler "\tbl\tstrong_n3(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\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 "\tbl?\tstrong_s1(\\(PLT\\))?\n" } +} */ +/* { dg-final { scan-assembler "\tbl\tstrong_s2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tstrong_s2(\\(PLT\\))?\n" } +} */ +/* { dg-final { scan-assembler "\tbl\tstrong_s3(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tstrong_s3(\\(PLT\\))?\n" } +} */ + + +/* { dg-final { scan-assembler "\tbl\tweak_n1(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tweak_n1(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl\tweak_n2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tweak_n2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl\tweak_n3(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\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 "\tbl?\tweak_s1(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl\tweak_s2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\tweak_s2(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl\tweak_s3(\\(PLT\\))?\n" } } +*/ +/* { dg-final { scan-assembler "\tbl?\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 "\tbl?\tstatic_n1((\\(PLT\\))?)\n" +} } */ +/* { dg-final { scan-assembler "\tbl\tstatic_n2((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\tstatic_n2((\\(PLT\\))?)\n" +} } */ +/* { dg-final { scan-assembler "\tbl\tstatic_n3((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\tstatic_n3((\\(PLT\\))?)\n" +} } */ + +/* { dg-final { scan-assembler "\tbl\tstatic_l1((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\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 "\tbl?\tstatic_l3((\\(PLT\\))?)\n" +} } */ + +/* { dg-final { scan-assembler "\tbl\tstatic_s1((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s1((\\(PLT\\))?)\n" +} } */ +/* { dg-final { scan-assembler "\tbl\tstatic_s2((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s2((\\(PLT\\))?)\n" +} } */ +/* { dg-final { scan-assembler "\tbl\tstatic_s3((\\(PLT\\))?)\n" } +} */ +/* { dg-final { scan-assembler "\tbl?\tstatic_s3((\\(PLT\\))?)\n" +} } */ Index: gcc/testsuite/ChangeLog=================================================================== --- gcc/testsuite/ChangeLog (revision 217394) +++ gcc/testsuite/ChangeLog (working copy) @@ -1,3 +1,9 @@ +2014-11-12 Felix Yang <felix.y...@huawei.com> + Haijian Zhang <z.zhanghaij...@huawei.com> + + * gcc.target/aarch64/long-calls-1.c: New test. + * gcc.target/aarch64/long-calls-2.c: Likewise. + 2014-11-11 Anthony Brandon <anthony.bran...@gmail.com> Manuel L贸pez-Ib谩帽ez <m...@gcc.gnu.org> Index: gcc/config/aarch64/predicates.md=================================================================== --- gcc/config/aarch64/predicates.md (revision 217394) +++ gcc/config/aarch64/predicates.md (working copy) @@ -27,7 +27,8 @@ ) (define_predicate "aarch64_call_insn_operand" - (ior (match_code "symbol_ref") + (ior (and (match_code "symbol_ref") + (match_test "!aarch64_is_long_call_p (op)")) (match_operand 0 "register_operand"))) (define_predicate "aarch64_simd_register" Index: gcc/config/aarch64/aarch64.md=================================================================== --- gcc/config/aarch64/aarch64.md (revision 217394) +++ gcc/config/aarch64/aarch64.md (working copy) @@ -587,11 +587,13 @@ (use (match_operand 2 "" ""))])] "" { - rtx pat; + rtx callee, pat; - if (!REG_P (XEXP (operands[0], 0)) - && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)) - XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); + callee = XEXP (operands[0], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? aarch64_is_long_call_p (callee) + : !REG_P (callee)) + XEXP (operands[0], 0) = force_reg (Pmode, callee); if (operands[2] == NULL_RTX) operands[2] = const0_rtx; @@ -617,11 +619,13 @@ (use (match_operand 3 "" ""))])] "" { - rtx pat; + rtx callee, pat; - if (!REG_P (XEXP (operands[1], 0)) - && (GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)) - XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + callee = XEXP (operands[1], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? aarch64_is_long_call_p (callee) + : !REG_P (callee)) + XEXP (operands[1], 0) = force_reg (Pmode, callee); if (operands[3] == NULL_RTX) operands[3] = const0_rtx; Index: gcc/config/aarch64/aarch64-protos.h=================================================================== --- gcc/config/aarch64/aarch64-protos.h (revision 217394) +++ gcc/config/aarch64/aarch64-protos.h (working copy) @@ -218,6 +218,10 @@ const char *aarch64_mangle_builtin_type (const_tre const char *aarch64_output_casesi (rtx *); const char *aarch64_rewrite_selected_cpu (const char *name); +extern void aarch64_pr_long_calls (struct cpp_reader *); extern +void aarch64_pr_no_long_calls (struct cpp_reader *); extern void +aarch64_pr_long_calls_off (struct cpp_reader *); + enum aarch64_symbol_type aarch64_classify_symbol (rtx, enum aarch64_symbol_context); enumaarch64_symbol_typeaarch64_classify_tls_symbol (rtx); Index: gcc/config/aarch64/aarch64.c=================================================================== --- gcc/config/aarch64/aarch64.c (revision 217394) +++ gcc/config/aarch64/aarch64.c (working copy) @@ -78,6 +78,9 @@ #include "builtins.h" #include "rtl-iter.h" +static void aarch64_set_default_type_attributes (tree); static int +aarch64_comp_type_attributes (const_tree, const_tree); + /* Defined for convenience. */ #define POINTER_BYTES (POINTER_SIZE / BITS_PER_UNIT) @@ -545,11 +548,157 @@ aarch64_hard_regno_caller_save_mode (unsigned regn return choose_hard_reg_mode (regno, nregs, false); } +/* Table of machine attributes. */ static const struct +attribute_spec aarch64_attribute_table[] = { + /* { name, min_len, max_len, decl_req, type_req, fn_type_req,handler,+ affects_type_identity } */ + /* Function calls made to this symbol must be done indirectly, because + it may lie outside of the 26 bit addressing range of a normal function + call. */ + { "long_call", 0, 0, false, true, true, NULL, false }, + /* Whereas these functions are always known to reside within the 26 bit + addressing range. */ + { "short_call", 0, 0, false, true, true, NULL, false }, + { NULL, 0, 0, false, false, false, NULL, false } +}; + +/* Encode the current state of the #pragma [no_]long_calls. */ +typedef enum { + OFF, /* No #pragma [no_]long_calls is in effect. */ + LONG, /* #pragma long_calls is in effect. */ + SHORT /* #pragma no_long_calls is in effect. */ +} aarch64_pragma_enum; + +static aarch64_pragma_enum aarch64_pragma_long_calls = OFF; + +void +aarch64_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED) +{ + aarch64_pragma_long_calls = LONG; } + +void +aarch64_pr_no_long_calls (struct cpp_reader * pfile +ATTRIBUTE_UNUSED) { + aarch64_pragma_long_calls = SHORT; } + +void +aarch64_pr_long_calls_off (struct cpp_reader * pfile +ATTRIBUTE_UNUSED) { + aarch64_pragma_long_calls = OFF; } + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ +static int +aarch64_comp_type_attributes (const_tree type1, const_tree type2) +{ + int l1, l2, s1, s2; + + /* Check for mismatch of non-default calling convention. */ if + (TREE_CODE (type1) != FUNCTION_TYPE) + return 1; + + /* Check for mismatched call attributes. */ + l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != + NULL; + l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != + NULL; + s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != + NULL; + s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != + NULL; + + /* Only bother to check if an attribute is defined. */ if (l1 + | + l2 | s1 | s2) + { + /* If one type has an attribute, the other must have the + sameattribute.*/ + if ((l1 != l2) || (s1 != s2)) + return 0; + + /* Disallow mixed attributes. */ + if ((l1 & s2) || (l2 & s1)) + return 0; + } + + return 1; +} + +/* 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. */ +static void aarch64_set_default_type_attributes (tree type) { + /* Add __attribute__ ((long_call)) to all functions, when + inside #pragma long_calls or __attribute__ ((short_call)), + when inside #pragma no_long_calls. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + tree type_attr_list, attr_name; + type_attr_list = TYPE_ATTRIBUTES (type); + + if (aarch64_pragma_long_calls == LONG) + attr_name = get_identifier ("long_call"); + else if (aarch64_pragma_long_calls == SHORT) + attr_name = get_identifier ("short_call"); + else + return; + + type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list); + TYPE_ATTRIBUTES (type) = type_attr_list; + } +} + +/* Return true if DECL is known to be linked into section SECTION. +*/ static bool aarch64_function_in_section_p (tree decl, section +*section) { + /* We can only be certain about functions defined in the same + compilation unit. */ + if (!TREE_STATIC (decl)) + return false; + + /* Make sure that SYMBOL always binds to the definition in this + compilation unit. */ + if (!targetm.binds_local_p (decl)) + return false; + + /* If DECL_SECTION_NAME is set, assume it is trustworthy. */ + if (!DECL_SECTION_NAME (decl)) + { + /* 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 true if calls to DECL should be treated as long-calls (ie called via a register). */ static bool -aarch64_decl_is_long_call_p (const_tree decl ATTRIBUTE_UNUSED) +aarch64_decl_is_long_call_p (tree decl) { + tree attrs; + + if (!decl) + return false; + + attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); if + (lookup_attribute ("short_call", attrs)) + return false; + + /* 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 + && TREE_CODE (decl) == FUNCTION_DECL + && aarch64_function_in_section_p (decl, + current_function_section()))+ return false; + + if (lookup_attribute ("long_call", attrs)) + return true; + return false; } @@ -10224,6 +10373,15 @@ aarch64_use_by_pieces_infrastructure_p (unsigned i #define TARGET_USE_BY_PIECES_INFRASTRUCTURE_P \ aarch64_use_by_pieces_infrastructure_p +#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES +#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES +aarch64_set_default_type_attributes + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table + +#undef TARGET_COMP_TYPE_ATTRIBUTES #define +TARGET_COMP_TYPE_ATTRIBUTES aarch64_comp_type_attributes + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-aarch64.h" Index: gcc/config/aarch64/aarch64.h=================================================================== --- gcc/config/aarch64/aarch64.h (revision 217394) +++ gcc/config/aarch64/aarch64.h (working copy) @@ -645,6 +645,13 @@ typedef struct } CUMULATIVE_ARGS; #endif +/* Handle pragmas for compatibility with Intel's compilers. */ +#define REGISTER_TARGET_PRAGMAS() do{ \+ c_register_pragma (0, "long_calls", aarch64_pr_long_calls);\+ c_register_pragma (0, "no_long_calls", +aarch64_pr_no_long_calls);\+ c_register_pragma (0, "long_calls_off", aarch64_pr_long_calls_off);\+} while (0) + #define FUNCTION_ARG_PADDING(MODE, TYPE) \ (aarch64_pad_arg_upward (MODE, TYPE) ? upward : downward)