> +/* 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? Index: gcc/ChangeLog =================================================================== --- gcc/ChangeLog (revision 216558) +++ gcc/ChangeLog (working copy) @@ -1,3 +1,26 @@ +2014-10-27 Felix Yang <felix.y...@huawei.com> + Haijian Zhang <z.zhanghaij...@huawei.com> + + * config/aarch64/aarch64.opt (mlong-calls): New option. + * config/aarch64/aarch64.h (REGISTER_TARGET_PRAGMAS): Define. + * config/aarch64/aarch64.c (aarch64_set_default_type_attributes, + aarch64_attribute_table, aarch64_comp_type_attributes, + aarch64_decl_is_long_call_p, aarch64_function_in_section_p, + aarch64_pr_long_calls, aarch64_pr_no_long_calls, + aarch64_pr_long_calls_off): New functions. + (TARGET_SET_DEFAULT_TYPE_ATTRIBUTES): Define as + aarch64_set_default_type_attributes. + (TARGET_ATTRIBUTE_TABLE): Define as aarch64_attribute_table. + (TARGET_COMP_TYPE_ATTRIBUTES): Define as aarch64_comp_type_attribute. + (aarch64_pragma_enum): New enum. + (aarch64_attribute_table): New attribute table. + * config/aarch64/aarch64-protos.h (aarch64_pr_long_calls, + aarch64_pr_no_long_calls, aarch64_pr_long_calls_off): New declarations. + * config/aarch64/aarch64.md (sibcall, sibcall_value): Modified to + generate indirect call for sibling call when needed. + * config/aarch64/predicate.md (aarch64_call_insn_operand): Modified to + exclude a symbol_ref for an indirect call. + 2014-10-22 Richard Sandiford <richard.sandif...@arm.com> * lra.c (lra): Remove call to recog_init. Index: gcc/config/aarch64/predicates.md =================================================================== --- gcc/config/aarch64/predicates.md (revision 216558) +++ gcc/config/aarch64/predicates.md (working copy) @@ -27,7 +27,8 @@ ) (define_predicate "aarch64_call_insn_operand" - (ior (match_code "symbol_ref") + (ior (and (match_code "symbol_ref") + (match_test "!aarch64_is_long_call_p (op)")) (match_operand 0 "register_operand"))) (define_predicate "aarch64_simd_register" Index: gcc/config/aarch64/aarch64.md =================================================================== --- gcc/config/aarch64/aarch64.md (revision 216558) +++ gcc/config/aarch64/aarch64.md (working copy) @@ -581,11 +581,13 @@ (use (match_operand 2 "" ""))])] "" { - rtx pat; + rtx callee, pat; - if (!REG_P (XEXP (operands[0], 0)) - && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF)) - XEXP (operands[0], 0) = force_reg (Pmode, XEXP (operands[0], 0)); + callee = XEXP (operands[0], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? aarch64_is_long_call_p (callee) + : !REG_P (callee)) + XEXP (operands[0], 0) = force_reg (Pmode, callee); if (operands[2] == NULL_RTX) operands[2] = const0_rtx; @@ -611,11 +613,13 @@ (use (match_operand 3 "" ""))])] "" { - rtx pat; + rtx callee, pat; - if (!REG_P (XEXP (operands[1], 0)) - && (GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF)) - XEXP (operands[1], 0) = force_reg (Pmode, XEXP (operands[1], 0)); + callee = XEXP (operands[1], 0); + if (GET_CODE (callee) == SYMBOL_REF + ? aarch64_is_long_call_p (callee) + : !REG_P (callee)) + XEXP (operands[1], 0) = force_reg (Pmode, callee); if (operands[3] == NULL_RTX) operands[3] = const0_rtx; Index: gcc/config/aarch64/aarch64.opt =================================================================== --- gcc/config/aarch64/aarch64.opt (revision 216558) +++ gcc/config/aarch64/aarch64.opt (working copy) @@ -75,6 +75,10 @@ mlittle-endian Target Report RejectNegative InverseMask(BIG_END) Assume target CPU is configured as little endian +mlong-calls +Target Report Mask(LONG_CALLS) +Generate call insns as indirect calls, if necessary + mcmodel= Target RejectNegative Joined Enum(cmodel) Var(aarch64_cmodel_var) Init(AARCH64_CMODEL_SMALL) Specify the code model Index: gcc/config/aarch64/aarch64-protos.h =================================================================== --- gcc/config/aarch64/aarch64-protos.h (revision 216558) +++ gcc/config/aarch64/aarch64-protos.h (working copy) @@ -217,6 +217,10 @@ bool aarch64_use_return_insn_p (void); const char *aarch64_output_casesi (rtx *); const char *aarch64_rewrite_selected_cpu (const char *name); +extern void aarch64_pr_long_calls (struct cpp_reader *); +extern void aarch64_pr_no_long_calls (struct cpp_reader *); +extern void aarch64_pr_long_calls_off (struct cpp_reader *); + enum aarch64_symbol_type aarch64_classify_symbol (rtx, enum aarch64_symbol_context); enum aarch64_symbol_type aarch64_classify_tls_symbol (rtx); Index: gcc/config/aarch64/aarch64.c =================================================================== --- gcc/config/aarch64/aarch64.c (revision 216558) +++ gcc/config/aarch64/aarch64.c (working copy) @@ -69,6 +69,9 @@ #include "dumpfile.h" #include "builtins.h" +static void aarch64_set_default_type_attributes (tree); +static int aarch64_comp_type_attributes (const_tree, const_tree); + /* Defined for convenience. */ #define POINTER_BYTES (POINTER_SIZE / BITS_PER_UNIT) @@ -530,12 +533,158 @@ aarch64_hard_regno_caller_save_mode (unsigned regn return choose_hard_reg_mode (regno, nregs, false); } +/* Table of machine attributes. */ +static const struct attribute_spec aarch64_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, + affects_type_identity } */ + /* Function calls made to this symbol must be done indirectly, because + it may lie outside of the 26 bit addressing range of a normal function + call. */ + { "long_call", 0, 0, false, true, true, NULL, false }, + /* Whereas these functions are always known to reside within the 26 bit + addressing range. */ + { "short_call", 0, 0, false, true, true, NULL, false }, + { NULL, 0, 0, false, false, false, NULL, false } +}; + +/* Encode the current state of the #pragma [no_]long_calls. */ +typedef enum +{ + OFF, /* No #pragma [no_]long_calls is in effect. */ + LONG, /* #pragma long_calls is in effect. */ + SHORT /* #pragma no_long_calls is in effect. */ +} aarch64_pragma_enum; + +static aarch64_pragma_enum aarch64_pragma_long_calls = OFF; + +void +aarch64_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED) +{ + aarch64_pragma_long_calls = LONG; +} + +void +aarch64_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED) +{ + aarch64_pragma_long_calls = SHORT; +} + +void +aarch64_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED) +{ + aarch64_pragma_long_calls = OFF; +} + +/* Return 0 if the attributes for two types are incompatible, 1 if they + are compatible, and 2 if they are nearly compatible (which causes a + warning to be generated). */ +static int +aarch64_comp_type_attributes (const_tree type1, const_tree type2) +{ + int l1, l2, s1, s2; + + /* Check for mismatch of non-default calling convention. */ + if (TREE_CODE (type1) != FUNCTION_TYPE) + return 1; + + /* Check for mismatched call attributes. */ + l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL; + l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL; + s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL; + s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL; + + /* Only bother to check if an attribute is defined. */ + if (l1 | l2 | s1 | s2) + { + /* If one type has an attribute, the other must have the same attribute. */ + if ((l1 != l2) || (s1 != s2)) + return 0; + + /* Disallow mixed attributes. */ + if ((l1 & s2) || (l2 & s1)) + return 0; + } + + return 1; +} + +/* Assigns default attributes to newly defined type. This is used to + set short_call/long_call attributes for function types of + functions defined inside corresponding #pragma scopes. */ +static void +aarch64_set_default_type_attributes (tree type) +{ + /* Add __attribute__ ((long_call)) to all functions, when + inside #pragma long_calls or __attribute__ ((short_call)), + when inside #pragma no_long_calls. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + tree type_attr_list, attr_name; + type_attr_list = TYPE_ATTRIBUTES (type); + + if (aarch64_pragma_long_calls == LONG) + attr_name = get_identifier ("long_call"); + else if (aarch64_pragma_long_calls == SHORT) + attr_name = get_identifier ("short_call"); + else + return; + + type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list); + TYPE_ATTRIBUTES (type) = type_attr_list; + } +} + +/* Return true if DECL is known to be linked into section SECTION. */ +static bool +aarch64_function_in_section_p (tree decl, section *section) +{ + /* We can only be certain about functions defined in the same + compilation unit. */ + if (!TREE_STATIC (decl)) + return false; + + /* Make sure that SYMBOL always binds to the definition in this + compilation unit. */ + if (!targetm.binds_local_p (decl)) + return false; + + /* If DECL_SECTION_NAME is set, assume it is trustworthy. */ + if (!DECL_SECTION_NAME (decl)) + { + /* Make sure that we will not create a unique section for DECL. */ + if (flag_function_sections || DECL_ONE_ONLY (decl)) + return false; + } + + return function_section (decl) == section; +} + /* Return true if calls to DECL should be treated as long-calls (ie called via a register). */ static bool -aarch64_decl_is_long_call_p (const_tree decl ATTRIBUTE_UNUSED) +aarch64_decl_is_long_call_p (tree decl) { - return false; + tree attrs; + + if (!decl) + return TARGET_LONG_CALLS; + + attrs = TYPE_ATTRIBUTES (TREE_TYPE (decl)); + if (lookup_attribute ("short_call", attrs)) + return false; + + /* For "f", be conservative, and only cater for cases in which the + whole of the current function is placed in the same section. */ + if (!flag_reorder_blocks_and_partition + && TREE_CODE (decl) == FUNCTION_DECL + && aarch64_function_in_section_p (decl, current_function_section ())) + return false; + + if (lookup_attribute ("long_call", attrs)) + return true; + + return TARGET_LONG_CALLS; } /* Return true if calls to symbol-ref SYM should be treated as @@ -10231,6 +10380,15 @@ aarch64_asan_shadow_offset (void) #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS aarch64_legitimize_address +#undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES +#define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES aarch64_set_default_type_attributes + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE aarch64_attribute_table + +#undef TARGET_COMP_TYPE_ATTRIBUTES +#define TARGET_COMP_TYPE_ATTRIBUTES aarch64_comp_type_attributes + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-aarch64.h" Index: gcc/config/aarch64/aarch64.h =================================================================== --- gcc/config/aarch64/aarch64.h (revision 216558) +++ gcc/config/aarch64/aarch64.h (working copy) @@ -633,6 +633,13 @@ typedef struct stack arg area so far. */ } CUMULATIVE_ARGS; +/* Handle pragmas for compatibility with Intel's compilers. */ +#define REGISTER_TARGET_PRAGMAS() do { \ + c_register_pragma (0, "long_calls", aarch64_pr_long_calls); \ + c_register_pragma (0, "no_long_calls", aarch64_pr_no_long_calls); \ + c_register_pragma (0, "long_calls_off", aarch64_pr_long_calls_off); \ +} while (0) + #define FUNCTION_ARG_PADDING(MODE, TYPE) \ (aarch64_pad_arg_upward (MODE, TYPE) ? upward : downward)
aarch64-long-calls-v2.diff
Description: aarch64-long-calls-v2.diff