This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PING ^ 2][RFC PATCH, AARCH64] Add support for -mlong-calls option


> On Tue, Nov 18, 2014 at 11:51 AM, Yangfei (Felix) <felix.yang@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.yang@huawei.com>
> >> > +       Haijian Zhang  <z.zhanghaijian@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  <apinski@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.yang@huawei.com>
> >> > +       Haijian Zhang  <z.zhanghaijian@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.brandon@gmail.com>
> >> >         Manuel Lèpez-Ibèåez  <manu@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)
> >

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]