diff mbox

[RFC,AARCH64] Add support for -mlong-calls option

Message ID DA41BE1DDCA941489001C7FBD7A8820E5554C29F@szxema507-mbx.china.huawei.com
State New
Headers show

Commit Message

Yangfei (Felix) Oct. 27, 2014, 9:21 a.m. UTC
> +/* 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?

Comments

Richard Earnshaw Nov. 11, 2014, 3:20 p.m. UTC | #1
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.yang@huawei.com>
> +	    Haijian Zhang  <z.zhanghaijian@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.sandiford@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.yang@huawei.com>
> +	    Haijian Zhang  <z.zhanghaijian@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.sandiford@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)
>  
>
Yangfei (Felix) Nov. 13, 2014, 9:16 a.m. UTC | #2
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)
Yangfei (Felix) Nov. 17, 2014, 8:40 a.m. UTC | #3
Ping Richard.  Any comments?


> > 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)
Yangfei (Felix) Nov. 18, 2014, 11:51 a.m. UTC | #4
Ping again?  Any comment please? 


> 

> 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)
Ramana Radhakrishnan Nov. 18, 2014, 12:01 p.m. UTC | #5
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
>
>
>>
>> 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)
>
Yangfei (Felix) Nov. 18, 2014, 12:51 p.m. UTC | #6
> 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)

> >
Ramana Radhakrishnan Nov. 18, 2014, 1:26 p.m. UTC | #7
On 18/11/14 12:51, Yangfei (Felix) wrote:
>> 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 :-)

You've posted this patch before stage1 closed. In any case IIRC the 
policy in the contribute pages used to suggest a weekly ping.


Ramana

>
>
>>>
>>>
>>>>
>>>> Ping?  I hope this patch can catch up with stage 1 of GCC-5.0.  Thanks.
>>>>
>>>>
>>>>
>>>>
>>>>>> Hi Felix,
>>>>>>
>>>>>> Sorry for the delay responding, I've been out of the office
>>>>>> recently and I'm only just catching up on a backlog of GCC related emails.
>>>>>>
>>>>>> I'm in two minds about this; I can potentially see the need for
>>>>>> attributes to enable long calls for specific calls, and maybe
>>>>>> also for pragmas that can be used to efficiently mark a group of
>>>>>> functions in that way; but I don't really see the value in adding
>>>>>> a -mlong-calls option to 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)
>>>
diff mbox

Patch

Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 216558)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,26 @@ 
+2014-10-27  Felix Yang  <felix.yang@huawei.com>
+	    Haijian Zhang  <z.zhanghaijian@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.sandiford@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)