> 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. > > Ramana
Oh, 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 :-) > > > > > >> > >> 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 do > >> > this 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 > >> > > available > for 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 being > >> far 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 strong > >> > justification 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): New > declarations. > >> > + * 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): Modified > to > >> > + 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); enum > >> aarch64_symbol_type > >> > aarch64_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 > >> > + same > >> attribute. > >> > */ > >> > + 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) > >