On 27/10/14 09:21, Yangfei (Felix) wrote: >> +/* 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) > > > Hi, > > I updated the patch with the following two changes: > 1. Add one entry in ChangeLog for this patch; > 2. Enable this feature for sibling calls too. > > Assuming no issues pop up, OK for trunk? >
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. > > Index: gcc/ChangeLog > =================================================================== > --- gcc/ChangeLog (revision 216558) > +++ gcc/ChangeLog (working copy) > @@ -1,3 +1,26 @@ > +2014-10-27 Felix Yang <felix.y...@huawei.com> > + Haijian Zhang <z.zhanghaij...@huawei.com> > + > + * config/aarch64/aarch64.opt (mlong-calls): New option. > + * 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-10-22 Richard Sandiford <richard.sandif...@arm.com> > > * lra.c (lra): Remove call to recog_init. > Index: gcc/config/aarch64/predicates.md > =================================================================== > --- gcc/config/aarch64/predicates.md (revision 216558) > +++ 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 216558) > +++ gcc/config/aarch64/aarch64.md (working copy) > @@ -581,11 +581,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; > @@ -611,11 +613,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.opt > =================================================================== > --- gcc/config/aarch64/aarch64.opt (revision 216558) > +++ gcc/config/aarch64/aarch64.opt (working copy) > @@ -75,6 +75,10 @@ mlittle-endian > Target Report RejectNegative InverseMask(BIG_END) > Assume target CPU is configured as little endian > > +mlong-calls > +Target Report Mask(LONG_CALLS) > +Generate call insns as indirect calls, if necessary > + > mcmodel= > Target RejectNegative Joined Enum(cmodel) Var(aarch64_cmodel_var) > Init(AARCH64_CMODEL_SMALL) > Specify the code model > Index: gcc/config/aarch64/aarch64-protos.h > =================================================================== > --- gcc/config/aarch64/aarch64-protos.h (revision 216558) > +++ gcc/config/aarch64/aarch64-protos.h (working copy) > @@ -217,6 +217,10 @@ bool aarch64_use_return_insn_p (void); > 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 216558) > +++ gcc/config/aarch64/aarch64.c (working copy) > @@ -69,6 +69,9 @@ > #include "dumpfile.h" > #include "builtins.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) > > @@ -530,12 +533,158 @@ 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) > { > - return false; > + tree attrs; > + > + if (!decl) > + return TARGET_LONG_CALLS; > + > + 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 TARGET_LONG_CALLS; > } > > /* Return true if calls to symbol-ref SYM should be treated as > @@ -10231,6 +10380,15 @@ aarch64_asan_shadow_offset (void) > #undef TARGET_LEGITIMIZE_ADDRESS > #define TARGET_LEGITIMIZE_ADDRESS aarch64_legitimize_address > > +#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 216558) > +++ gcc/config/aarch64/aarch64.h (working copy) > @@ -633,6 +633,13 @@ typedef struct > stack arg area so far. */ > } CUMULATIVE_ARGS; > > +/* 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) > > > aarch64-long-calls-v2.diff > > > Index: gcc/ChangeLog > =================================================================== > --- gcc/ChangeLog (revision 216558) > +++ gcc/ChangeLog (working copy) > @@ -1,3 +1,26 @@ > +2014-10-27 Felix Yang <felix.y...@huawei.com> > + Haijian Zhang <z.zhanghaij...@huawei.com> > + > + * config/aarch64/aarch64.opt (mlong-calls): New option. > + * 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-10-22 Richard Sandiford <richard.sandif...@arm.com> > > * lra.c (lra): Remove call to recog_init. > Index: gcc/config/aarch64/predicates.md > =================================================================== > --- gcc/config/aarch64/predicates.md (revision 216558) > +++ 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 216558) > +++ gcc/config/aarch64/aarch64.md (working copy) > @@ -581,11 +581,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; > @@ -611,11 +613,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.opt > =================================================================== > --- gcc/config/aarch64/aarch64.opt (revision 216558) > +++ gcc/config/aarch64/aarch64.opt (working copy) > @@ -75,6 +75,10 @@ mlittle-endian > Target Report RejectNegative InverseMask(BIG_END) > Assume target CPU is configured as little endian > > +mlong-calls > +Target Report Mask(LONG_CALLS) > +Generate call insns as indirect calls, if necessary > + > mcmodel= > Target RejectNegative Joined Enum(cmodel) Var(aarch64_cmodel_var) > Init(AARCH64_CMODEL_SMALL) > Specify the code model > Index: gcc/config/aarch64/aarch64-protos.h > =================================================================== > --- gcc/config/aarch64/aarch64-protos.h (revision 216558) > +++ gcc/config/aarch64/aarch64-protos.h (working copy) > @@ -217,6 +217,10 @@ bool aarch64_use_return_insn_p (void); > 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 216558) > +++ gcc/config/aarch64/aarch64.c (working copy) > @@ -69,6 +69,9 @@ > #include "dumpfile.h" > #include "builtins.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) > > @@ -530,12 +533,158 @@ 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) > { > - return false; > + tree attrs; > + > + if (!decl) > + return TARGET_LONG_CALLS; > + > + 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 TARGET_LONG_CALLS; > } > > /* Return true if calls to symbol-ref SYM should be treated as > @@ -10231,6 +10380,15 @@ aarch64_asan_shadow_offset (void) > #undef TARGET_LEGITIMIZE_ADDRESS > #define TARGET_LEGITIMIZE_ADDRESS aarch64_legitimize_address > > +#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 216558) > +++ gcc/config/aarch64/aarch64.h (working copy) > @@ -633,6 +633,13 @@ typedef struct > stack arg area so far. */ > } CUMULATIVE_ARGS; > > +/* 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) > >