===================================================================
@@ -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
===================================================================
@@ -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" } } */
===================================================================
@@ -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" } } */
===================================================================
@@ -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>
===================================================================
@@ -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"
===================================================================
@@ -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;
===================================================================
@@ -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);
===================================================================
@@ -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"
===================================================================
@@ -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)