[PING][RFC PATCH, AARCH64] Add support for -mlong-calls option
Yangfei (Felix)
felix.yang@huawei.com
Thu Nov 13 09:34:00 GMT 2014
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)
More information about the Gcc-patches
mailing list