diff --git a/configure b/configure index 3b0abeb8b2e..f7a7da118cc 100755 --- a/configure +++ b/configure @@ -3518,6 +3518,8 @@ esac # Disable libffi for some systems. case "${target}" in + aarch64*-*-darwin2*) + ;; powerpc-*-darwin*) ;; i[3456789]86-*-darwin*) diff --git a/configure.ac b/configure.ac index 042681c27be..21218446587 100644 --- a/configure.ac +++ b/configure.ac @@ -747,6 +747,8 @@ esac # Disable libffi for some systems. case "${target}" in + aarch64*-*-darwin2*) + ;; powerpc-*-darwin*) ;; i[[3456789]]86-*-darwin*) diff --git a/gcc/builtins.cc b/gcc/builtins.cc index f8d94c4b435..13f321b6be6 100644 --- a/gcc/builtins.cc +++ b/gcc/builtins.cc @@ -5929,6 +5929,13 @@ expand_builtin_trap (void) static void expand_builtin_unreachable (void) { + /* If the target wants a trap in place of the fall-through, use that. */ + if (targetm.unreachable_should_trap ()) + { + expand_builtin_trap (); + return; + } + /* Use gimple_build_builtin_unreachable or builtin_decl_unreachable to avoid this. */ gcc_checking_assert (!sanitize_flags_p (SANITIZE_UNREACHABLE)); diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 04e39b41bdf..6cb2637f3cf 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -665,6 +665,18 @@ attribute_takes_identifier_p (const_tree attr_id) return targetm.attribute_takes_identifier_p (attr_id); } +/* Returns TRUE iff the attribute indicated by ATTR_ID needs its + arguments converted to string constants. */ + +bool +attribute_clang_form_p (const_tree attr_id) +{ + const struct attribute_spec *spec = lookup_attribute_spec (attr_id); + if (spec && !strcmp ("availability", spec->name)) + return true; + return false; +} + /* Verify that argument value POS at position ARGNO to attribute NAME applied to function FN (which is either a function declaration or function type) refers to a function parameter at position POS and the expected type diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 2d5f5399885..78414d4519e 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1628,6 +1628,7 @@ extern void check_for_xor_used_as_pow (location_t lhs_loc, tree lhs_val, /* In c-attribs.cc. */ extern bool attribute_takes_identifier_p (const_tree); extern tree handle_deprecated_attribute (tree *, tree, tree, int, bool *); +extern bool attribute_clang_form_p (const_tree); extern tree handle_unused_attribute (tree *, tree, tree, int, bool *); extern tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *); extern int parse_tm_stmt_attr (tree, int); diff --git a/gcc/c-family/c-lex.cc b/gcc/c-family/c-lex.cc index ff5ce2bf729..d5cc6fa43a9 100644 --- a/gcc/c-family/c-lex.cc +++ b/gcc/c-family/c-lex.cc @@ -584,6 +584,21 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, case CPP_NUMBER: { + /* If the user wants number-like entities to be returned as a raw + string, then don't try to classify them, which emits unwanted + diagnostics. */ + if (lex_flags & C_LEX_NUMBER_AS_STRING) + { + /* build_string adds a trailing NUL at [len]. */ + tree num_string = build_string (tok->val.str.len + 1, + (const char *) tok->val.str.text); + TREE_TYPE (num_string) = char_array_type_node; + *value = num_string; + /* We will effectively note this as CPP_N_INVALID, because we + made no checks here. */ + break; + } + const char *suffix = NULL; unsigned int flags = cpp_classify_number (parse_in, tok, &suffix, *loc); diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index be3058dca63..d54d1e57d75 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -1119,7 +1119,7 @@ c_common_post_options (const char **pfilename) if (flag_extern_tls_init) { - if (!TARGET_SUPPORTS_ALIASES || !SUPPORTS_WEAK) + if (!SUPPORTS_WEAK) { /* Lazy TLS initialization for a variable in another TU requires alias and weak reference support. */ diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h index ce93a52fa57..95828547713 100644 --- a/gcc/c-family/c-pragma.h +++ b/gcc/c-family/c-pragma.h @@ -276,6 +276,9 @@ extern void pragma_lex_discard_to_eol (); #define C_LEX_STRING_NO_JOIN 2 /* Do not concatenate strings nor translate them into execution character set. */ +#define C_LEX_NUMBER_AS_STRING 4 /* Do not classify a number, but + instead return it as a raw + string. */ /* This is not actually available to pragma parsers. It's merely a convenient location to declare this function for c-lex, after diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 00f8bf4376e..a1e0775cb4e 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -217,6 +217,9 @@ struct GTY(()) c_parser { should translate them to the execution character set (false inside attributes). */ BOOL_BITFIELD translate_strings_p : 1; + /* True if we want to lex arbitrary number-like sequences as their + string representation. */ + BOOL_BITFIELD lex_number_as_string : 1; /* Objective-C specific parser/lexer information. */ @@ -308,10 +311,10 @@ c_lex_one_token (c_parser *parser, c_token *token, bool raw = false) if (raw || vec_safe_length (parser->raw_tokens) == 0) { + int lex_flags = parser->lex_joined_string ? 0 : C_LEX_STRING_NO_JOIN; + lex_flags |= parser->lex_number_as_string ? C_LEX_NUMBER_AS_STRING : 0; token->type = c_lex_with_flags (&token->value, &token->location, - &token->flags, - (parser->lex_joined_string - ? 0 : C_LEX_STRING_NO_JOIN)); + &token->flags, lex_flags); token->id_kind = C_ID_NONE; token->keyword = RID_MAX; token->pragma_kind = PRAGMA_NONE; @@ -5213,6 +5216,88 @@ c_parser_gnu_attribute_any_word (c_parser *parser) return attr_name; } +/* Handle parsing clang-form attribute arguments, where we need to adjust + the parsing rules to relate to a specific attribute. */ + +static tree +c_parser_clang_attribute_arguments (c_parser *parser, tree /*attr_id*/) +{ + /* We can, if required, alter the parsing on the basis of the attribute. + At present, we handle the availability attr, where ach entry can be : + identifier + identifier=N.MM.Z + identifier="string" + followed by ',' or ) for the last entry*/ + + tree attr_args = NULL_TREE; + do + { + tree name = NULL_TREE; + tree value = NULL_TREE; + + if (c_parser_next_token_is (parser, CPP_NAME) + && c_parser_peek_token (parser)->id_kind == C_ID_ID) + { + name = c_parser_peek_token (parser)->value; + c_parser_consume_token (parser); + } + else if (c_parser_next_token_is (parser, CPP_COMMA)) + name = error_mark_node; /* Comma handled below. */ + else + { + bool saved_join_state = parser->lex_joined_string; + parser->lex_number_as_string = 1; + parser->lex_joined_string = 1; + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected an attribute keyword"); + parser->lex_number_as_string = 0; + parser->lex_joined_string = saved_join_state; + return error_mark_node; + } + if (c_parser_next_token_is (parser, CPP_EQ)) + { + c_parser_consume_token (parser); /* eat the '=' */ + /* We need to bludgeon the lexer into not trying to interpret the + xx.yy.zz form, since that just looks like a malformed float. + Also, as a result of macro processing, we can have strig literals + that are in multiple pieces so, for this specific part of the + parse, we need to join strings. */ + bool saved_join_state = parser->lex_joined_string; + parser->lex_number_as_string = 1; + parser->lex_joined_string = 1; + /* So look at the next token, expecting a string, or something that + looks initially like a number, but might be a version number. */ + c_parser_peek_token (parser); + /* Done with the funky number parsing. */ + parser->lex_number_as_string = 0; + parser->lex_joined_string = saved_join_state; + if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN) + && c_parser_next_token_is_not (parser, CPP_COMMA)) + { + value = c_parser_peek_token (parser)->value; + /* ???: check for error mark and early-return? */ + c_parser_consume_token (parser); + } + /* else value is absent. */ + } + else if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN) + && c_parser_next_token_is_not (parser, CPP_COMMA)) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, + "expected %<,%> or %<=%>"); + return error_mark_node; + } + if (c_parser_next_token_is (parser, CPP_COMMA)) + c_parser_consume_token (parser); /* Just skip the comma. */ + tree t = tree_cons (value, name, NULL); + if (!attr_args) + attr_args = t; + else + chainon (attr_args, t); + } while (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN)); + return attr_args; +} + /* Parse attribute arguments. This is a common form of syntax covering all currently valid GNU and standard attributes. @@ -5378,9 +5463,13 @@ c_parser_gnu_attribute (c_parser *parser, tree attrs, attrs = chainon (attrs, attr); return attrs; } - c_parser_consume_token (parser); + c_parser_consume_token (parser); /* The '('. */ - tree attr_args + tree attr_args; + if (attribute_clang_form_p (attr_name)) + attr_args = c_parser_clang_attribute_arguments (parser, attr_name); + else + attr_args = c_parser_attribute_arguments (parser, attribute_takes_identifier_p (attr_name), false, diff --git a/gcc/calls.cc b/gcc/calls.cc index 21d78f9779f..d84998668a4 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -1376,7 +1376,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, with those made by function.cc. */ /* See if this argument should be passed by invisible reference. */ - function_arg_info arg (type, argpos < n_named_args); + function_arg_info arg (type, argpos < n_named_args, + argpos == n_named_args - 1); if (pass_by_reference (args_so_far_pnt, arg)) { const bool callee_copies @@ -1496,10 +1497,13 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, unsignedp = TYPE_UNSIGNED (type); arg.type = type; - arg.mode - = promote_function_mode (type, TYPE_MODE (type), &unsignedp, - fndecl ? TREE_TYPE (fndecl) : fntype, 0); - + arg.mode = TYPE_MODE (type); +// arg.mode +// = promote_function_mode (type, TYPE_MODE (type), &unsignedp, +// fndecl ? TREE_TYPE (fndecl) : fntype, 0); + arg.mode = promote_function_mode (args_so_far, arg, + fndecl ? TREE_TYPE (fndecl) : fntype, + &unsignedp, 0); args[i].unsignedp = unsignedp; args[i].mode = arg.mode; @@ -1549,6 +1553,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, #endif reg_parm_stack_space, args[i].pass_on_stack ? 0 : args[i].partial, + args_so_far, fndecl, args_size, &args[i].locate); #ifdef BLOCK_REG_PADDING else @@ -4096,6 +4101,7 @@ split_complex_types (tree types) return types; } +extern void debug_tree (tree); /* Output a library call to function ORGFUN (a SYMBOL_REF rtx) for a value of mode OUTMODE, with NARGS different arguments, passed as ARGS. @@ -4281,6 +4287,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, argvec[count].reg != 0, #endif reg_parm_stack_space, 0, + args_so_far, NULL_TREE, &args_size, &argvec[count].locate); if (argvec[count].reg == 0 || argvec[count].partial != 0 @@ -4351,8 +4358,16 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, val = force_operand (XEXP (slot, 0), NULL_RTX); } - arg.mode = promote_function_mode (NULL_TREE, arg.mode, &unsigned_p, - NULL_TREE, 0); +// arg.mode = promote_function_mode (NULL_TREE, arg.mode, &unsigned_p, +// NULL_TREE, 0); + tree t = arg.type; +if (t) + debug_tree (t); +gcc_assert (!t); + arg.type = NULL_TREE; + arg.mode = promote_function_mode (args_so_far, arg, NULL_TREE, + &unsigned_p, 0); + arg.type = t; argvec[count].mode = arg.mode; argvec[count].value = convert_modes (arg.mode, GET_MODE (val), val, unsigned_p); @@ -4372,6 +4387,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, argvec[count].reg != 0, #endif reg_parm_stack_space, argvec[count].partial, + args_so_far, NULL_TREE, &args_size, &argvec[count].locate); args_size.constant += argvec[count].locate.size.constant; gcc_assert (!argvec[count].locate.size.var); diff --git a/gcc/calls.h b/gcc/calls.h index 464a4e34e33..499f7560ee8 100644 --- a/gcc/calls.h +++ b/gcc/calls.h @@ -35,24 +35,43 @@ class function_arg_info { public: function_arg_info () - : type (NULL_TREE), mode (VOIDmode), named (false), + : type (NULL_TREE), mode (VOIDmode), named (false), last_named (false), pass_by_reference (false) {} /* Initialize an argument of mode MODE, either before or after promotion. */ function_arg_info (machine_mode mode, bool named) - : type (NULL_TREE), mode (mode), named (named), pass_by_reference (false) + : type (NULL_TREE), mode (mode), named (named), last_named (false), + pass_by_reference (false) + {} + + function_arg_info (machine_mode mode, bool named, bool last_named) + : type (NULL_TREE), mode (mode), named (named), last_named (last_named), + pass_by_reference (false) {} /* Initialize an unpromoted argument of type TYPE. */ function_arg_info (tree type, bool named) - : type (type), mode (TYPE_MODE (type)), named (named), + : type (type), mode (TYPE_MODE (type)), named (named), last_named (false), pass_by_reference (false) {} + /* Initialize an unpromoted argument of type TYPE. */ + function_arg_info (tree type, bool named, bool last_named) + : type (type), mode (TYPE_MODE (type)), named (named), + last_named (last_named), pass_by_reference (false) + {} + /* Initialize an argument with explicit properties. */ function_arg_info (tree type, machine_mode mode, bool named) - : type (type), mode (mode), named (named), pass_by_reference (false) + : type (type), mode (mode), named (named), last_named (false), + pass_by_reference (false) + {} + + /* Initialize an argument with explicit properties. */ + function_arg_info (tree type, machine_mode mode, bool named, bool last_named) + : type (type), mode (mode), named (named), last_named (last_named), + pass_by_reference (false) {} /* Return true if the gimple-level type is an aggregate. */ @@ -105,6 +124,9 @@ public: "..."). See also TARGET_STRICT_ARGUMENT_NAMING. */ unsigned int named : 1; + /* True if this is the last named argument. */ + unsigned int last_named : 1; + /* True if we have decided to pass the argument by reference, in which case the function_arg_info describes a pointer to the original argument. */ unsigned int pass_by_reference : 1; diff --git a/gcc/common.opt b/gcc/common.opt index ad348844775..e92ad9e5366 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -2919,6 +2919,10 @@ fstack-usage Common RejectNegative Var(flag_stack_usage) Output stack usage information on a per-function basis. +fstack-use-cumulative-args +Common RejectNegative Var(flag_stack_use_cumulative_args) Init(STACK_USE_CUMULATIVE_ARGS_INIT) +Use cumulative args-based stack layout hooks. + fstrength-reduce Common Ignore Does nothing. Preserved for backward compatibility. diff --git a/gcc/common/config/aarch64/aarch64-common.cc b/gcc/common/config/aarch64/aarch64-common.cc index 951d041d310..496d0d82e05 100644 --- a/gcc/common/config/aarch64/aarch64-common.cc +++ b/gcc/common/config/aarch64/aarch64-common.cc @@ -298,8 +298,12 @@ aarch64_get_extension_string_for_isa_flags However, assemblers with Armv8-R AArch64 support should not have this issue, so we don't need this fix when targeting Armv8-R. */ - auto explicit_flags = (!(current_flags & AARCH64_FL_V8R) - ? AARCH64_FL_CRC : 0); + aarch64_feature_flags explicit_flags = +#ifndef DISABLE_AARCH64_AS_CRC_BUGFIX + (!(current_flags & AARCH64_ISA_V8R) ? AARCH64_FL_CRC : 0); +#else + 0; +#endif /* Add the features in isa_flags & ~current_flags using the smallest possible number of extensions. We can do this by iterating over the @@ -329,7 +333,10 @@ aarch64_get_extension_string_for_isa_flags if (added & opt.flag_canonical) { outstr += "+"; - outstr += opt.name; + if (startswith (opt.name, "rdm")) + outstr += "rdm"; + else + outstr += opt.name; } /* Remove the features in current_flags & ~isa_flags. If the feature does @@ -358,7 +365,10 @@ aarch64_get_extension_string_for_isa_flags { current_flags &= ~opt.flags_off; outstr += "+no"; - outstr += opt.name; + if (startswith (opt.name, "rdm")) + outstr += "rdm"; + else + outstr += opt.name; } } diff --git a/gcc/config.gcc b/gcc/config.gcc index 95c91ee02be..381e27dc759 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -1177,13 +1177,22 @@ case ${target} in ;; esac -# Figure out if we need to enable heap trampolines by default +# Figure out if we need to enable heap trampolines +# and variadic functions handling. case ${target} in +aarch64*-*-darwin2*) + # This applies to arm64 Darwin variadic funtions. + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=1" + # Executable stack is forbidden. + tm_defines="$tm_defines HEAP_TRAMPOLINES_INIT=1" + ;; *-*-darwin2*) + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=0" # Currently, we do this for macOS 11 and above. tm_defines="$tm_defines HEAP_TRAMPOLINES_INIT=1" ;; *) + tm_defines="$tm_defines STACK_USE_CUMULATIVE_ARGS_INIT=0" tm_defines="$tm_defines HEAP_TRAMPOLINES_INIT=0" ;; esac @@ -1227,6 +1236,14 @@ aarch64*-*-elf | aarch64*-*-fuchsia* | aarch64*-*-rtems*) done TM_MULTILIB_CONFIG=`echo $TM_MULTILIB_CONFIG | sed 's/^,//'` ;; +aarch64-*-darwin* ) + tm_file="${tm_file} aarch64/aarch64-errata.h" + tmake_file="${tmake_file} aarch64/t-aarch64 aarch64/t-aarch64-darwin" + tm_defines="${tm_defines} TARGET_DEFAULT_ASYNC_UNWIND_TABLES=1" + tm_defines="${tm_defines} DISABLE_AARCH64_AS_CRC_BUGFIX=1" + # Choose a default CPU version that will work for all current releases. + with_cpu=${with_cpu:-apple-m1} + ;; aarch64*-*-freebsd*) tm_file="${tm_file} elfos.h ${fbsd_tm_file}" tm_file="${tm_file} aarch64/aarch64-elf.h aarch64/aarch64-errata.h aarch64/aarch64-freebsd.h" diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 75d21de1401..c54dcd941a3 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -788,6 +788,8 @@ enum aarch64_builtins AARCH64_PLDX, AARCH64_PLI, AARCH64_PLIX, + /* OS-specific */ + AARCH64_BUILTIN_CFSTRING, AARCH64_BUILTIN_MAX }; @@ -887,6 +889,9 @@ tree aarch64_fp16_ptr_type_node = NULL_TREE; /* Back-end node type for brain float (bfloat) types. */ tree aarch64_bf16_ptr_type_node = NULL_TREE; +/* Pointer to __float128 on Mach-O, where the 128b float is not long double. */ +tree aarch64_float128_ptr_type_node = NULL_TREE; + /* Wrapper around add_builtin_function. NAME is the name of the built-in function, TYPE is the function type, CODE is the function subcode (relative to AARCH64_BUILTIN_GENERAL), and ATTRS is the function @@ -1662,6 +1667,29 @@ aarch64_init_bf16_types (void) aarch64_bf16_ptr_type_node = build_pointer_type (bfloat16_type_node); } +/* Initialize the backend REAL_TYPE type supporting __float128 on Mach-O, + as well as the related built-ins. */ +static void +aarch64_init_float128_types (void) +{ + /* The __float128 type. The node has already been created as + _Float128, so for C we only need to register the __float128 name for + it. For C++, we create a distinct type which will mangle differently + (g) vs. _Float128 (DF128_) and behave backwards compatibly. */ + if (float128t_type_node == NULL_TREE) + { + float128t_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float128t_type_node) + = TYPE_PRECISION (float128_type_node); + SET_TYPE_MODE (float128t_type_node, TYPE_MODE (float128_type_node)); + layout_type (float128t_type_node); + } + lang_hooks.types.register_builtin_type (float128t_type_node, "__float128"); + + aarch64_float128_ptr_type_node = build_pointer_type (float128t_type_node); +} + + /* Pointer authentication builtins that will become NOP on legacy platform. Currently, these builtins are for internal use only (libgcc EH unwinder). */ @@ -2047,8 +2075,9 @@ aarch64_general_init_builtins (void) aarch64_init_fpsr_fpcr_builtins (); aarch64_init_fp16_types (); - aarch64_init_bf16_types (); + if (TARGET_MACHO) + aarch64_init_float128_types (); { aarch64_simd_switcher simd; @@ -2088,6 +2117,14 @@ aarch64_general_init_builtins (void) handle_arm_acle_h (); } +void +aarch64_init_subtarget_builtins (void) +{ +#ifdef SUBTARGET_INIT_BUILTINS + SUBTARGET_INIT_BUILTINS; +#endif +} + /* Implement TARGET_BUILTIN_DECL for the AARCH64_BUILTIN_GENERAL group. */ tree aarch64_general_builtin_decl (unsigned code, bool) diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc index fe1a20e4e54..607d533d08e 100644 --- a/gcc/config/aarch64/aarch64-c.cc +++ b/gcc/config/aarch64/aarch64-c.cc @@ -279,6 +279,16 @@ aarch64_cpu_cpp_builtins (cpp_reader *pfile) { aarch64_define_unconditional_macros (pfile); aarch64_update_cpp_builtins (pfile); + + if (TARGET_MACHO) + { + builtin_define ("__builtin_copysignq=__builtin_copysignf128"); + builtin_define ("__builtin_fabsq=__builtin_fabsf128"); + builtin_define ("__builtin_huge_valq=__builtin_huge_valf128"); + builtin_define ("__builtin_infq=__builtin_inff128"); + builtin_define ("__builtin_nanq=__builtin_nanf128"); + builtin_define ("__builtin_nansq=__builtin_nansf128"); + } } /* Hook to validate the current #pragma GCC target and set the state, and @@ -418,4 +428,8 @@ aarch64_register_pragmas (void) targetm.check_builtin_call = aarch64_check_builtin_call; c_register_pragma ("GCC", "aarch64", aarch64_pragma_aarch64); + +#ifdef REGISTER_SUBTARGET_PRAGMAS + REGISTER_SUBTARGET_PRAGMAS (); +#endif } diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def index f69fc212d56..a84520a5867 100644 --- a/gcc/config/aarch64/aarch64-cores.def +++ b/gcc/config/aarch64/aarch64-cores.def @@ -166,6 +166,17 @@ AARCH64_CORE("cortex-a76.cortex-a55", cortexa76cortexa55, cortexa53, V8_2A, (F /* Armv8-R Architecture Processors. */ AARCH64_CORE("cortex-r82", cortexr82, cortexa53, V8R, (), cortexa53, 0x41, 0xd15, -1) +/* Apple (A12 and M) cores. + Apple implementer ID from xnu, + guesses for part #, guesses for scheduler ident, generic_armv8_a for costs. + A12 seems mostly 8.3, + M1 seems to be 8.4 + extras (see comments in option-extensions about f16fml), + M2 mostly 8.5 but with missing mandatory features. */ +AARCH64_CORE("apple-a12", applea12, cortexa53, V8_3A, (), generic_armv8_a, 0x61, 0x12, -1) +AARCH64_CORE("apple-m1", applem1, cortexa57, V8_4A, (F16, SB, SSBS), generic_armv8_a, 0x61, 0x23, -1) +AARCH64_CORE("apple-m2", applem2, cortexa57, V8_4A, (I8MM, BF16, F16, SB, SSBS), generic_armv8_a, 0x61, 0x23, -1) +AARCH64_CORE("apple-m3", applem3, cortexa57, V8_4A, (I8MM, BF16, F16, SB, SSBS), generic_armv8_a, 0x61, 0x23, -1) + /* Armv9.0-A Architecture Processors. */ /* Arm ('A') cores. */ diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 42639e9efcf..192a9da99bb 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -109,6 +109,14 @@ enum aarch64_symbol_type SYMBOL_TLSLE24, SYMBOL_TLSLE32, SYMBOL_TLSLE48, + SYMBOL_MO_SMALL_ABS, + SYMBOL_MO_SMALL_PCR, + SYMBOL_MO_SMALL_GOT, + SYMBOL_MO_SMALL_TLS, + SYMBOL_MO_LARGE_ABS, + SYMBOL_MO_LARGE_PCR, + SYMBOL_MO_LARGE_GOT, + SYMBOL_MO_LARGE_TLS, SYMBOL_FORCE_TO_MEM }; @@ -748,6 +756,7 @@ void aarch64_post_cfi_startproc (void); poly_int64 aarch64_initial_elimination_offset (unsigned, unsigned); int aarch64_get_condition_code (rtx); bool aarch64_address_valid_for_prefetch_p (rtx, bool); +bool aarch64_address_valid_for_unscaled_prefetch_p (rtx, bool); bool aarch64_bitmask_imm (unsigned HOST_WIDE_INT val, machine_mode); unsigned HOST_WIDE_INT aarch64_and_split_imm1 (HOST_WIDE_INT val_in); unsigned HOST_WIDE_INT aarch64_and_split_imm2 (HOST_WIDE_INT val_in); @@ -782,7 +791,11 @@ bool aarch64_is_extend_from_extract (scalar_int_mode, rtx, rtx); bool aarch64_is_long_call_p (rtx); bool aarch64_is_noplt_call_p (rtx); bool aarch64_label_mentioned_p (rtx); +#if TARGET_MACHO +void aarch64_darwin_declare_function_name (FILE *, const char*, tree ); +#else void aarch64_declare_function_name (FILE *, const char*, tree); +#endif void aarch64_asm_output_alias (FILE *, const tree, const tree); void aarch64_asm_output_external (FILE *, tree, const char*); bool aarch64_legitimate_pic_operand_p (rtx); @@ -999,6 +1012,7 @@ void aarch64_override_options_internal (struct gcc_options *); const char *aarch64_general_mangle_builtin_type (const_tree); void aarch64_general_init_builtins (void); +void aarch64_init_subtarget_builtins (void); tree aarch64_general_fold_builtin (unsigned int, tree, unsigned int, tree *); gimple *aarch64_general_gimple_fold_builtin (unsigned int, gcall *, gimple_stmt_iterator *); diff --git a/gcc/config/aarch64/aarch64-tune.md b/gcc/config/aarch64/aarch64-tune.md index abd3c9e0822..ed86d76db5c 100644 --- a/gcc/config/aarch64/aarch64-tune.md +++ b/gcc/config/aarch64/aarch64-tune.md @@ -1,5 +1,5 @@ ;; -*- buffer-read-only: t -*- ;; Generated automatically by gentune.sh from aarch64-cores.def (define_attr "tune" - "cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,cortexa510,cortexa520,cortexa710,cortexa715,cortexa720,cortexx2,cortexx3,cortexx4,neoversen2,cobalt100,neoversev2,demeter,generic,generic_armv8_a,generic_armv9_a" + "cortexa34,cortexa35,cortexa53,cortexa57,cortexa72,cortexa73,thunderx,thunderxt88p1,thunderxt88,octeontx,octeontxt81,octeontxt83,thunderxt81,thunderxt83,ampere1,ampere1a,ampere1b,emag,xgene1,falkor,qdf24xx,exynosm1,phecda,thunderx2t99p1,vulcan,thunderx2t99,cortexa55,cortexa75,cortexa76,cortexa76ae,cortexa77,cortexa78,cortexa78ae,cortexa78c,cortexa65,cortexa65ae,cortexx1,cortexx1c,neoversen1,ares,neoversee1,octeontx2,octeontx2t98,octeontx2t96,octeontx2t93,octeontx2f95,octeontx2f95n,octeontx2f95mm,a64fx,tsv110,thunderx3t110,neoversev1,zeus,neoverse512tvb,saphira,cortexa57cortexa53,cortexa72cortexa53,cortexa73cortexa35,cortexa73cortexa53,cortexa75cortexa55,cortexa76cortexa55,cortexr82,applea12,applem1,applem2,applem3,cortexa510,cortexa520,cortexa710,cortexa715,cortexa720,cortexx2,cortexx3,cortexx4,neoversen2,cobalt100,neoversev2,demeter,generic,generic_armv8_a,generic_armv9_a" (const (symbol_ref "((enum attr_tune) aarch64_tune)"))) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 1beec94629d..f12b1a308ea 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -329,8 +329,10 @@ static bool aarch64_vfp_is_call_or_return_candidate (machine_mode, const_tree, machine_mode *, int *, bool *, bool); +#if !TARGET_MACHO static void aarch64_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED; static void aarch64_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED; +#endif static void aarch64_override_options_after_change (void); static bool aarch64_vector_mode_supported_p (machine_mode); static int aarch64_address_cost (rtx, machine_mode, addr_space_t, bool); @@ -848,6 +850,9 @@ static const attribute_spec aarch64_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ +#ifdef SUBTARGET_ATTRIBUTE_TABLE + SUBTARGET_ATTRIBUTE_TABLE, +#endif { "aarch64_vector_pcs", 0, 0, false, true, true, true, handle_aarch64_vector_pcs_attribute, NULL }, { "arm_sve_vector_bits", 1, 1, false, true, false, true, @@ -2067,7 +2072,7 @@ aarch64_hard_regno_mode_ok (unsigned regno, machine_mode mode) if (known_le (GET_MODE_SIZE (mode), 8)) return true; if (known_le (GET_MODE_SIZE (mode), 16)) - return (regno & 1) == 0; + return (regno & 1) == 0 || TARGET_MACHO; /* darwinpcs D.4 */ } else if (FP_REGNUM_P (regno)) { @@ -2113,8 +2118,10 @@ static bool aarch64_takes_arguments_in_sve_regs_p (const_tree fntype) { CUMULATIVE_ARGS args_so_far_v; + /* This does not apply to variadic functions, so all the (currently + uncounted) arguments must be named. */ aarch64_init_cumulative_args (&args_so_far_v, NULL_TREE, NULL_RTX, - NULL_TREE, 0, true); + NULL_TREE, -1, true); cumulative_args_t args_so_far = pack_cumulative_args (&args_so_far_v); for (tree chain = TYPE_ARG_TYPES (fntype); @@ -2861,6 +2868,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, switch (type) { case SYMBOL_SMALL_ABSOLUTE: + case SYMBOL_MO_SMALL_PCR: { /* In ILP32, the mode of dest can be either SImode or DImode. */ rtx tmp_reg = dest; @@ -2871,6 +2879,21 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, if (can_create_pseudo_p ()) tmp_reg = gen_reg_rtx (mode); + if (TARGET_MACHO) + { + rtx sym, off; + split_const (imm, &sym, &off); + /* Negative offsets don't work, whether by intention is TBD. */ + if (INTVAL (off) < 0 || INTVAL (off) > 8 * 1024 * 1024) + { + emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, sym)); + emit_insn (gen_add_losym (dest, tmp_reg, sym)); + /* FIXME: add the SI option if/when we support ilp32. */ + emit_insn (gen_adddi3 (dest, dest, off)); + return; + } + /* else small enough positive offset is OK. */ + } emit_move_insn (tmp_reg, gen_rtx_HIGH (mode, copy_rtx (imm))); emit_insn (gen_add_losym (dest, tmp_reg, imm)); return; @@ -2954,6 +2977,7 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm, return; } + case SYMBOL_MO_SMALL_GOT: case SYMBOL_SMALL_GOT_4G: emit_insn (gen_rtx_SET (dest, imm)); return; @@ -6026,6 +6050,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) case SYMBOL_SMALL_TLSIE: case SYMBOL_SMALL_GOT_28K: case SYMBOL_SMALL_GOT_4G: + case SYMBOL_MO_SMALL_GOT: case SYMBOL_TINY_GOT: case SYMBOL_TINY_TLSIE: if (const_offset != 0) @@ -6039,6 +6064,7 @@ aarch64_expand_mov_immediate (rtx dest, rtx imm) /* FALLTHRU */ case SYMBOL_SMALL_ABSOLUTE: + case SYMBOL_MO_SMALL_PCR: case SYMBOL_TINY_ABSOLUTE: case SYMBOL_TLSLE12: case SYMBOL_TLSLE24: @@ -6628,6 +6654,7 @@ aarch64_return_in_memory (const_tree type, const_tree fndecl ATTRIBUTE_UNUSED) gcc_unreachable (); } +#if !TARGET_MACHO static bool aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, const_tree type, int *nregs) @@ -6637,6 +6664,7 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, &pcum->aapcs_vfp_rmode, nregs, NULL, pcum->silent_p); } +#endif /* Given MODE and TYPE of a function argument, return the alignment in bits. The idea is to suppress any stronger alignment requested by @@ -6665,7 +6693,7 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type, if (integer_zerop (TYPE_SIZE (type))) return 0; - gcc_assert (TYPE_MODE (type) == mode); + gcc_assert (TARGET_MACHO || TYPE_MODE (type) == mode); if (!AGGREGATE_TYPE_P (type)) { @@ -6863,6 +6891,14 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) Both behaviors were wrong, but in different cases. */ pcum->aapcs_arg_processed = true; + if (TARGET_MACHO) + { + /* Set suitable defaults for queries. */ + pcum->darwinpcs_arg_boundary + = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, + &abi_break_gcc_13, &abi_break_gcc_14); + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + } pure_scalable_type_info pst_info; if (type && pst_info.analyze_registers (type)) @@ -6922,13 +6958,29 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* No frontends can create types with variable-sized modes, so we shouldn't be asked to pass or return them. */ size = GET_MODE_SIZE (mode).to_constant (); + + if (TARGET_MACHO) + /* Since we can pack things on the stack, we need the unrounded size. */ + pcum->darwinpcs_stack_bytes = size; + size = ROUND_UP (size, UNITS_PER_WORD); allocate_ncrn = (type) ? !(FLOAT_TYPE_P (type)) : !FLOAT_MODE_P (mode); + bool is_ha = false; +#if !TARGET_MACHO allocate_nvrn = aarch64_vfp_is_call_candidate (pcum_v, mode, type, &nregs); +#else + /* We care if the value is a homogenous aggregate when laying out the stack, + so use this call directly. */ + allocate_nvrn + = aarch64_vfp_is_call_or_return_candidate (mode, type, + &pcum->aapcs_vfp_rmode, + &nregs, &is_ha, + pcum->silent_p); +#endif gcc_assert (!sve_p || !allocate_nvrn); unsigned int alignment @@ -6957,7 +7009,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) if (!pcum->silent_p && !TARGET_FLOAT) aarch64_err_no_fpadvsimd (mode); - if (nvrn + nregs <= NUM_FP_ARG_REGS) + if (TARGET_MACHO + && !arg.named) + { + pcum->aapcs_nextnvrn = NUM_FP_ARG_REGS; + goto on_stack; + } + else if (nvrn + nregs <= NUM_FP_ARG_REGS) { pcum->aapcs_nextnvrn = nvrn + nregs; if (!aarch64_composite_type_p (type, mode)) @@ -6987,6 +7045,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) } pcum->aapcs_reg = par; } + pcum->darwinpcs_stack_bytes = 0; return; } else @@ -7003,14 +7062,24 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* C6 - C9. though the sign and zero extension semantics are handled elsewhere. This is the case where the argument fits entirely general registers. */ + if (allocate_ncrn && (ncrn + nregs <= NUM_ARG_REGS)) { gcc_assert (nregs == 0 || nregs == 1 || nregs == 2); + if (TARGET_MACHO + && !arg.named) + { + pcum->aapcs_nextncrn = NUM_ARG_REGS; + goto on_stack; + } + /* C.8 if the argument has an alignment of 16 then the NGRN is rounded up to the next even number. */ if (nregs == 2 - && ncrn % 2) + && ncrn % 2 + /* Darwin PCS deletes rule C.8. */ + && !TARGET_MACHO) { /* Emit a warning if the alignment changed when taking the 'packed' attribute into account. */ @@ -7080,8 +7149,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) } pcum->aapcs_reg = par; } - pcum->aapcs_nextncrn = ncrn + nregs; + pcum->darwinpcs_stack_bytes = 0; return; } @@ -7091,7 +7160,81 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* The argument is passed on stack; record the needed number of words for this argument and align the total size if necessary. */ on_stack: - pcum->aapcs_stack_words = size / UNITS_PER_WORD; + + if (TARGET_MACHO) + { + /* Darwin does not round up the allocation for smaller entities to 8 + bytes. It only requires the natural alignment for these. + + but we don't do this for: + * unnamed parms in variadic functions + * complex types + * unions + * aggregates (except for homogeneous ones which are handles as the + enclosed type). + each entry starts a new slot. + + 16 byte entities are naturally aligned on the stack. + There was no darwinpcs for GCC 9, so neither the implementation + change nor the warning should fire here (i.e. we do not need to check + if 16byte entities alter the stack size). */ + + gcc_checking_assert (arg.named == pcum->named_p); + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + if (!pcum->named_p + || TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (pcum->aapcs_vfp_rmode)) + || TREE_CODE (type) == UNION_TYPE) + { + pcum->aapcs_stack_words = size / UNITS_PER_WORD; + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + pcum->darwinpcs_arg_boundary = MAX (alignment, PARM_BOUNDARY); + if (!pcum->named_p) + pcum->darwinpcs_arg_padding = PARM_BOUNDARY; + return; + } + + /* Updated sub-word offset aligned for the new object. + We are looking for the case that the new object will fit after some + existing object(s) in the same stack slot. In that case, we do not + need to add any more stack space for it. */ + int new_off + = ROUND_UP (pcum->darwinpcs_sub_word_pos, alignment / BITS_PER_UNIT); + + if (new_off >= UNITS_PER_WORD) + { + /* That exceeds a stack slot, start a new one. */ + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + new_off = 0; + } + /* This is the end of the new object. */ + int new_pos = new_off + pcum->darwinpcs_stack_bytes; + + if (pcum->darwinpcs_sub_word_pos == 0) + /* New stack slot, just allocate one or more words, and note where + the next arg will start. */ + pcum->aapcs_stack_words = size / UNITS_PER_WORD; + else if (new_pos <= UNITS_PER_WORD) + /* Old stack slot, object starts at new_off and goes to new_pos, we do + not add any stack space. */ + pcum->darwinpcs_sub_word_offset = new_off; + pcum->darwinpcs_sub_word_pos = new_pos; + pcum->darwinpcs_arg_boundary = alignment ; + if (pcum->last_named_p && new_pos > 0) + { + /* Round the last named arg to the start of the next stack slot. */ + if (new_pos <= 4) + pcum->darwinpcs_arg_padding = PARM_BOUNDARY; + else if (new_pos <= 6) + pcum->darwinpcs_arg_padding = 4 * BITS_PER_UNIT; + else if (pcum->darwinpcs_sub_word_pos <= 7) + pcum->darwinpcs_arg_padding = 2 * BITS_PER_UNIT; + } + return; + } if (warn_pcs_change_le_gcc14 && abi_break_gcc_13 @@ -7107,6 +7250,8 @@ on_stack: inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 14.1", type); + /* size was already rounded up to PARM_BOUNDARY. */ + pcum->aapcs_stack_words = size / UNITS_PER_WORD; if (alignment == 16 * BITS_PER_UNIT) { int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); @@ -7211,12 +7356,33 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, pcum->aapcs_arg_processed = false; pcum->aapcs_stack_words = 0; pcum->aapcs_stack_size = 0; + pcum->darwinpcs_stack_bytes = 0; + pcum->darwinpcs_sub_word_offset = 0; + pcum->darwinpcs_sub_word_pos = 0; + pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + /* If we have been invoked for incoming args, then n_named will have been + set to -1, but we should have a function decl - so pick up the named + count from that. If that fails, and we end up with -1, this effectively + corresponds to assuming that there is an arbitrary number of named + args. */ + pcum->darwinpcs_n_named = n_named; + if (n_named == (unsigned)-1 && fndecl) + { + tree fnt = TREE_TYPE (fndecl); + if (fnt && TYPE_ARG_TYPES (fnt)) + pcum->darwinpcs_n_named = list_length (TYPE_ARG_TYPES (fnt)); + } + pcum->darwinpcs_n_args_processed = 0; + pcum->named_p = pcum->darwinpcs_n_named != 0; + pcum->last_named_p = pcum->darwinpcs_n_named == 1; pcum->silent_p = silent_p; pcum->shared_za_flags = (fntype ? aarch64_fntype_shared_flags (fntype, "za") : 0U); pcum->shared_zt0_flags = (fntype ? aarch64_fntype_shared_flags (fntype, "zt0") : 0U); pcum->num_sme_mode_switch_args = 0; + pcum->aapcs_vfp_rmode = VOIDmode; if (!silent_p && !TARGET_FLOAT @@ -7255,9 +7421,11 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, || pcum->pcs_variant == ARM_PCS_SVE) { aarch64_layout_arg (pcum_v, arg); - gcc_assert ((pcum->aapcs_reg != NULL_RTX) - != (pcum->aapcs_stack_words != 0)); - if (pcum->aapcs_reg + pcum->darwinpcs_n_args_processed++; + gcc_assert (TARGET_MACHO + || (pcum->aapcs_reg != NULL_RTX) + != (pcum->aapcs_stack_words != 0)); + if (pcum->aapcs_reg && aarch64_call_switches_pstate_sm (pcum->isa_mode)) aarch64_record_sme_mode_switch_args (pcum); @@ -7268,6 +7436,12 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, pcum->aapcs_stack_size += pcum->aapcs_stack_words; pcum->aapcs_stack_words = 0; pcum->aapcs_reg = NULL_RTX; + pcum->darwinpcs_arg_boundary = BITS_PER_UNIT; + pcum->darwinpcs_arg_padding = BITS_PER_UNIT; + pcum->named_p + = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; + pcum->last_named_p + = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; } } @@ -7279,12 +7453,15 @@ aarch64_function_arg_regno_p (unsigned regno) || (PR_REGNUM_P (regno) && regno < P0_REGNUM + NUM_PR_ARG_REGS)); } -/* Implement FUNCTION_ARG_BOUNDARY. Every parameter gets at least - PARM_BOUNDARY bits of alignment, but will be given anything up - to STACK_BOUNDARY bits if the type requires it. This makes sure - that both before and after the layout of each argument, the Next - Stacked Argument Address (NSAA) will have a minimum alignment of - 8 bytes. */ +/* Implement FUNCTION_ARG_BOUNDARY. + For AAPCS64, Every parameter gets at least PARM_BOUNDARY bits of + alignment, but will be given anything up to STACK_BOUNDARY bits + if the type requires it. This makes sure that both before and after + the layout of each argument, the Next Stacked Argument Address (NSAA) + will have a minimum alignment of 8 bytes. + + For darwinpcs, this is only called to lower va_arg entries which are + always aligned as for AAPCS64. */ static unsigned int aarch64_function_arg_boundary (machine_mode mode, const_tree type) @@ -7298,8 +7475,108 @@ aarch64_function_arg_boundary (machine_mode mode, const_tree type) &abi_break_gcc_14); /* We rely on aarch64_layout_arg and aarch64_gimplify_va_arg_expr to emit warnings about ABI incompatibility. */ +#if TARGET_MACHO + /* This can only work for unnamed args. */ + machine_mode comp_mode = VOIDmode; + int nregs; + bool is_ha; + aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, + &is_ha, /*silent*/true); + if (TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) + || TREE_CODE (type) == UNION_TYPE) + return MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); + return MIN (alignment, STACK_BOUNDARY); +#else + alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); + return alignment; +#endif +} + +/* For Darwin, we want to use the arg boundary computed when laying out the + function arg, to cope with items packed on the stack and the different + rules applied to unnamed parms. */ + +static unsigned int +aarch64_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + unsigned int abi_break_gcc_9; + unsigned int abi_break_gcc_13; + unsigned int abi_break_gcc_14; + unsigned int alignment + = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, + &abi_break_gcc_13, &abi_break_gcc_14); + /* We rely on aarch64_layout_arg and aarch64_gimplify_va_arg_expr + to emit warnings about ABI incompatibility. */ +#if TARGET_MACHO + CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); +gcc_checking_assert (pcum->aapcs_arg_processed); + + bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; +gcc_checking_assert (named_p == pcum->named_p); + machine_mode comp_mode = VOIDmode; + int nregs; + bool is_ha; + aarch64_vfp_is_call_or_return_candidate (mode, type, &comp_mode, &nregs, + &is_ha, /*silent*/true); + bool no_pack = (TREE_CODE (type) == COMPLEX_TYPE + || (TREE_CODE (type) == RECORD_TYPE + && !is_ha && !SCALAR_FLOAT_MODE_P (comp_mode)) + || TREE_CODE (type) == UNION_TYPE); + + bool in_regs = (pcum->aapcs_reg != NULL_RTX); + + if ((named_p && !no_pack) || in_regs) + ; /* Leave the alignment as natural. */ + else + alignment = MAX (alignment, PARM_BOUNDARY); +gcc_checking_assert (alignment == pcum->darwinpcs_arg_boundary); + return MIN (alignment, STACK_BOUNDARY); + +#else alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); return alignment; +#endif +} + +/* Implement TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA for darwinpcs which allows + non-standard passing of byte-aligned items [D.2]. This is done by pulling + the values out of the cumulative args struct. */ + +static unsigned int +aarch64_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); +gcc_checking_assert (pcum->aapcs_arg_processed); + bool named_p = pcum->darwinpcs_n_args_processed < pcum->darwinpcs_n_named; +gcc_checking_assert (named_p == pcum->named_p); + bool last_named_p = pcum->darwinpcs_n_args_processed + 1 == pcum->darwinpcs_n_named; +gcc_checking_assert (last_named_p == pcum->last_named_p); + + unsigned boundary = BITS_PER_UNIT; + if (last_named_p && pcum->darwinpcs_sub_word_pos > 0) + { + /* Round the last named arg to the start of the next stack slot. */ + if (pcum->darwinpcs_sub_word_pos <= 4) + boundary = PARM_BOUNDARY; + else if (pcum->darwinpcs_sub_word_pos <= 6) + boundary = 4 * BITS_PER_UNIT; + else if (pcum->darwinpcs_sub_word_pos <= 7) + boundary = 2 * BITS_PER_UNIT; + } + else if (named_p) + /* Named args are naturally aligned, but with no rounding. */ + ; + else + /* un-named args are rounded to fill slots. */ + boundary = PARM_BOUNDARY; +gcc_checking_assert (boundary == pcum->darwinpcs_arg_padding); + return boundary; } /* Implement TARGET_GET_RAW_RESULT_MODE and TARGET_GET_RAW_ARG_MODE. */ @@ -10698,6 +10975,7 @@ aarch64_classify_address (struct aarch64_address_info *info, /* load literal: pc-relative constant pool entry. Only supported for SI mode or larger. */ info->type = ADDRESS_SYMBOLIC; + info->offset = NULL_RTX; if (!load_store_pair_p && GET_MODE_SIZE (mode).is_constant (&const_size) @@ -10705,6 +10983,7 @@ aarch64_classify_address (struct aarch64_address_info *info, { poly_int64 offset; rtx sym = strip_offset_and_salt (x, &offset); + return ((LABEL_REF_P (sym) || (SYMBOL_REF_P (sym) && CONSTANT_POOL_ADDRESS_P (sym) @@ -10722,10 +11001,13 @@ aarch64_classify_address (struct aarch64_address_info *info, poly_int64 offset; HOST_WIDE_INT const_offset; rtx sym = strip_offset_and_salt (info->offset, &offset); + if (SYMBOL_REF_P (sym) && offset.is_constant (&const_offset) && (aarch64_classify_symbol (sym, const_offset) - == SYMBOL_SMALL_ABSOLUTE)) + == SYMBOL_SMALL_ABSOLUTE + || aarch64_classify_symbol (sym, const_offset) + == SYMBOL_MO_SMALL_PCR)) { /* The symbol and offset must be aligned to the access size. */ unsigned int align; @@ -10775,6 +11057,55 @@ aarch64_address_valid_for_prefetch_p (rtx x, bool strict_p) if (!res) return false; + /* For ELF targets using GAS, we emit prfm unconditionally; GAS will alter + the instruction to pick the prfum form where possible (i.e. when the + offset is in the range -256..255) and fall back to prfm otherwise. + We can reject cases where the offset exceeds the range usable by both + insns [-256..32760], or for offsets > 255 when the value is not divisible + by 8. + For Mach-O (Darwin) where the assembler uses the LLVM back end, that does + not yet do the substitution, so we must reject all prfum cases. */ + if (addr.offset) + { + HOST_WIDE_INT offs = INTVAL (addr.offset); + if (offs < -256) /* Out of range for both prfum and prfm. */ + return false; + if (offs > 32760) /* Out of range for prfm. */ + return false; + if (offs & 0x07) /* We cannot use prfm. */ + { + if (offs > 255) /* Out of range for prfum. */ + return false; + if (TARGET_MACHO) + return false; + } + if (TARGET_MACHO && offs < 0) + return false; + } + + /* ... except writeback forms. */ + return addr.type != ADDRESS_REG_WB; +} + +/* Return true if the address X is valid for a PRFUM instruction. + STRICT_P is true if we should do strict checking with + aarch64_classify_address. */ + +bool +aarch64_address_valid_for_unscaled_prefetch_p (rtx x, bool strict_p) +{ + struct aarch64_address_info addr; + + /* PRFUM accepts the same addresses as DImode, but constrained to a range + -256..255. */ + bool res = aarch64_classify_address (&addr, x, DImode, strict_p); + if (!res) + return false; + + if (addr.offset && ((INTVAL (addr.offset) > 255) + || (INTVAL (addr.offset) < -256))) + return false; + /* ... except writeback forms. */ return addr.type != ADDRESS_REG_WB; } @@ -11908,6 +12239,144 @@ sizetochar (int size) } } +static void +output_macho_postfix_expr (FILE *file, rtx x, const char *postfix) +{ + char buf[256]; + + restart: + switch (GET_CODE (x)) + { + case PC: + putc ('.', file); + break; + + case SYMBOL_REF: + if (SYMBOL_REF_DECL (x)) + assemble_external (SYMBOL_REF_DECL (x)); + assemble_name (file, XSTR (x, 0)); + fprintf (file, "@%s", postfix); + break; + + case LABEL_REF: + x = label_ref_label (x); + /* Fall through. */ + case CODE_LABEL: + ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x)); + assemble_name (file, buf); + fprintf (file, "@%s", postfix); + break; + + case CONST_INT: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); + break; + + case CONST: + /* This used to output parentheses around the expression, + but that does not work on the 386 (either ATT or BSD assembler). */ + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + break; + + case CONST_WIDE_INT: + /* We do not know the mode here so we have to use a round about + way to build a wide-int to get it printed properly. */ + { + wide_int w = wide_int::from_array (&CONST_WIDE_INT_ELT (x, 0), + CONST_WIDE_INT_NUNITS (x), + CONST_WIDE_INT_NUNITS (x) + * HOST_BITS_PER_WIDE_INT, + false); + print_decs (w, file); + } + break; + + case CONST_DOUBLE: + if (CONST_DOUBLE_AS_INT_P (x)) + { + /* We can use %d if the number is one word and positive. */ + if (CONST_DOUBLE_HIGH (x)) + fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + (unsigned HOST_WIDE_INT) CONST_DOUBLE_HIGH (x), + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); + else if (CONST_DOUBLE_LOW (x) < 0) + fprintf (file, HOST_WIDE_INT_PRINT_HEX, + (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (x)); + else + fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x)); + } + else + /* We can't handle floating point constants; + PRINT_OPERAND must handle them. */ + output_operand_lossage ("floating constant misused"); + break; + + case CONST_FIXED: + fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_FIXED_VALUE_LOW (x)); + break; + + case PLUS: + /* Some assemblers need integer constants to appear last (eg masm). */ + if (CONST_INT_P (XEXP (x, 0))) + { + output_macho_postfix_expr (file, XEXP (x, 1), postfix); + if (INTVAL (XEXP (x, 0)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 0)); + } + else + { + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + if (!CONST_INT_P (XEXP (x, 1)) + || INTVAL (XEXP (x, 1)) >= 0) + fprintf (file, "+"); + output_addr_const (file, XEXP (x, 1)); + } + break; + + case MINUS: + /* Avoid outputting things like x-x or x+5-x, + since some assemblers can't handle that. */ + x = simplify_subtraction (x); + if (GET_CODE (x) != MINUS) + goto restart; + + output_macho_postfix_expr (file, XEXP (x, 0), postfix); + fprintf (file, "-"); + if ((CONST_INT_P (XEXP (x, 1)) && INTVAL (XEXP (x, 1)) >= 0) + || GET_CODE (XEXP (x, 1)) == PC + || GET_CODE (XEXP (x, 1)) == SYMBOL_REF) + output_addr_const (file, XEXP (x, 1)); + else + { + fputs (targetm.asm_out.open_paren, file); + output_addr_const (file, XEXP (x, 1)); + fputs (targetm.asm_out.close_paren, file); + } + break; + + case ZERO_EXTEND: + case SIGN_EXTEND: + case SUBREG: + case TRUNCATE: + output_addr_const (file, XEXP (x, 0)); + break; + + case UNSPEC: + if (XINT (x, 1) == UNSPEC_SALT_ADDR) + { + output_macho_postfix_expr (file, XVECEXP (x, 0, 0), postfix); + break; + } + /* FALLTHROUGH */ + default: + if (targetm.asm_out.output_addr_const_extra (file, x)) + break; + + output_operand_lossage ("invalid expression as operand"); + } + +} + /* Print operand X to file F in a target specific manner according to CODE. The acceptable formatting commands given by CODE are: 'c': An integer or symbol address without a preceding # @@ -11981,6 +12450,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) } break; + case 'J': + output_macho_postfix_expr (f, x, "PAGEOFF"); + break; + case 'O': + output_macho_postfix_expr (f, x, "GOTPAGEOFF"); + break; case 'e': { x = unwrap_const_vec_duplicate (x); @@ -12313,7 +12788,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) case 'A': if (GET_CODE (x) == HIGH) x = XEXP (x, 0); - +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_SMALL_GOT_4G: @@ -12344,9 +12819,26 @@ aarch64_print_operand (FILE *f, rtx x, int code) break; } output_addr_const (asm_out_file, x); +#endif +#if TARGET_MACHO + switch (aarch64_classify_symbolic_expression (x)) + { + case SYMBOL_MO_SMALL_PCR: + output_macho_postfix_expr (asm_out_file, x, "PAGE"); + break; + case SYMBOL_MO_SMALL_GOT: + output_macho_postfix_expr (asm_out_file, x, "GOTPAGE"); + break; + default: + /* large code model unimplemented. */ + gcc_unreachable (); + break; + } +#endif break; case 'L': +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_SMALL_GOT_4G: @@ -12384,10 +12876,12 @@ aarch64_print_operand (FILE *f, rtx x, int code) default: break; } +#endif output_addr_const (asm_out_file, x); break; case 'G': +#if !TARGET_MACHO switch (aarch64_classify_symbolic_expression (x)) { case SYMBOL_TLSLE24: @@ -12396,6 +12890,7 @@ aarch64_print_operand (FILE *f, rtx x, int code) default: break; } +#endif output_addr_const (asm_out_file, x); break; @@ -12561,8 +13056,13 @@ aarch64_print_address_internal (FILE *f, machine_mode mode, rtx x, break; case ADDRESS_LO_SUM: +#if TARGET_MACHO + asm_fprintf (f, "[%s, #", reg_names [REGNO (addr.base)]); + output_macho_postfix_expr (f, addr.offset, "PAGEOFF"); +#else asm_fprintf (f, "[%s, #:lo12:", reg_names [REGNO (addr.base)]); output_addr_const (f, addr.offset); +#endif asm_fprintf (f, "]"); return true; @@ -12870,7 +13370,23 @@ aarch64_frame_pointer_required () { /* If the function needs to record the incoming value of PSTATE.SM, make sure that the slot is accessible from the frame pointer. */ - return aarch64_need_old_pstate_sm (); + if (!TARGET_MACHO) + return aarch64_need_old_pstate_sm (); + + /* We could do with some more general test. + gcc_checking_assert (!aarch64_need_old_pstate_sm ());*/ + + if (crtl->calls_eh_return || aarch64_need_old_pstate_sm ()) + return true; + + /* Not used in leaf functions (unless forced). */ + if (flag_omit_leaf_frame_pointer && leaf_function_p ()) + return false; + + /* NOTE: We are allowing the user to force omission of the frame + pointer, (despite that it is not ABI-compliant). */ + + return flag_omit_frame_pointer != 1; } static bool @@ -13098,6 +13614,8 @@ aarch64_asm_output_labelref (FILE* f, const char *name) asm_fprintf (f, "%U%s", name); } +#if !TARGET_MACHO + static void aarch64_elf_asm_constructor (rtx symbol, int priority) { @@ -13137,6 +13655,7 @@ aarch64_elf_asm_destructor (rtx symbol, int priority) assemble_aligned_integer (POINTER_BYTES, symbol); } } +#endif const char* aarch64_output_casesi (rtx *operands) @@ -13289,7 +13808,11 @@ aarch64_select_rtx_section (machine_mode mode, if (aarch64_can_use_per_function_literal_pools_p ()) return function_section (current_function_decl); +#if TARGET_MACHO + return machopic_select_rtx_section (mode, x, align); +#else return default_elf_select_rtx_section (mode, x, align); +#endif } /* Implement ASM_OUTPUT_POOL_EPILOGUE. */ @@ -15559,15 +16082,17 @@ aarch64_init_builtins () { aarch64_general_init_builtins (); aarch64_sve::init_builtins (); -#ifdef SUBTARGET_INIT_BUILTINS - SUBTARGET_INIT_BUILTINS; -#endif + aarch64_init_subtarget_builtins (); } /* Implement TARGET_FOLD_BUILTIN. */ static tree aarch64_fold_builtin (tree fndecl, int nargs, tree *args, bool) { +#ifdef SUBTARGET_FOLD_BUILTIN + if (tree res = SUBTARGET_FOLD_BUILTIN (fndecl, nargs, args, false)) + return res; +#endif unsigned int code = DECL_MD_FUNCTION_CODE (fndecl); unsigned int subcode = code >> AARCH64_BUILTIN_SHIFT; tree type = TREE_TYPE (TREE_TYPE (fndecl)); @@ -18979,10 +19504,14 @@ initialize_aarch64_code_model (struct gcc_options *opts) } break; case AARCH64_CMODEL_LARGE: - if (opts->x_flag_pic) + if (TARGET_MACHO) + /* We need to implement fPIC here (arm64_32 also accepts the large + model). */ + sorry ("code model %qs not supported yet", "large"); + else if (opts->x_flag_pic) sorry ("code model %qs with %<-f%s%>", "large", opts->x_flag_pic > 1 ? "PIC" : "pic"); - if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) + else if (opts->x_aarch64_abi == AARCH64_ABI_ILP32) sorry ("code model %qs not supported in ilp32 mode", "large"); break; case AARCH64_CMODEL_TINY_PIC: @@ -20899,7 +21428,9 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: case AARCH64_CMODEL_SMALL: - return SYMBOL_SMALL_ABSOLUTE; + return TARGET_MACHO + ? SYMBOL_MO_SMALL_PCR + : SYMBOL_SMALL_ABSOLUTE; default: gcc_unreachable (); @@ -20935,10 +21466,22 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) return SYMBOL_TINY_ABSOLUTE; - case AARCH64_CMODEL_SMALL_SPIC: case AARCH64_CMODEL_SMALL_PIC: case AARCH64_CMODEL_SMALL: +#if TARGET_MACHO + if (TARGET_MACHO) + { + /* Constant pool addresses are always TU-local and PC- + relative. We indirect common, external and weak + symbols (but weak only if not hidden). */ + if (!CONSTANT_POOL_ADDRESS_P (x) + && (MACHO_SYMBOL_MUST_INDIRECT_P (x) + || !aarch64_symbol_binds_local_p (x))) + return SYMBOL_MO_SMALL_GOT; + } + else +#endif if ((flag_pic || SYMBOL_REF_WEAK (x)) && !aarch64_symbol_binds_local_p (x)) return aarch64_cmodel == AARCH64_CMODEL_SMALL_SPIC @@ -20950,7 +21493,8 @@ aarch64_classify_symbol (rtx x, HOST_WIDE_INT offset) || offset_within_block_p (x, offset))) return SYMBOL_FORCE_TO_MEM; - return SYMBOL_SMALL_ABSOLUTE; + return TARGET_MACHO ? SYMBOL_MO_SMALL_PCR + : SYMBOL_SMALL_ABSOLUTE; case AARCH64_CMODEL_LARGE: /* This is alright even in PIC code as the constant @@ -21080,7 +21624,10 @@ static GTY(()) tree va_list_type; void *__vr_top; int __gr_offs; int __vr_offs; - }; */ + }; + + darwinpcs uses 'char *' for the va_list (in common with other platform + ports). */ static tree aarch64_build_builtin_va_list (void) @@ -21088,6 +21635,13 @@ aarch64_build_builtin_va_list (void) tree va_list_name; tree f_stack, f_grtop, f_vrtop, f_groff, f_vroff; + /* darwinpcs uses a simple char * for this. */ + if (TARGET_MACHO) + { + va_list_type = build_pointer_type (char_type_node); + return va_list_type; + } + /* Create the type. */ va_list_type = lang_hooks.types.make_type (RECORD_TYPE); /* Give it the required name. */ @@ -21159,6 +21713,13 @@ aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) int vr_save_area_size = cfun->va_list_fpr_size; int vr_offset; + /* darwinpcs uses the default, char * va_list impl. */ + if (TARGET_MACHO) + { + std_expand_builtin_va_start (valist, nextarg); + return; + } + cum = &crtl->args.info; if (cfun->va_list_gpr_size) gr_save_area_size = MIN ((NUM_ARG_REGS - cum->aapcs_ncrn) * UNITS_PER_WORD, @@ -21249,6 +21810,9 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, HOST_WIDE_INT size, rsize, adjust, align; tree t, u, cond1, cond2; + if (TARGET_MACHO) + return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); + indirect_p = pass_va_arg_by_reference (type); if (indirect_p) type = build_pointer_type (type); @@ -21453,8 +22017,18 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, field_ptr_t = double_ptr_type_node; break; case E_TFmode: - field_t = long_double_type_node; - field_ptr_t = long_double_ptr_type_node; + if (TARGET_MACHO) + { + /* Darwin has __float128, and long double is the same as + double. */ + field_t = float128_type_node; + field_ptr_t = aarch64_float128_ptr_type_node; + } + else + { + field_t = long_double_type_node; + field_ptr_t = long_double_ptr_type_node; + } break; case E_SDmode: field_t = dfloat32_type_node; @@ -21537,6 +22111,9 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v, int gr_saved = cfun->va_list_gpr_size; int vr_saved = cfun->va_list_fpr_size; + if (TARGET_MACHO) + return default_setup_incoming_varargs (cum_v, arg, pretend_size, no_rtl); + /* The caller has advanced CUM up to, but not beyond, the last named argument. Advance a local copy of CUM past the last "real" named argument, to find out how many registers are left over. */ @@ -22380,6 +22957,12 @@ aarch64_autovectorize_vector_modes (vector_modes *modes, bool) static const char * aarch64_mangle_type (const_tree type) { + /* The darwinpcs ABI documents say that "__va_list" has to be + mangled as char *. */ + if (TARGET_MACHO + && lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) + return "Pc"; + /* The AArch64 ABI documents say that "__va_list" has to be mangled as if it is in the "std" namespace. */ if (lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) @@ -22396,6 +22979,12 @@ aarch64_mangle_type (const_tree type) return "Dh"; } + /* __float128 is mangled as "g" on darwin. _Float128 is not mangled here, + but handled in common code (as "DF128_"). */ + if (TARGET_MACHO && TYPE_MODE (type) == TFmode + && TYPE_MAIN_VARIANT (type) == float128t_type_node) + return "g"; + /* Mangle AArch64-specific internal types. TYPE_NAME is non-NULL_TREE for builtin types. */ if (TYPE_NAME (type) != NULL) @@ -23093,7 +23682,8 @@ aarch64_mov_operand_p (rtx x, machine_mode mode) /* GOT accesses are valid moves. */ if (SYMBOL_REF_P (x) - && aarch64_classify_symbolic_expression (x) == SYMBOL_SMALL_GOT_4G) + && (aarch64_classify_symbolic_expression (x) == SYMBOL_SMALL_GOT_4G + || aarch64_classify_symbolic_expression (x) == SYMBOL_MO_SMALL_GOT)) return true; if (SYMBOL_REF_P (x) && mode == DImode && CONSTANT_ADDRESS_P (x)) @@ -24430,12 +25020,8 @@ aarch64_asm_output_variant_pcs (FILE *stream, const tree decl, const char* name) static std::string aarch64_last_printed_arch_string; static std::string aarch64_last_printed_tune_string; -/* Implement ASM_DECLARE_FUNCTION_NAME. Output the ISA features used - by the function fndecl. */ - -void -aarch64_declare_function_name (FILE *stream, const char* name, - tree fndecl) +static void +aarch64_function_options_preamble (tree fndecl) { tree target_parts = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); @@ -24474,15 +25060,60 @@ aarch64_declare_function_name (FILE *stream, const char* name, this_tune->name); aarch64_last_printed_tune_string = this_tune->name; } +} + +/* Implement ASM_DECLARE_FUNCTION_NAME. Output the ISA features used + by the function fndecl. */ + +#if TARGET_MACHO +void +aarch64_darwin_declare_function_name (FILE *stream, const char* name, + tree fndecl) +{ + gcc_checking_assert (TREE_CODE (fndecl) == FUNCTION_DECL); + gcc_checking_assert (!DECL_COMMON (fndecl)); + /* Update .arch and .tune as needed. */ + aarch64_function_options_preamble (fndecl); + + /* Darwin does not emit pcs variant info. */ + + rtx decl_rtx = XEXP (DECL_RTL (fndecl), 0); + if (GET_CODE (decl_rtx) != SYMBOL_REF) + name = IDENTIFIER_POINTER (DECL_NAME (fndecl)); + + if (! DECL_WEAK (fndecl) + && ((TREE_STATIC (fndecl) && !TREE_PUBLIC (fndecl)) + || DECL_INITIAL (fndecl))) + machopic_define_symbol (DECL_RTL (fndecl)); + if ((TREE_STATIC (fndecl) && !TREE_PUBLIC (fndecl)) + || DECL_INITIAL (fndecl)) + (* targetm.encode_section_info) (fndecl, DECL_RTL (fndecl), false); + ASM_OUTPUT_FUNCTION_LABEL (stream, name, fndecl); + + cfun->machine->label_is_assembled = true; +} + +#else + +void +aarch64_declare_function_name (FILE *stream, const char* name, + tree fndecl) +{ + /* Update .arch and .tune as needed. */ + aarch64_function_options_preamble (fndecl); + /* Emit any necessary pcs information. */ aarch64_asm_output_variant_pcs (stream, fndecl, name); /* Don't forget the type directive for ELF. */ +#ifdef ASM_OUTPUT_TYPE_DIRECTIVE ASM_OUTPUT_TYPE_DIRECTIVE (stream, name, "function"); +#endif ASM_OUTPUT_FUNCTION_LABEL (stream, name, fndecl); cfun->machine->label_is_assembled = true; } +#endif /* Implement PRINT_PATCHABLE_FUNCTION_ENTRY. */ @@ -24539,12 +25170,17 @@ aarch64_output_patchable_area (unsigned int patch_area_size, bool record_p) /* Implement ASM_OUTPUT_DEF_FROM_DECLS. Output .variant_pcs for aliases. */ void -aarch64_asm_output_alias (FILE *stream, const tree decl, const tree target) +aarch64_asm_output_alias (FILE *stream, const tree decl, + const tree target ATTRIBUTE_UNUSED) { const char *name = XSTR (XEXP (DECL_RTL (decl), 0), 0); +#ifdef ASM_OUTPUT_DEF const char *value = IDENTIFIER_POINTER (target); +#endif aarch64_asm_output_variant_pcs (stream, decl, name); +#ifdef ASM_OUTPUT_DEF ASM_OUTPUT_DEF (stream, name, value); +#endif } /* Implement ASM_OUTPUT_EXTERNAL. Output .variant_pcs for undefined @@ -24590,6 +25226,9 @@ aarch64_start_file (void) aarch64_last_printed_arch_string.c_str ()); default_file_start (); +#if TARGET_MACHO + darwin_file_start (); +#endif } /* Emit load exclusive. */ @@ -25169,6 +25808,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, } gcc_assert (CONST_INT_P (info.u.mov.value)); + unsigned HOST_WIDE_INT value = UINTVAL (info.u.mov.value); + + /* We have signed chars which can result in a sign-extended 8bit value + which is then emitted as an unsigned hex value, and the LLVM back end + assembler rejects that as being too big. */ + if (TARGET_MACHO && (known_eq (GET_MODE_BITSIZE (info.elt_mode), 8))) + { + unsigned HOST_WIDE_INT mask = (1U << GET_MODE_BITSIZE (info.elt_mode))-1; + value &= mask; + } if (which == AARCH64_CHECK_MOV) { @@ -25177,16 +25826,16 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, ? "msl" : "lsl"); if (lane_count == 1) snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX, - mnemonic, UINTVAL (info.u.mov.value)); + mnemonic, value); else if (info.u.mov.shift) snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX ", %s %d", mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value), shift_op, + element_char, value, shift_op, info.u.mov.shift); else snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX, mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value)); + element_char, value); } else { @@ -25195,12 +25844,12 @@ aarch64_output_simd_mov_immediate (rtx const_vector, unsigned width, if (info.u.mov.shift) snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value), "lsl", + element_char, value, "lsl", info.u.mov.shift); else snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #" HOST_WIDE_INT_PRINT_DEC, mnemonic, lane_count, - element_char, UINTVAL (info.u.mov.value)); + element_char, value); } return templ; } @@ -28437,7 +29086,8 @@ aarch64_libgcc_floating_mode_supported_p (scalar_float_mode mode) } /* Implement TARGET_SCALAR_MODE_SUPPORTED_P - return TRUE - if MODE is [BH]Fmode, and punt to the generic implementation otherwise. */ + if MODE is [BH]Fmode, or TFmode on Mach-O, and punt to the generic + implementation otherwise. */ static bool aarch64_scalar_mode_supported_p (scalar_mode mode) @@ -28445,7 +29095,7 @@ aarch64_scalar_mode_supported_p (scalar_mode mode) if (DECIMAL_FLOAT_MODE_P (mode)) return default_decimal_float_supported_p (); - return ((mode == HFmode || mode == BFmode) + return ((mode == HFmode || mode == BFmode || (mode == TFmode && TARGET_MACHO)) ? true : default_scalar_mode_supported_p (mode)); } @@ -29262,19 +29912,37 @@ aarch64_sls_emit_shared_blr_thunks (FILE *out_file) continue; const char *name = indirect_symbol_names[regnum]; - switch_to_section (get_named_section (decl, NULL, 0)); + /* If the target uses a unique section for this switch to it. */ + if (DECL_SECTION_NAME (decl)) + switch_to_section (get_named_section (decl, NULL, 0)); + else + switch_to_section (text_section); ASM_OUTPUT_ALIGN (out_file, 2); - targetm.asm_out.globalize_label (out_file, name); + if (!TARGET_MACHO) + targetm.asm_out.globalize_label (out_file, name); +#ifdef ASM_OUTPUT_TYPE_DIRECTIVE + ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); +#endif + if (TARGET_MACHO) + { +#ifdef ASM_WEAKEN_DECL + if (DECL_WEAK (decl)) + ASM_WEAKEN_DECL (out_file, decl, name, 0); + else +#endif + targetm.asm_out.globalize_decl_name (out_file, decl); + } /* Only emits if the compiler is configured for an assembler that can handle visibility directives. */ targetm.asm_out.assemble_visibility (decl, VISIBILITY_HIDDEN); - ASM_OUTPUT_TYPE_DIRECTIVE (out_file, name, "function"); ASM_OUTPUT_LABEL (out_file, name); aarch64_sls_emit_function_stub (out_file, regnum); /* Use the most conservative target to ensure it can always be used by any function in the translation unit. */ asm_fprintf (out_file, "\tdsb\tsy\n\tisb\n"); +#ifdef ASM_DECLARE_FUNCTION_SIZE ASM_DECLARE_FUNCTION_SIZE (out_file, name, decl); +#endif } } @@ -30366,6 +31034,60 @@ aarch64_retrieve_sysreg (const char *regname, bool write_p, bool is128op) return sysreg->encoding; } +#if TARGET_MACHO +/* This handles the promotion of function return values. + It also handles function args under two specific curcumstances: + - called from combine with a register argument + - caller for a libcall with type == NULL. + The remaining cases for argument promotion are handled with access to + cumulative args data, below. */ +machine_mode +aarch64_darwin_promote_fn_mode (const_tree type, machine_mode mode, + int *punsignedp, + const_tree funtype ATTRIBUTE_UNUSED, + int for_return ATTRIBUTE_UNUSED) +{ + /* With the amended use of promote using cargs, the only cases that arrive + here with for_return == 0 are from combine (where the value is definitely + in a register) and for libcalls, where type == NULL. We want to promote + function return values in the callee, so this becomes pretty much + unconditional now. */ + if (type != NULL_TREE) + return promote_mode (type, mode, punsignedp); + return mode; +} + +/* Ensure that we only promote the mode of named parms when they are passed in + a register. Named values passed on the stack retain their original mode and + alignment. */ +machine_mode +aarch64_darwin_promote_function_mode_ca (cumulative_args_t ca, + function_arg_info arg, + const_tree funtype ATTRIBUTE_UNUSED, + int *punsignedp, + int for_return ATTRIBUTE_UNUSED) +{ + tree type = arg.type; + machine_mode mode = arg.mode; + machine_mode new_mode = promote_mode (type, mode, punsignedp); + if (new_mode == mode || arg.named == false + || GET_MODE_CLASS (new_mode) != MODE_INT + || known_gt (GET_MODE_SIZE (new_mode), 4)) + return new_mode; + + CUMULATIVE_ARGS *pcum = get_cumulative_args (ca); + /* Make sure that changes in assumption do not get missed. */ + gcc_checking_assert (for_return == 0 && new_mode == SImode + && !pcum->aapcs_arg_processed); + /* We have a named integer value that fits in a reg; if there's one available + then promote the value. */ + if (pcum->aapcs_ncrn < 8) + return new_mode; + return mode; +} + +#endif + /* Target-specific selftests. */ #if CHECKING_P @@ -30571,6 +31293,15 @@ aarch64_run_selftests (void) #undef TARGET_ASM_ALIGNED_SI_OP #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t" +#if TARGET_MACHO +#undef TARGET_ASM_UNALIGNED_HI_OP +#define TARGET_ASM_UNALIGNED_HI_OP "\t.short\t" +#undef TARGET_ASM_UNALIGNED_SI_OP +#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" +#undef TARGET_ASM_UNALIGNED_DI_OP +#define TARGET_ASM_UNALIGNED_DI_OP "\t.quad\t" +#endif + #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK #define TARGET_ASM_CAN_OUTPUT_MI_THUNK \ hook_bool_const_tree_hwi_hwi_const_tree_true @@ -30673,6 +31404,12 @@ aarch64_run_selftests (void) #undef TARGET_FUNCTION_ARG_BOUNDARY #define TARGET_FUNCTION_ARG_BOUNDARY aarch64_function_arg_boundary +#undef TARGET_FUNCTION_ARG_BOUNDARY_CA +#define TARGET_FUNCTION_ARG_BOUNDARY_CA aarch64_function_arg_boundary_ca + +#undef TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA +#define TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA aarch64_function_arg_round_boundary_ca + #undef TARGET_FUNCTION_ARG_PADDING #define TARGET_FUNCTION_ARG_PADDING aarch64_function_arg_padding @@ -31013,7 +31750,7 @@ aarch64_libgcc_floating_mode_supported_p /* The architecture reserves bits 0 and 1 so use bit 2 for descriptors. */ #undef TARGET_CUSTOM_FUNCTION_DESCRIPTORS -#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS 4 +#define TARGET_CUSTOM_FUNCTION_DESCRIPTORS AARCH64_CUSTOM_FUNCTION_TEST #undef TARGET_HARD_REGNO_NREGS #define TARGET_HARD_REGNO_NREGS aarch64_hard_regno_nregs diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 4fa1dfc7906..84344e50fad 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -72,6 +72,10 @@ #define TARGET_SIMD (AARCH64_ISA_SIMD && AARCH64_ISA_SM_OFF) #define TARGET_FLOAT (AARCH64_ISA_FP) +/* If this is non-zero then generated code of the object format, ABI and + assembler syntax used by Darwin (Mach-O) platforms. */ +#define TARGET_MACHO 0 + #define UNITS_PER_WORD 8 #define UNITS_PER_VREG 16 @@ -149,6 +153,12 @@ /* Heap alignment (same as BIGGEST_ALIGNMENT and STACK_BOUNDARY). */ #define MALLOC_ABI_ALIGNMENT 128 +/* We will and with this value to test if a custom function descriptor needs + a static chain. The function boundary must the adjusted so that the bit + this represents is no longer part of the address. 0 Disables the custom + function descriptors. */ +#define AARCH64_CUSTOM_FUNCTION_TEST 4 + /* Defined by the ABI */ #define WCHAR_TYPE "unsigned int" #define WCHAR_TYPE_SIZE 32 @@ -1146,6 +1156,24 @@ typedef struct aapcs_reg == NULL_RTX. */ int aapcs_stack_size; /* The total size (in words, per 8 byte) of the stack arg area so far. */ + + /* In the darwinpcs, items smaller than one word are packed onto the stack + naturally aligned. Unnamed parameters passed in a variadic call are, + however, aligned the same way as the AAPCS64. This means that we need to + pad the last named arg to the next parm boundary (and hence notice when + we are processing that arg). */ + int darwinpcs_stack_bytes; /* If the argument is passed on the stack, this + the byte-size. */ + int darwinpcs_sub_word_offset;/* This is the offset of this arg within a word + when placing smaller items for darwinpcs. */ + int darwinpcs_sub_word_pos; /* The next byte available within the word for + darwinpcs. */ + unsigned darwinpcs_arg_boundary; /* The computed argument boundary. */ + unsigned darwinpcs_arg_padding; /* The computed argument padding. */ + unsigned darwinpcs_n_named; /* Number of named arguments. */ + unsigned darwinpcs_n_args_processed; /* Processed so far. */ + bool named_p; /* Is this arg named? */ + bool last_named_p; /* Is this the last named arg? */ bool silent_p; /* True if we should act silently, rather than raise an error for invalid calls. */ @@ -1457,8 +1485,13 @@ extern const char *aarch64_rewrite_mcpu (int argc, const char **argv); #define ASM_CPU_SPEC \ MCPU_TO_MARCH_SPEC +#ifndef SUBTARGET_EXTRA_SPECS +#define SUBTARGET_EXTRA_SPECS +#endif + #define EXTRA_SPECS \ - { "asm_cpu_spec", ASM_CPU_SPEC } + { "asm_cpu_spec", ASM_CPU_SPEC }, \ + SUBTARGET_EXTRA_SPECS #define ASM_OUTPUT_POOL_EPILOGUE aarch64_asm_output_pool_epilogue @@ -1471,6 +1504,10 @@ extern GTY(()) tree aarch64_fp16_ptr_type_node; bfloat16_type_node. Defined in aarch64-builtins.cc. */ extern GTY(()) tree aarch64_bf16_ptr_type_node; +/* A pointer to the user-visible __float128 (on Mach-O). Defined in + aarch64-builtins.c. */ +extern GTY(()) tree aarch64_float128_ptr_type_node; + /* The generic unwind code in libgcc does not initialize the frame pointer. So in order to unwind a function using a frame pointer, the very first function that is unwound must save the frame pointer. That way the frame diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index dbde066f747..d1698b5b142 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -363,6 +363,7 @@ ;; Wraps a constant integer that should be multiplied by the number ;; of quadwords in an SME vector. UNSPEC_SME_VQ + UNSPEC_MACHOPIC_OFFSET ; Common to Mach-O ports. ]) (define_c_enum "unspecv" [ @@ -995,6 +996,37 @@ [(set_attr "type" "load_4")] ) +(define_insn "prefetch_unscaled" + [(prefetch (match_operand:DI 0 "aarch64_unscaled_prefetch_operand" "Du") + (match_operand:QI 1 "const_int_operand" "") + (match_operand:QI 2 "const_int_operand" ""))] + "" + { + const char * pftype[2][4] = + { + {"prfum\\tPLDL1STRM, %0", + "prfum\\tPLDL3KEEP, %0", + "prfum\\tPLDL2KEEP, %0", + "prfum\\tPLDL1KEEP, %0"}, + {"prfum\\tPSTL1STRM, %0", + "prfum\\tPSTL3KEEP, %0", + "prfum\\tPSTL2KEEP, %0", + "prfum\\tPSTL1KEEP, %0"}, + }; + + int locality = INTVAL (operands[2]); + + gcc_assert (IN_RANGE (locality, 0, 3)); + + /* PRFUM accepts the same addresses as a 64-bit LDR so wrap + the address into a DImode MEM so that aarch64_print_operand knows + how to print it. */ + operands[0] = gen_rtx_MEM (DImode, operands[0]); + return pftype[INTVAL(operands[1])][locality]; + } + [(set_attr "type" "load_4")] +) + (define_insn "trap" [(trap_if (const_int 1) (const_int 8))] "" @@ -1447,7 +1479,7 @@ [w , m ; load_4 , fp , 4] ldr\t%s0, %1 [m , r Z; store_4 , * , 4] str\t%w1, %0 [m , w ; store_4 , fp , 4] str\t%s1, %0 - [r , Usw; load_4 , * , 8] adrp\t%x0, %A1;ldr\t%w0, [%x0, %L1] + [r , Usw; load_4 , * , 8] << TARGET_MACHO ? \"adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %O1]\" : \"adrp\\t%x0, %A1\;ldr\\t%w0, [%x0, %L1]\"; [r , Usa; adr , * , 4] adr\t%x0, %c1 [r , Ush; adr , * , 4] adrp\t%x0, %A1 [w , r Z; f_mcr , fp , 4] fmov\t%s0, %w1 @@ -1484,7 +1516,7 @@ [w, m ; load_8 , fp , 4] ldr\t%d0, %1 [m, r Z; store_8 , * , 4] str\t%x1, %0 [m, w ; store_8 , fp , 4] str\t%d1, %0 - [r, Usw; load_8 , * , 8] << TARGET_ILP32 ? "adrp\t%0, %A1;ldr\t%w0, [%0, %L1]" : "adrp\t%0, %A1;ldr\t%0, [%0, %L1]"; + [r, Usw; load_8 , * , 8] << TARGET_ILP32 ? (TARGET_MACHO ? \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %O1]\" : \"adrp\\t%0, %A1\;ldr\\t%w0, [%0, %L1]\") : (TARGET_MACHO ? \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %O1]\" : \"adrp\\t%0, %A1\;ldr\\t%0, [%0, %L1]\"); [r, Usa; adr , * , 4] adr\t%x0, %c1 [r, Ush; adr , * , 4] adrp\t%x0, %A1 [w, r Z; f_mcr , fp , 4] fmov\t%d0, %x1 @@ -7387,7 +7419,10 @@ (lo_sum:P (match_operand:P 1 "register_operand" "r") (match_operand 2 "aarch64_valid_symref" "S")))] "" - "add\\t%0, %1, :lo12:%c2" + { return TARGET_MACHO + ? "add\\t%0, %1, %J2;" + : "add\\t%0, %1, :lo12:%c2"; + } [(set_attr "type" "alu_imm")] ) diff --git a/gcc/config/aarch64/aarch64.opt b/gcc/config/aarch64/aarch64.opt index 6356c419399..5c9bb0a9056 100644 --- a/gcc/config/aarch64/aarch64.opt +++ b/gcc/config/aarch64/aarch64.opt @@ -193,6 +193,13 @@ Enum(aarch64_abi) String(ilp32) Value(AARCH64_ABI_ILP32) EnumValue Enum(aarch64_abi) String(lp64) Value(AARCH64_ABI_LP64) +EnumValue +Enum(aarch64_abi) String(darwinpcs) Value(AARCH64_ABI_LP64) + +m64 +Target RejectNegative Alias(mabi=, darwinpcs) +On Darwin for compatibility with other platform variants. + mpc-relative-literal-loads Target Save Var(pcrelative_literal_loads) Init(2) Save PC relative literal loads. diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md index a2569cea510..9ade357cacc 100644 --- a/gcc/config/aarch64/constraints.md +++ b/gcc/config/aarch64/constraints.md @@ -203,7 +203,9 @@ A constraint that matches a small GOT access." (and (match_code "const,symbol_ref") (match_test "aarch64_classify_symbolic_expression (op) - == SYMBOL_SMALL_GOT_4G"))) + == SYMBOL_SMALL_GOT_4G + || aarch64_classify_symbolic_expression (op) + == SYMBOL_MO_SMALL_GOT"))) (define_constraint "Uss" "@internal @@ -574,6 +576,11 @@ An address valid for a prefetch instruction." (match_test "aarch64_address_valid_for_prefetch_p (op, true)")) +(define_address_constraint "Du" + "@internal + An address valid for a prefetch instruction with an unscaled offset." + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, true)")) + (define_constraint "vgb" "@internal A constraint that matches an immediate offset valid for SVE LD1B diff --git a/gcc/config/aarch64/darwin.h b/gcc/config/aarch64/darwin.h new file mode 100644 index 00000000000..4b6bac4cf4b --- /dev/null +++ b/gcc/config/aarch64/darwin.h @@ -0,0 +1,291 @@ +/* Target definitions for Arm64/Aarch64 running on macOS/iOS. + +Copyright The GNU Toolchain Authors. +Contributed by Iain Sandoe. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +. */ + +/* Enable Mach-O bits in generic Aarch64 code. */ +#undef TARGET_MACHO +#define TARGET_MACHO 1 + +#undef DARWIN_ARM64 +#define DARWIN_ARM64 1 + +/* This is used in generic code in darwin.cc (at present, we have no support + for the arm64_32 target). */ +#undef TARGET_64BIT +#define TARGET_64BIT 1 + +#undef PTRDIFF_TYPE +#define PTRDIFF_TYPE "long int" + +#undef TARGET_PROMOTE_FUNCTION_MODE +#define TARGET_PROMOTE_FUNCTION_MODE aarch64_darwin_promote_fn_mode + +#undef TARGET_PROMOTE_FUNCTION_MODE_CA +#define TARGET_PROMOTE_FUNCTION_MODE_CA aarch64_darwin_promote_function_mode_ca + +/* NOTE that arm64_32 is a valid thing and corresponds to darwinpcs + and TARGET_ILP32, but we are not implementing that for now. */ +#define TARGET_OS_CPP_BUILTINS() \ + do { \ + builtin_define ("__LITTLE_ENDIAN__"); \ + builtin_define ("__arm64"); \ + builtin_define ("__arm64__"); \ + darwin_cpp_builtins (pfile); \ + } while (0) + +/* In Darwin's Arm64 ABI, chars are signed. */ + +#undef DEFAULT_SIGNED_CHAR +#define DEFAULT_SIGNED_CHAR 1 + +#undef LONG_DOUBLE_TYPE_SIZE +#define LONG_DOUBLE_TYPE_SIZE 64 + +/* Disable custom function descriptors on Darwin (we use heap-based + trampolines). */ +#undef AARCH64_CUSTOM_FUNCTION_TEST +#define AARCH64_CUSTOM_FUNCTION_TEST 0 + +/* Non-PIE executables are forbidden by the Arm64-darwin security model; + remove the option from link-lines since they just produce a warning from + ld64 and are then ignored anyway. */ +#undef DARWIN_NOPIE_SPEC +#define DARWIN_NOPIE_SPEC \ +" % 10years). Any symbol that is not 'global' and does not begin + with 'L' (the local symbol designation) is counted as 'linker visible'. + * does _not_ support 'static' code in the user space + + Everything needs to be invoked using the dynamic linker (`dyld`). There is + neither crt0.o nor a static edition of libc. + +FIXME: CHECK the kernel model here. + +### Darwin Relocations and Assembler syntax + +* `Mach-O` for `Arm64` uses a reduced set of relocations c.f. the ELF set. + + There are only 11 entries but the relocation format allows for multiple sizes +(1, 2, 4, 8) where that's appropriate, and for ancillary data (e.g. a scale), +so the actual number of permutations is larger. + +* Generally, Darwin supports relocations of the form A - B + signed const + + A must be known (i.e. defined in the current TU). + +* `Mach-O` for `Arm64` has postfix assembler syntax. + + Where there's an assembly language representation for the relocation type + it appears after the name (e.g. `foo@PAGE` in contrast to the ELF + `:got:foo`). + +#### Relocs list + +For pointers (no source representation). + +`ARM64_RELOC_UNSIGNED = 0` + +Must be followed by an `ARM64_RELOC_UNSIGNED` + +`ARM64_RELOC_SUBTRACTOR = 1` + +A B/BL instruction with 26-bit displacement. +(no source representation) + +`ARM64_RELOC_BRANCH26 = 2` + +PC-rel distance to page of target [adrp]. + +`foo@PAGE` + +`ARM64_RELOC_PAGE21 = 3` + +Offset within page, scaled by r_length [add imm, ld/st]. + +`foo@PAGEOFF` + +`ARM64_RELOC_PAGEOFF12 = 4` + +PC-rel distance to page of GOT slot [adrp]. + +`foo@GOTPAGE` +`ARM64_RELOC_GOT_LOAD_PAGE21 = 5` + +Offset within page of GOT slot, scaled by r_length [add imm, ld/st]. + +`foo@GOTPAGEOFF` + +`ARM64_RELOC_GOT_LOAD_PAGEOFF12 = 6` + + +For pointers to GOT slots. +(4 and 8 byte versions) + +`foo@GOT` + +`ARM64_RELOC_POINTER_TO_GOT = 7` + + +PC-rel distance to page of TLVP slot [adrp]. + +`foo@TVLPPAGE` + +`ARM64_RELOC_TLVP_LOAD_PAGE21 = 8` + +Offset within page of TLVP slot, scaled by r_length [add imm, ld/st]. + +`foo@TVLPPAGEOFF` + +`ARM64_RELOC_TLVP_LOAD_PAGEOFF12 = 9` + +Must be followed by `ARM64_RELOC_PAGE21` or `ARM64_RELOC_PAGEOFF12`. +(no source representation) + +The addend is a signed 24bit quantity (+/- 8M range). + +`ARM64_RELOC_ADDEND = 10` + +## PART 2 - GCC-12 deviations from the PCS and supporting information. + +### D.3 is not yet supported (github issue #74) + + GCC promotes in the callee not the caller. + +### Support for nested functions + + GCC provides nested functions which are used overtly from C but also to + implement some parts of Ada and Fortran. + + This requires assigning a register to act as the STATIC CHAIN. + For GCC-12 this is X16 + + Support for nested function trampolines is provided by a heap-based table. + +### Support for __float128 + + The darwinpcs has no provision for a 128bit float type. + GCC-12 supports IEEE741 128bit float values by sof-float. + The ABI used for __float128 matches that for AAPCS64 + +## End. diff --git a/gcc/config/aarch64/driver-aarch64.cc b/gcc/config/aarch64/driver-aarch64.cc index b620351e572..e0e8a8fb8a0 100644 --- a/gcc/config/aarch64/driver-aarch64.cc +++ b/gcc/config/aarch64/driver-aarch64.cc @@ -28,6 +28,74 @@ #include "aarch64-protos.h" #include "aarch64-feature-deps.h" +#if TARGET_MACHO +# include +# include +#endif + + +#if TARGET_MACHO + +/* Default architecture to use if -mcpu=native did not detect a known CPU. */ +#define DEFAULT_ARCH "apple-m1" + +/* macOS does not have /proc/cpuinfo and needs a different approach, + based on sysctl. It is much simpler. */ + +const char * +host_detect_local_cpu (ATTRIBUTE_UNUSED int argc, ATTRIBUTE_UNUSED const char **argv) +{ + bool arch = false; + bool tune = false; + bool cpu = false; + const char *res = NULL; + uint32_t family; + size_t len = sizeof(family); + + gcc_assert (argc); + if (!argv[0]) + return NULL; + + /* Are we processing -march, mtune or mcpu? */ + arch = strcmp (argv[0], "arch") == 0; + if (!arch) + tune = strcmp (argv[0], "tune") == 0; + if (!arch && !tune) + cpu = strcmp (argv[0], "cpu") == 0; + if (!arch && !tune && !cpu) + return NULL; + + sysctlbyname("hw.cpufamily", &family, &len, NULL, 0); + + switch (family) + { + case 0x07d34b9f: // Vortex, Tempest + res = "apple-a12"; + break; + case 0x573b5eec: + case 0x1b588bb3: // Firestorm, Icestorm + res = "apple-m1"; + break; + case 0xda33d83d: // Blizzard, Avalanche + res = "apple-m2"; + break; + case 0xfa33415e: // Ibiza (M3) + case 0x5f4dea93: // Lobos (M3 Pro) + case 0x72015832: // Palma (M3 Max) + res = "apple-m3"; + break; + default: + res = DEFAULT_ARCH; + } + + if (res) + return concat ("-m", argv[0], "=", res, NULL); + else + return NULL; +} + +#else + struct aarch64_arch_extension { const char *ext; @@ -477,3 +545,4 @@ not_found: } } +#endif diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index b895f5dcb86..6e7487bcef5 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -352,9 +352,24 @@ (define_predicate "aarch64_prefetch_operand" (match_test "aarch64_address_valid_for_prefetch_p (op, false)")) +(define_predicate "aarch64_unscaled_prefetch_operand" + (match_test "aarch64_address_valid_for_unscaled_prefetch_p (op, false)")) + (define_predicate "aarch64_valid_symref" (match_code "const, symbol_ref, label_ref") { + if (TARGET_MACHO) + { + rtx x = op; + rtx offset; + split_const (x, &x, &offset); + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_SALT_ADDR) + x = XVECEXP (x, 0, 0); + if (SYMBOL_REF_P (x) && INTVAL (offset) < 0) + return false; + } return (aarch64_classify_symbolic_expression (op) != SYMBOL_FORCE_TO_MEM); }) diff --git a/gcc/config/aarch64/t-aarch64-darwin b/gcc/config/aarch64/t-aarch64-darwin new file mode 100644 index 00000000000..e2b8ad9237f --- /dev/null +++ b/gcc/config/aarch64/t-aarch64-darwin @@ -0,0 +1,25 @@ +# Machine description for AArch64 architecture. +# Copyright (C) 2020 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +LIB1ASMSRC = aarch64/lib1funcs.asm +LIB1ASMFUNCS = _aarch64_sync_cache_range + +# TODO - figure out what multilib provisions we should make for +# a) arm64e +# b) arm64_32 diff --git a/gcc/config/darwin-driver.cc b/gcc/config/darwin-driver.cc index eabe9bc970d..176bcfb6843 100644 --- a/gcc/config/darwin-driver.cc +++ b/gcc/config/darwin-driver.cc @@ -268,10 +268,13 @@ darwin_driver_init (unsigned int *decoded_options_count, bool seenX86_64 = false; bool seenPPC = false; bool seenPPC64 = false; +#if !DARWIN_ARM64 + bool seenArm64 = false; bool seenM32 = false; bool seenM64 = false; bool appendM32 = false; bool appendM64 = false; +#endif const char *vers_string = NULL; bool seen_version_min = false; bool seen_sysroot_p = false; @@ -296,6 +299,12 @@ darwin_driver_init (unsigned int *decoded_options_count, seenPPC = true; else if (!strcmp ((*decoded_options)[i].arg, "ppc64")) seenPPC64 = true; + else if (!strcmp ((*decoded_options)[i].arg, "arm64")) +#if !DARWIN_ARM64 + seenArm64 = true; +#else + ; /* We accept the option, but don't need to act on it. */ +#endif else error ("this compiler does not support %qs", (*decoded_options)[i].arg); @@ -309,7 +318,7 @@ darwin_driver_init (unsigned int *decoded_options_count, --i; --*decoded_options_count; break; - +#if !DARWIN_ARM64 case OPT_m32: seenM32 = true; break; @@ -317,6 +326,7 @@ darwin_driver_init (unsigned int *decoded_options_count, case OPT_m64: seenM64 = true; break; +#endif case OPT_mmacosx_version_min_: seen_version_min = true; @@ -366,6 +376,9 @@ darwin_driver_init (unsigned int *decoded_options_count, if (seenPPC || seenPPC64) warning (0, "this compiler does not support PowerPC" " (%<-arch%> option ignored)"); + else if (seenArm64) + warning (0, "this compiler does not support Arm64" + " (%<-arch%> option ignored)"); if (seenX86) { if (seenX86_64 || seenM64) @@ -389,6 +402,9 @@ darwin_driver_init (unsigned int *decoded_options_count, if (seenX86 || seenX86_64) warning (0, "this compiler does not support x86" " (%<-arch%> option ignored)"); + else if (seenArm64) + warning (0, "this compiler does not support Arm64" + " (%<-arch%> option ignored)"); if (seenPPC) { if (seenPPC64 || seenM64) @@ -408,12 +424,20 @@ darwin_driver_init (unsigned int *decoded_options_count, if (! seenM64) /* Add -m64 if the User didn't. */ appendM64 = true; } +#elif DARWIN_ARM64 + if (seenPPC || seenPPC64) + warning (0, "this compiler does not support PowerPC" + " (%<-arch%> option ignored)"); + if (seenX86 || seenX86_64) + warning (0, "this compiler does not support x86" + " (%<-arch%> option ignored)"); #endif /* If there is nothing else on the command line, do not add sysroot etc. */ if (*decoded_options_count <= 1) return; +#if !DARWIN_ARM64 if (appendM32 || appendM64) { ++*decoded_options_count; @@ -423,6 +447,7 @@ darwin_driver_init (unsigned int *decoded_options_count, generate_option (appendM32 ? OPT_m32 : OPT_m64, NULL, 1, CL_DRIVER, &(*decoded_options)[*decoded_options_count - 1]); } +#endif if (!seen_sysroot_p) { diff --git a/gcc/config/darwin-protos.h b/gcc/config/darwin-protos.h index b67e05264e1..35116317b59 100644 --- a/gcc/config/darwin-protos.h +++ b/gcc/config/darwin-protos.h @@ -86,9 +86,12 @@ extern void darwin_asm_lto_end (void); extern void darwin_mark_decl_preserved (const char *); extern tree darwin_handle_kext_attribute (tree *, tree, tree, int, bool *); -extern tree darwin_handle_weak_import_attribute (tree *node, tree name, - tree args, int flags, - bool * no_add_attrs); +extern tree darwin_handle_weak_import_attribute (tree *, tree, tree, int, + bool *); +extern tree darwin_handle_availability_attribute (tree *, tree, tree, + int, bool *); +extern bool darwin_attribute_takes_identifier_p (const_tree); + extern void machopic_output_stub (FILE *, const char *, const char *); extern void darwin_globalize_label (FILE *, const char *); extern void darwin_assemble_visibility (tree, int); @@ -124,6 +127,7 @@ extern void darwin_enter_string_into_cfstring_table (tree); extern void darwin_asm_output_anchor (rtx symbol); extern bool darwin_use_anchors_for_symbol_p (const_rtx symbol); extern bool darwin_kextabi_p (void); +extern bool darwin_unreachable_traps_p (void); extern void darwin_override_options (void); extern void darwin_patch_builtins (void); extern void darwin_rename_builtins (void); diff --git a/gcc/config/darwin.cc b/gcc/config/darwin.cc index 63b8c509405..f33a30d74ca 100644 --- a/gcc/config/darwin.cc +++ b/gcc/config/darwin.cc @@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see #include "cfghooks.h" #include "df.h" #include "memmodel.h" +#include "c-family/c-common.h" /* enum rid. */ #include "tm_p.h" #include "stringpool.h" #include "attribs.h" @@ -49,6 +50,7 @@ along with GCC; see the file COPYING3. If not see #include "optabs.h" #include "flags.h" #include "opts.h" +#include "c-family/c-objc.h" /* for objc_method_decl(). */ /* Fix and Continue. @@ -102,6 +104,7 @@ int darwin_running_cxx; /* Some code-gen now depends on OS major version numbers (at least). */ int generating_for_darwin_version ; +unsigned long current_os_version = 0; /* For older linkers we need to emit special sections (marked 'coalesced') for for weak or single-definition items. */ @@ -131,7 +134,7 @@ struct { section * darwin_sections[NUM_DARWIN_SECTIONS]; /* While we transition to using in-tests instead of ifdef'd code. */ -#if !HAVE_lo_sum +#if !HAVE_lo_sum || DARWIN_ARM64 #define gen_macho_high(m,a,b) (a) #define gen_macho_low(m,a,b,c) (a) #endif @@ -1104,6 +1107,7 @@ machopic_legitimize_pic_address (rtx orig, machine_mode mode, rtx reg) return pic_ref; } +#if !DARWIN_ARM64 /* Callbacks to output the stub or non-lazy pointers. Each works on the item in *SLOT,if it has been used. DATA is the FILE* for assembly output. @@ -1259,6 +1263,7 @@ machopic_finish (FILE *out_file) machopic_indirections->traverse_noresize (out_file); } +#endif int machopic_operand_p (rtx op) @@ -2194,6 +2199,122 @@ darwin_handle_kext_attribute (tree *node, tree name, return NULL_TREE; } +enum version_components { MAJOR, MINOR, TINY }; + +/* Parse a version number in x.y.z form and validate it as a macOS + version. Ideally, we'd put this in a common place usable by the + Darwin backend. */ + +static bool +parse_version (unsigned version_array[3], const char *version_str) +{ + size_t version_len; + char *end, last = '\0', delimiter = '.', alt_delim = '_'; + + if (!version_str) + return false; + + /* Handle the odd situation in which we get STRING_CST which contain the + starting and ending quotes. */ + if (version_str[0] == '"') + { + version_str++; + version_len = strrchr (&version_str[1], '"') - version_str; + last = '"'; + } + else + version_len = strlen (version_str); + + if (version_len < 1) + return false; + + /* Version string must consist of digits and periods only. */ + if (strspn (version_str, "0123456789._") != version_len) + return false; + + if (!ISDIGIT (version_str[0]) || !ISDIGIT (version_str[version_len - 1])) + return false; + + version_array[MAJOR] = strtoul (version_str, &end, 10); + if (*end == '_') + { + delimiter = '_'; + alt_delim = '.'; + } + version_str = end + ((*end == delimiter) ? 1 : 0); + if (version_array[MAJOR] == 100000) + return true; + if (version_array[MAJOR] > 99) + return false; + + /* Version string must not contain adjacent delimiters. */ + if (*version_str == delimiter || *version_str == alt_delim) + return false; + + version_array[MINOR] = strtoul (version_str, &end, 10); + if (*end == alt_delim) + return false; + version_str = end + ((*end == delimiter) ? 1 : 0); + if (version_array[MINOR] > 99) + return false; + + version_array[TINY] = strtoul (version_str, &end, 10); + if (version_array[TINY] > 99) + return false; + + /* Version string must contain no more than three tokens. */ + if (*end != last) + return false; + + return true; +} + +/* Turn a version expressed as maj.min.tiny into an unsigned long + integer representing the value used in macOS availability macros. */ + +static unsigned long +version_from_version_array (unsigned vers[3]) +{ + unsigned long res = 0; + /* There seems to be a special "unknown" value. */ + if (vers[0] == 100000) + return 999999; + + /* Here, we follow the 'modern' / 'legacy' numbering scheme for versions. */ + if (vers[0] > 10 || vers[1] >= 10) + res = vers[0] * 10000 + vers[1] * 100 + vers[2]; + else + { + res = vers[0] * 100; + if (vers[1] > 9) + res += 90; + else + res += vers[1] * 10; + if (vers[2] > 9) + res += 9; + else + res += vers[1]; + } + return res; +} + +/* Extract a macOS version from an availability attribute argument. */ + +static unsigned long +os_version_from_avail_value (tree value) +{ + unsigned long res = 0; + unsigned vers[3] = {0,0,0}; + if (TREE_CODE (value) == STRING_CST) + { + if (parse_version (&vers[0], TREE_STRING_POINTER (value))) + res = version_from_version_array (&vers[0]); + } + else + gcc_unreachable (); + return res; +} + /* Handle a "weak_import" attribute; arguments as in struct attribute_spec.handler. */ @@ -2215,6 +2336,231 @@ darwin_handle_weak_import_attribute (tree *node, tree name, return NULL_TREE; } +#define NUM_AV_OSES 13 +const char *availability_os[NUM_AV_OSES] + = { "macos", "macosx", "ios", "tvos", "watchos", "driverkit", "swift", + "maccatalyst", "macCatalyst", "xros", "visionos", "android", "zos" }; + +#define NUM_AV_CLAUSES 6 +const char *availability_clause[NUM_AV_CLAUSES] + = { "unavailable", "introduced", "deprecated", "obsoleted", "message", + "replacement" }; + +/* Validate and act upon the arguments to an 'availability' attribute. */ + +tree +darwin_handle_availability_attribute (tree *node, tree name, tree args, + int flags, bool * no_add_attrs) +{ + tree decl = *node; + *no_add_attrs = true; + + if (!decl || (!TYPE_P (decl) && !DECL_P (decl))) + { + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + else if (decl == error_mark_node) + return NULL_TREE; + + location_t loc = DECL_SOURCE_LOCATION (decl); + if (args == NULL_TREE) + { + error_at (loc, "%qE attribute requires at least one argument", + name); + return NULL_TREE; + } + else if (args == error_mark_node) + return NULL_TREE; + + /* The first argument must name a supported OS - although we could choose + to ignore any OS we don't recognise. */ + gcc_checking_assert (TREE_CODE (args) == TREE_LIST); + tree platform = TREE_VALUE (args); + if (platform == error_mark_node) + return NULL_TREE; + + gcc_checking_assert (TREE_CODE (platform) == IDENTIFIER_NODE); + bool platform_ok = false; + unsigned plat_num = 0; + for (; plat_num < (unsigned) NUM_AV_OSES; plat_num++) + if (strcmp (availability_os[plat_num], IDENTIFIER_POINTER (platform)) == 0) + { + platform_ok = true; + break; + } + if (!platform_ok) + { + error_at (input_location, + "platform %qE is not recognised for the % " + "attribute", platform); + return NULL_TREE; + } + else if (plat_num > 1) /* We only compile for macos so far. */ + return NULL_TREE; + + /* We might be dealing with an object or type. */ + tree target_decl = NULL_TREE; + tree type = NULL_TREE; + bool warn = false; + if (DECL_P (*node)) + { + type = TREE_TYPE (decl); + + if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == PARM_DECL + || VAR_OR_FUNCTION_DECL_P (decl) + || TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == CONST_DECL + /*|| objc_method_decl (TREE_CODE (decl))*/) + target_decl = decl; + else + warn = true; + } + else if (TYPE_P (*node)) + type = target_decl = *node; + else + warn = true; + + tree what = NULL_TREE; + if (warn) + { + if (type && TYPE_NAME (type)) + { + if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE) + what = TYPE_NAME (*node); + else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (type))) + what = DECL_NAME (TYPE_NAME (type)); + } + if (what) + warning (OPT_Wattributes, "%qE attribute ignored for %qE", name, what); + else + warning (OPT_Wattributes, "%qE attribute ignored", name); + return NULL_TREE; + } + + /* Now we have to parse the availability clauses. */ + tree msg = NULL_TREE; + tree replacement = NULL_TREE; + bool unavailable = false; + unsigned introduced = 1000; + unsigned deprecated = current_os_version + 1; + unsigned obsoleted = current_os_version + 1; + for (tree arg = TREE_CHAIN (args); arg; arg = TREE_CHAIN (arg)) + { + tree clause_name = TREE_VALUE (arg); + tree clause_value = TREE_PURPOSE (arg); + if (clause_name == error_mark_node + || clause_value == error_mark_node) + continue; + unsigned clause_num = 0; + for (; clause_num < (unsigned) NUM_AV_CLAUSES; clause_num++) + if (strcmp (availability_clause[clause_num], + IDENTIFIER_POINTER (clause_name)) == 0) + break; + switch (clause_num) + { + default: + error_at (input_location, + "clause %qE is not recognised for the % " + "attribute", clause_name); + break; + case 0: + unavailable = true; + break; + case 1: + case 2: + case 3: + if (!clause_value) + error_at (input_location, "%<%E=%> requires a value", clause_name); + else + { + unsigned version = os_version_from_avail_value (clause_value); + if (version == 0) + error_at (input_location, "the value %qE provided to %qE is " + "not a valid OS version", clause_value, clause_name); + else if (clause_num == 1) + introduced = version; + else if (clause_num == 2) + deprecated = version; + else if (clause_num == 3) + obsoleted = version; + } + break; + case 4: + case 5: + if (!clause_value || TREE_CODE (clause_value) != STRING_CST) + error_at (input_location, "%<%E=%> requires a string", clause_name); + else if (clause_num == 4) + msg = clause_value; + else + replacement = clause_value; + break; + } + } + /* Now figure out what to do. */ + tree maybe_text = NULL_TREE; + if (replacement) + maybe_text = tree_cons (NULL_TREE, replacement, NULL_TREE); + else if (msg) + maybe_text = tree_cons (NULL_TREE, msg, NULL_TREE); + + if (unavailable || current_os_version >= obsoleted) + { + TREE_UNAVAILABLE (*node) = true; + /* We do not handle the availability attribute at diagnostics-time, so + if we want the informational messages, then attach them to additional + attributes for the deprecation or unavailability. TODO; maybe we can + fabricate the composite here. */ + if (maybe_text) + { + *no_add_attrs = false; + tree new_attr = tree_cons (get_identifier ("unavailable"), + maybe_text, NULL_TREE); + /* This is the actual consequence of the evaluation. */ + if (TYPE_P (target_decl) && !(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + *node = build_variant_type_copy (*node); + TYPE_ATTRIBUTES (*node) = chainon (TYPE_ATTRIBUTES (*node), + new_attr); + } + else + DECL_ATTRIBUTES (*node) = chainon (DECL_ATTRIBUTES (*node), + new_attr); + } + } + else if (current_os_version > deprecated) + { + TREE_DEPRECATED (*node) = true; + if (maybe_text) + { + *no_add_attrs = false; + tree new_attr = tree_cons (get_identifier ("deprecated"), + maybe_text, NULL_TREE); + /* This is the actual consequence of the evaluation. */ + if (TYPE_P (target_decl) && !(flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + *node = build_variant_type_copy (*node); + TYPE_ATTRIBUTES (*node) = chainon (TYPE_ATTRIBUTES (*node), + new_attr); + } + else + DECL_ATTRIBUTES (*node) = chainon (DECL_ATTRIBUTES (*node), + new_attr); + } + } + else if (current_os_version < introduced) + *no_add_attrs = false; + return NULL_TREE; +} + +bool +darwin_attribute_takes_identifier_p (const_tree attr_id) +{ + return is_attribute_p ("availability", attr_id); +} + /* Emit a label for an FDE, making it global and/or weak if appropriate. The third parameter is nonzero if this is for exception handling. The fourth parameter is nonzero if this is just a placeholder for an @@ -2306,6 +2652,8 @@ darwin_emit_except_table_label (FILE *file) rtx darwin_make_eh_symbol_indirect (rtx orig, bool ARG_UNUSED (pubvis)) { + if (DARWIN_ARM64) + return orig; if (DARWIN_PPC == 0 && TARGET_64BIT) return orig; @@ -3154,7 +3502,12 @@ darwin_file_end (void) fprintf (asm_out_file, "\t.long\t0\n\t.long\t%u\n", flags); } +#if !DARWIN_ARM64 machopic_finish (asm_out_file); +#else + gcc_checking_assert (!machopic_indirections); +#endif + if (flag_apple_kext) { /* These sections are only used for kernel code. */ @@ -3330,6 +3683,13 @@ darwin_kextabi_p (void) { return flag_apple_kext; } +/* True, iff we want to map __builtin_unreachable to a trap. */ + +bool +darwin_unreachable_traps_p (void) { + return darwin_unreachable_traps; +} + void darwin_override_options (void) { @@ -3350,7 +3710,14 @@ darwin_override_options (void) generating_for_darwin_version = 8; /* Earlier versions are not specifically accounted, until required. */ + unsigned vers[3] = {0,0,0}; + if (!parse_version (vers, darwin_macosx_version_min)) + error_at (UNKNOWN_LOCATION, "how did we get a bad OS version? (%s)", + darwin_macosx_version_min); + current_os_version = version_from_version_array (vers); } + else + current_os_version = 1058; /* Some codegen needs to account for the capabilities of the target linker. */ diff --git a/gcc/config/darwin.h b/gcc/config/darwin.h index c09b9e9dc94..c3e8defcbc0 100644 --- a/gcc/config/darwin.h +++ b/gcc/config/darwin.h @@ -42,6 +42,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define DARWIN_X86 0 #define DARWIN_PPC 0 +#define DARWIN_ARM64 0 #define OBJECT_FORMAT_MACHO 1 @@ -975,7 +976,12 @@ extern GTY(()) section * darwin_sections[NUM_DARWIN_SECTIONS]; { "apple_kext_compatibility", 0, 0, false, true, false, false, \ darwin_handle_kext_attribute, NULL }, \ { "weak_import", 0, 0, true, false, false, false, \ - darwin_handle_weak_import_attribute, NULL } + darwin_handle_weak_import_attribute, NULL }, \ + { "availability", 0, -1, true, false, false, false, \ + darwin_handle_availability_attribute, NULL } + +#undef TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P +#define TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P darwin_attribute_takes_identifier_p /* Make local constant labels linker-visible, so that if one follows a weak_global constant, ld64 will be able to separate the atoms. */ @@ -1223,6 +1229,10 @@ void add_framework_path (char *); #define TARGET_N_FORMAT_TYPES 1 #define TARGET_FORMAT_TYPES darwin_additional_format_types +/* We want __builtin_unreachable to be expanded as a trap instruction. */ +#undef TARGET_UNREACHABLE_SHOULD_TRAP +#define TARGET_UNREACHABLE_SHOULD_TRAP darwin_unreachable_traps_p + #ifndef USED_FOR_TARGET extern void darwin_driver_init (unsigned int *,struct cl_decoded_option **); #define GCC_DRIVER_HOST_INITIALIZATION \ diff --git a/gcc/config/darwin.opt b/gcc/config/darwin.opt index 307a760629b..42a47551c1c 100644 --- a/gcc/config/darwin.opt +++ b/gcc/config/darwin.opt @@ -91,6 +91,10 @@ mtarget-linker Target RejectNegative Joined Separate Var(darwin_target_linker) Init(LD64_VERSION) -mtarget-linker Specify that ld64 is the toolchain linker for the current invocation. +munreachable-traps +Target Var(darwin_unreachable_traps) Init(1) +When set (the default) this makes __builtin_unreachable render as a trap. + ; Driver options. all_load diff --git a/gcc/configure b/gcc/configure index 23da7d55d62..2cff1bc1374 100755 --- a/gcc/configure +++ b/gcc/configure @@ -3803,20 +3803,19 @@ gcc_gxx_libcxx_include_dir= # Check whether --with-gxx-libcxx-include-dir was given. if test "${with_gxx_libcxx_include_dir+set}" = set; then : - withval=$with_gxx_libcxx_include_dir; case "${withval}" in -yes) as_fn_error $? "bad value ${withval} given for libc++ include directory" "$LINENO" 5 ;; -*) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;; -esac + withval=$with_gxx_libcxx_include_dir; gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir fi # --with-gxx-libcxx-include-dir controls the enabling of the -stdlib option. # if --with-gxx-libcxx-include-dir is 'no' we disable the stdlib option. +# if --with-gxx-libcxx-include-dir is 'yes' we enable the stdlib option and use +# the default path within the installation. # if --with-gxx-libcxx-include-dir is unset we enable the stdlib option -# based on the platform (to be available on platform versions where it is the +# based on the platform (to be available on platform versions where it is the # default for the system tools). We also use a default path within the compiler -# install tree. -# Otherwise, we use the path provided and enable the stdlib option. +# install tree. +# Otherwise, we use the path provided and enable the stdlib option. # If both --with-sysroot and --with-gxx-libcxx-include-dir are passed, we # check to see if the latter starts with the former and, upon success, compute # gcc_gxx_libcxx_include_dir as relative to the sysroot. @@ -3824,16 +3823,20 @@ gcc_gxx_libcxx_include_dir_add_sysroot=0 gcc_enable_stdlib_opt=0 if test x${gcc_gxx_libcxx_include_dir} != x; then if test x${gcc_gxx_libcxx_include_dir} = xno; then - # set defaults for the dir, but the option is disabled anyway. + # set defaults for the dir, but the option is disabled anyway. + gcc_gxx_libcxx_include_dir= + elif test x${gcc_gxx_libcxx_include_dir} = xyes; then + # set defaults for the dir, and enable. gcc_gxx_libcxx_include_dir= + gcc_enable_stdlib_opt=1 else gcc_enable_stdlib_opt=1 fi else case $target in *-darwin1[1-9]* | *-darwin2*) - # Default this on for Darwin versions which default to libcxx, - # and embed the path in the compiler install so that we get a + # Default this on for Darwin versions which default to libcxx, + # and embed the path in the compiler install so that we get a # self-contained toolchain. gcc_enable_stdlib_opt=1 ;; @@ -21575,7 +21578,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21578 "configure" +#line 21581 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -21681,7 +21684,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 21684 "configure" +#line 21687 "configure" #include "confdefs.h" #if HAVE_DLFCN_H diff --git a/gcc/configure.ac b/gcc/configure.ac index d7cf0b92cd8..f78a6491e86 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -235,18 +235,17 @@ gcc_gxx_libcxx_include_dir= AC_ARG_WITH(gxx-libcxx-include-dir, [AS_HELP_STRING([--with-gxx-libcxx-include-dir=DIR], [specifies directory to find libc++ header files])], -[case "${withval}" in -yes) AC_MSG_ERROR(bad value ${withval} given for libc++ include directory) ;; -*) gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir ;; -esac]) +[gcc_gxx_libcxx_include_dir=$with_gxx_libcxx_include_dir]) # --with-gxx-libcxx-include-dir controls the enabling of the -stdlib option. # if --with-gxx-libcxx-include-dir is 'no' we disable the stdlib option. +# if --with-gxx-libcxx-include-dir is 'yes' we enable the stdlib option and use +# the default path within the installation. # if --with-gxx-libcxx-include-dir is unset we enable the stdlib option -# based on the platform (to be available on platform versions where it is the +# based on the platform (to be available on platform versions where it is the # default for the system tools). We also use a default path within the compiler -# install tree. -# Otherwise, we use the path provided and enable the stdlib option. +# install tree. +# Otherwise, we use the path provided and enable the stdlib option. # If both --with-sysroot and --with-gxx-libcxx-include-dir are passed, we # check to see if the latter starts with the former and, upon success, compute # gcc_gxx_libcxx_include_dir as relative to the sysroot. @@ -254,16 +253,20 @@ gcc_gxx_libcxx_include_dir_add_sysroot=0 gcc_enable_stdlib_opt=0 if test x${gcc_gxx_libcxx_include_dir} != x; then if test x${gcc_gxx_libcxx_include_dir} = xno; then - # set defaults for the dir, but the option is disabled anyway. + # set defaults for the dir, but the option is disabled anyway. gcc_gxx_libcxx_include_dir= + elif test x${gcc_gxx_libcxx_include_dir} = xyes; then + # set defaults for the dir, and enable. + gcc_gxx_libcxx_include_dir= + gcc_enable_stdlib_opt=1 else gcc_enable_stdlib_opt=1 fi else case $target in *-darwin1[[1-9]]* | *-darwin2*) - # Default this on for Darwin versions which default to libcxx, - # and embed the path in the compiler install so that we get a + # Default this on for Darwin versions which default to libcxx, + # and embed the path in the compiler install so that we get a # self-contained toolchain. gcc_enable_stdlib_opt=1 ;; diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index 806a2a4bc69..3e4ce6081e0 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -3838,9 +3838,8 @@ get_tls_init_fn (tree var) if (!flag_extern_tls_init && DECL_EXTERNAL (var)) return NULL_TREE; - /* If the variable is internal, or if we can't generate aliases, - call the local init function directly. */ - if (!TREE_PUBLIC (var) || !TARGET_SUPPORTS_ALIASES) + /* If the variable is internal call the local init function directly. */ + if (!TREE_PUBLIC (var)) return get_local_tls_init_fn (DECL_SOURCE_LOCATION (var)); tree sname = mangle_tls_init_fn (var); @@ -4004,6 +4003,25 @@ generate_tls_wrapper (tree fn) expand_or_defer_fn (finish_function (/*inline_p=*/false)); } +/* A dummy init function to act as a weak placeholder for a (possibly non- + existent) dynamic init. */ +static void +generate_tls_dummy_init (tree fn) +{ + tree var = DECL_BEFRIENDING_CLASSES (fn); + tree init_fn = get_tls_init_fn (var); + /* If have no init fn, or it is non-weak, then we do not need to make a + dummy. */ + if (!init_fn || !lookup_attribute ("weak", DECL_ATTRIBUTES (init_fn))) + return; + start_preparsed_function (init_fn, NULL_TREE, SF_DEFAULT | SF_PRE_PARSED); + tree body = begin_function_body (); + declare_weak (init_fn); + finish_return_stmt (NULL_TREE); + finish_function_body (body); + expand_or_defer_fn (finish_function (/*inline_p=*/false)); +} + /* Start a global constructor or destructor function. */ static tree @@ -4822,22 +4840,24 @@ handle_tls_init (void) finish_expr_stmt (cp_build_modify_expr (loc, guard, NOP_EXPR, boolean_true_node, tf_warning_or_error)); + auto_vec direct_calls; for (; vars; vars = TREE_CHAIN (vars)) { tree var = TREE_VALUE (vars); tree init = TREE_PURPOSE (vars); one_static_initialization_or_destruction (/*initp=*/true, var, init); - /* Output init aliases even with -fno-extern-tls-init. */ - if (TARGET_SUPPORTS_ALIASES && TREE_PUBLIC (var)) + /* Output inits even with -fno-extern-tls-init. + We save the list here and output either an alias or a stub function + below. */ + if (TREE_PUBLIC (var)) { - tree single_init_fn = get_tls_init_fn (var); + tree single_init_fn = get_tls_init_fn (var); if (single_init_fn == NULL_TREE) continue; - cgraph_node *alias - = cgraph_node::get_create (fn)->create_same_body_alias - (single_init_fn, fn); - gcc_assert (alias != NULL); + if (single_init_fn == fn) + continue; + direct_calls.safe_push (single_init_fn); } } @@ -4845,6 +4865,30 @@ handle_tls_init (void) finish_if_stmt (if_stmt); finish_function_body (body); expand_or_defer_fn (finish_function (/*inline_p=*/false)); + + /* For each TLS var that we have an init function, we either emit an alias + between that and the tls_init, or a stub function that just calls the + tls_init. */ + while (!direct_calls.is_empty()) + { + tree single_init_fn = direct_calls.pop (); + if (TARGET_SUPPORTS_ALIASES) + { + cgraph_node *alias + = cgraph_node::get_create (fn)->create_same_body_alias + (single_init_fn, fn); + gcc_assert (alias != NULL); + } + else + { + start_preparsed_function (single_init_fn, NULL_TREE, SF_PRE_PARSED); + tree body = begin_function_body (); + tree r = build_call_expr (fn, 0); + finish_expr_stmt (r); + finish_function_body (body); + expand_or_defer_fn (finish_function (/*inline_p=*/false)); + } + } } /* We're at the end of compilation, so generate any mangling aliases that @@ -5264,7 +5308,14 @@ c_parse_final_cleanups (void) } if (!DECL_INITIAL (decl) && decl_tls_wrapper_p (decl)) - generate_tls_wrapper (decl); + { + generate_tls_wrapper (decl); + /* The wrapper might have a weak reference to an init, we provide + a dummy function to satisfy that here. The linker/dynamic + loader will override this with the actual init, if one is + required. */ + generate_tls_dummy_init (decl); + } if (!DECL_SAVED_TREE (decl)) continue; diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 598380dda08..485e3802f86 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -705,6 +705,91 @@ cp_lexer_handle_early_pragma (cp_lexer *lexer) static cp_parser *cp_parser_new (cp_lexer *); static GTY (()) cp_parser *the_parser; +/* Context-sensitive parse-checking for clang-style attributes. */ + +enum clang_attr_state { + CA_NONE = 0, + CA_ATTR, + CA_BR1, CA_BR2, + CA_LIST, + CA_LIST_ARGS, + CA_IS_CA, + CA_CA_ARGS, + CA_LIST_CONT +}; + +/* State machine tracking context of attribute lexing. */ + +static enum clang_attr_state +cp_lexer_attribute_state (cp_token& token, enum clang_attr_state attr_state) +{ + /* Implement a context-sensitive parser for clang attributes. + We detect __attribute__((clang_style_attribute (ARGS))) and lex the + args ARGS with the following differences from GNU attributes: + (a) number-like values are lexed as strings [this allows lexing XX.YY.ZZ + version numbers]. + (b) we concatenate strings, since clang attributes allow this too. */ + switch (attr_state) + { + case CA_NONE: + if (token.type == CPP_KEYWORD + && token.keyword == RID_ATTRIBUTE) + attr_state = CA_ATTR; + break; + case CA_ATTR: + if (token.type == CPP_OPEN_PAREN) + attr_state = CA_BR1; + else + attr_state = CA_NONE; + break; + case CA_BR1: + if (token.type == CPP_OPEN_PAREN) + attr_state = CA_BR2; + else + attr_state = CA_NONE; + break; + case CA_BR2: + if (token.type == CPP_NAME) + { + tree identifier = (token.type == CPP_KEYWORD) + /* For keywords, use the canonical spelling, not the + parsed identifier. */ + ? ridpointers[(int) token.keyword] + : token.u.value; + identifier = canonicalize_attr_name (identifier); + if (attribute_clang_form_p (identifier)) + attr_state = CA_IS_CA; + else + attr_state = CA_LIST; + } + else + attr_state = CA_NONE; + break; + case CA_IS_CA: + case CA_LIST: + if (token.type == CPP_COMMA) + attr_state = CA_BR2; /* Back to the list outer. */ + else if (token.type == CPP_OPEN_PAREN) + attr_state = attr_state == CA_IS_CA ? CA_CA_ARGS + : CA_LIST_ARGS; + else + attr_state = CA_NONE; + break; + case CA_CA_ARGS: /* We will special-case args in this state. */ + case CA_LIST_ARGS: + if (token.type == CPP_CLOSE_PAREN) + attr_state = CA_LIST_CONT; + break; + case CA_LIST_CONT: + if (token.type == CPP_COMMA) + attr_state = CA_BR2; /* Back to the list outer. */ + else + attr_state = CA_NONE; + break; + } + return attr_state; +} + /* Create a new main C++ lexer, the lexer that gets tokens from the preprocessor, and also create the main parser. */ @@ -721,6 +806,8 @@ cp_lexer_new_main (void) c_common_no_more_pch (); cp_lexer *lexer = cp_lexer_alloc (); + enum clang_attr_state attr_state = CA_NONE; + /* Put the first token in the buffer. */ cp_token *tok = lexer->buffer->quick_push (token); @@ -744,8 +831,14 @@ cp_lexer_new_main (void) if (tok->type == CPP_PRAGMA_EOL) cp_lexer_handle_early_pragma (lexer); + attr_state = cp_lexer_attribute_state (*tok, attr_state); tok = vec_safe_push (lexer->buffer, cp_token ()); - cp_lexer_get_preprocessor_token (C_LEX_STRING_NO_JOIN, tok); + unsigned int flags = C_LEX_STRING_NO_JOIN; + /* If we are processing clang-style attribute args, lex numbers as + potential version strings; NN .. NN.MM .. NN.MM.OO */ + if (attr_state == CA_CA_ARGS) + flags |= C_LEX_NUMBER_AS_STRING; + cp_lexer_get_preprocessor_token (flags, tok); } lexer->next_token = lexer->buffer->address (); @@ -962,7 +1055,7 @@ cp_lexer_get_preprocessor_token (unsigned flags, cp_token *token) { static int is_extern_c = 0; - /* Get a new token from the preprocessor. */ + /* Get a new token from the preprocessor. */ token->type = c_lex_with_flags (&token->u.value, &token->location, &token->flags, flags); @@ -29707,6 +29800,91 @@ cp_parser_gnu_attributes_opt (cp_parser* parser) return attributes; } +/* Parse the arguments list for a clang attribute. */ +static tree +cp_parser_clang_attribute (cp_parser *parser, tree/*attr_id*/) +{ + /* Each entry can be : + identifier + identifier=N.MM.Z + identifier="string" + followed by ',' or ) for the last entry*/ + + matching_parens parens; + if (!parens.require_open (parser)) + return NULL; + + bool save_translate_strings_p = parser->translate_strings_p; + parser->translate_strings_p = false; + tree attr_args = NULL_TREE; + cp_token *token; + do + { + tree name = NULL_TREE; + tree value = NULL_TREE; + + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_NAME) + name = token->u.value; + else if (token->type == CPP_KEYWORD) + name = ridpointers[(int) token->keyword]; + else if (token->flags & NAMED_OP) + name = get_identifier (cpp_type2name (token->type, token->flags)); + else + { + /* FIXME: context-sensitive for that attrib. */ + error_at (token->location, "expected an attribute keyword"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/false); + attr_args = error_mark_node; + break; + } + cp_lexer_consume_token (parser->lexer); + + if (cp_lexer_next_token_is (parser->lexer, CPP_EQ)) + { + cp_lexer_consume_token (parser->lexer); /* eat the '=' */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) + && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + { + token = cp_lexer_peek_token (parser->lexer); + if (token->type == CPP_STRING) + value = cp_parser_string_literal (parser, /*translate=*/false, + /*wide_ok=*/false); + else + { + value = token->u.value; + cp_lexer_consume_token (parser->lexer); + } + } + /* else value is missing. */ + } + else if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN) + && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA)) + { + error_at (token->location, "expected %<,%>, %<=%> or %<)%>"); + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/false); + attr_args = error_mark_node; + break; + } + if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA)) + cp_lexer_consume_token (parser->lexer); + tree t = tree_cons (value, name, NULL_TREE); + attr_args = chainon (attr_args, t); + } while (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)); + + parser->translate_strings_p = save_translate_strings_p; + if (!parens.require_close (parser)) + return error_mark_node; + + return attr_args; +} + /* Parse a GNU attribute-list. attribute-list: @@ -29766,9 +29944,12 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) /* Peek at the next token. */ token = cp_lexer_peek_token (parser->lexer); - /* If it's an `(', then parse the attribute arguments. */ - if (token->type == CPP_OPEN_PAREN) + if (token->type == CPP_OPEN_PAREN + && attribute_clang_form_p (identifier)) + arguments = cp_parser_clang_attribute (parser, identifier); + else if (token->type == CPP_OPEN_PAREN) { + /* If it's an `(', then parse the attribute arguments. */ vec *vec; int attr_flag = (attribute_takes_identifier_p (identifier) ? id_attr : normal_attr); @@ -29785,12 +29966,12 @@ cp_parser_gnu_attribute_list (cp_parser* parser, bool exactly_one /* = false */) arguments = build_tree_list_vec (vec); release_tree_vector (vec); } - /* Save the arguments away. */ - TREE_VALUE (attribute) = arguments; } if (arguments != error_mark_node) { + /* Save the arguments away. */ + TREE_VALUE (attribute) = arguments; /* Add this attribute to the list. */ TREE_CHAIN (attribute) = attribute_list; attribute_list = attribute; diff --git a/gcc/cumulative-args.h b/gcc/cumulative-args.h new file mode 100644 index 00000000000..b60928e37f9 --- /dev/null +++ b/gcc/cumulative-args.h @@ -0,0 +1,20 @@ +#ifndef GCC_CUMULATIVE_ARGS_H +#define GCC_CUMULATIVE_ARGS_H + +#if CHECKING_P + +struct cumulative_args_t { void *magic; void *p; }; + +#else /* !CHECKING_P */ + +/* When using a GCC build compiler, we could use + __attribute__((transparent_union)) to get cumulative_args_t function + arguments passed like scalars where the ABI would mandate a less + efficient way of argument passing otherwise. However, that would come + at the cost of less type-safe !CHECKING_P compilation. */ + +union cumulative_args_t { void *p; }; + +#endif /* !CHECKING_P */ + +#endif /* GCC_CUMULATIVE_ARGS_H */ diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9456ced468a..19d204fc74a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -732,7 +732,7 @@ Objective-C and Objective-C++ Dialects}. -freg-struct-return -fshort-enums -fshort-wchar -fverbose-asm -fpack-struct[=@var{n}] -fleading-underscore -ftls-model=@var{model} --fstack-reuse=@var{reuse_level} +-fstack-reuse=@var{reuse_level} -fstack-use-cumulative-args -ftrampolines -ftrampoline-impl=@r{[}stack@r{|}heap@r{]} -ftrapv -fwrapv -fvisibility=@r{[}default@r{|}internal@r{|}hidden@r{|}protected@r{]} @@ -954,7 +954,7 @@ Objective-C and Objective-C++ Dialects}. -twolevel_namespace -umbrella -undefined -unexported_symbols_list -weak_reference_mismatches -whatsloaded -F -gused -gfull -mmacosx-version-min=@var{version} --mkernel -mone-byte-bool} +-mkernel -mone-byte-bool -munreachable-traps} @emph{DEC Alpha Options} @gccoptlist{-mno-fp-regs -msoft-float @@ -19132,6 +19132,17 @@ the behavior of older compilers in which temporaries' stack space is not reused, the aggressive stack reuse can lead to runtime errors. This option is used to control the temporary stack reuse optimization. +@opindex fstack_use_cumulative_args +@item -fstack-use-cumulative-args +This option instructs the compiler to use the +@code{cumulative_args_t}-based stack layout target hooks, +@code{TARGET_FUNCTION_ARG_BOUNDARY_CA} and +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA}. If a given target does +not define these hooks, the default behaviour is to fallback to using +the standard non-@code{_CA} variants instead. Certain targets (such as +AArch64 Darwin) require using the more advanced @code{_CA}-based +hooks: For these targets this option should be enabled by default. + @opindex ftrapv @item -ftrapv This option generates traps for signed overflow on addition, subtraction, @@ -25148,6 +25159,11 @@ without that switch. Using this switch may require recompiling all other modules in a program, including system libraries. Use this switch to conform to a non-default data model. +@opindex munreachable-traps +@item -munreachable-traps +Causes @code{__builtin_unreachable} to be rendered as a trap. This is the +default for all Darwin architectures. + @opindex mfix-and-continue @opindex ffix-and-continue @opindex findirect-data diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index c8b8b126b24..ce1d393ec70 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -1066,6 +1066,10 @@ also define the hook to @code{default_promote_function_mode_always_promote} if you would like to apply the same rules given by @code{PROMOTE_MODE}. @end deftypefn +@deftypefn {Target Hook} machine_mode TARGET_PROMOTE_FUNCTION_MODE_CA (cumulative_args_t, @var{function_arg_info}, @var{const_tree}, int *@var{}, @var{int}) +Like @code{promote_function_mode}, but takes a cumulative_args pointer and a current arg to supply the input. +@end deftypefn + @defmac PARM_BOUNDARY Normal alignment required for function parameters on the stack, in bits. All stack parameters receive at least this much alignment @@ -4471,6 +4475,16 @@ with the specified mode and type. The default hook returns @code{PARM_BOUNDARY} for all arguments. @end deftypefn +@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) +This is the @code{cumulative_args_t}-based version of +@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more +fine-grained control over argument alignment, e.g. depending on whether +it is a named argument or not, or any other criteria that you choose to +place in the @var{ca} structure. + +The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}. +@end deftypefn + @deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY (machine_mode @var{mode}, const_tree @var{type}) Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY}, which is the default value for this hook. You can define this hook to @@ -4478,6 +4492,16 @@ return a different value if an argument size must be rounded to a larger value. @end deftypefn +@deftypefn {Target Hook} {unsigned int} TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA (machine_mode @var{mode}, const_tree @var{type}, cumulative_args_t @var{ca}) +This is the @code{cumulative_args_t}-based version of +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more +fine-grained control over argument size rounding, e.g. depending on whether +it is a named argument or not, or any other criteria that you choose to +place in the @var{ca} structure. + +The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. +@end deftypefn + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does @@ -12701,6 +12725,11 @@ This target hook can be used to generate a target-specific code If selftests are enabled, run any selftests for this target. @end deftypefn +@deftypefn {Target Hook} bool TARGET_UNREACHABLE_SHOULD_TRAP (void) +This hook should return @code{true} if the target wants @code{__builtin_unreachable} to expand to a trap or @code{abort ()}. + The default value is false. +@end deftypefn + @deftypefn {Target Hook} bool TARGET_MEMTAG_CAN_TAG_ADDRESSES () True if the backend architecture naturally supports ignoring some region of pointers. This feature means that @option{-fsanitize=hwaddress} can diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in index 658e1e63371..a2156ec99ff 100644 --- a/gcc/doc/tm.texi.in +++ b/gcc/doc/tm.texi.in @@ -949,6 +949,8 @@ applied. @hook TARGET_PROMOTE_FUNCTION_MODE +@hook TARGET_PROMOTE_FUNCTION_MODE_CA + @defmac PARM_BOUNDARY Normal alignment required for function parameters on the stack, in bits. All stack parameters receive at least this much alignment @@ -3441,8 +3443,12 @@ required. @hook TARGET_FUNCTION_ARG_BOUNDARY +@hook TARGET_FUNCTION_ARG_BOUNDARY_CA + @hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY +@hook TARGET_FUNCTION_ARG_ROUND_BOUNDARY_CA + @defmac FUNCTION_ARG_REGNO_P (@var{regno}) A C expression that is nonzero if @var{regno} is the number of a hard register in which function arguments are sometimes passed. This does @@ -8097,6 +8103,8 @@ maintainer is familiar with. @hook TARGET_RUN_TARGET_SELFTESTS +@hook TARGET_UNREACHABLE_SHOULD_TRAP + @hook TARGET_MEMTAG_CAN_TAG_ADDRESSES @hook TARGET_MEMTAG_TAG_SIZE diff --git a/gcc/explow.cc b/gcc/explow.cc index 8e5f6b8e680..ab5e9819117 100644 --- a/gcc/explow.cc +++ b/gcc/explow.cc @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks.h" #include "except.h" #include "dojump.h" +#include "calls.h" #include "explow.h" #include "expr.h" #include "stringpool.h" @@ -817,6 +818,16 @@ promote_function_mode (const_tree type, machine_mode mode, int *punsignedp, return mode; } } + +machine_mode +promote_function_mode (cumulative_args_t args_so_far, function_arg_info arg, + const_tree funtype, int *punsignedp , int for_return) +{ + return targetm.calls.promote_function_mode_ca (args_so_far, arg, funtype, + punsignedp, for_return); +// return promote_function_mode (arg.type, arg.mode, punsignedp, funtype, for_return); +} + /* Return the mode to use to store a scalar of TYPE and MODE. PUNSIGNEDP points to the signedness of the type and may be adjusted to show what signedness to use on extension operations. */ diff --git a/gcc/explow.h b/gcc/explow.h index 16aa02cfb68..6cc989798be 100644 --- a/gcc/explow.h +++ b/gcc/explow.h @@ -20,6 +20,8 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_EXPLOW_H #define GCC_EXPLOW_H +#include "calls.h" /* for cummulative args stuff. */ + /* Return a memory reference like MEMREF, but which is known to have a valid address. */ extern rtx validize_mem (rtx); @@ -47,8 +49,13 @@ extern rtx force_not_mem (rtx); /* Return mode and signedness to use when an argument or result in the given mode is promoted. */ -extern machine_mode promote_function_mode (const_tree, machine_mode, int *, - const_tree, int); +machine_mode promote_function_mode (const_tree, machine_mode, int *, + const_tree, int); + +/* Return mode and signedness to use when an argument or result in the + given mode is promoted. */ +machine_mode promote_function_mode (cumulative_args_t, function_arg_info, + const_tree, int *, int); /* Return mode and signedness to use when an object in the given mode is promoted. */ diff --git a/gcc/function.cc b/gcc/function.cc index 4edd4da1247..7e5434fd2af 100644 --- a/gcc/function.cc +++ b/gcc/function.cc @@ -58,8 +58,8 @@ along with GCC; see the file COPYING3. If not see #include "varasm.h" #include "except.h" #include "dojump.h" -#include "explow.h" #include "calls.h" +#include "explow.h" #include "expr.h" #include "optabs-tree.h" #include "output.h" @@ -2449,7 +2449,10 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, else if (DECL_CHAIN (parm)) data->arg.named = 1; /* Not the last non-variadic parm. */ else if (targetm.calls.strict_argument_naming (all->args_so_far)) - data->arg.named = 1; /* Only variadic ones are unnamed. */ + { + data->arg.named = 1; /* Only variadic ones are unnamed. */ + data->arg.last_named = 1; + } else data->arg.named = 0; /* Treat as variadic. */ @@ -2491,9 +2494,12 @@ assign_parm_find_data_types (struct assign_parm_data_all *all, tree parm, /* Find mode as it is passed by the ABI. */ unsignedp = TYPE_UNSIGNED (data->arg.type); - data->arg.mode - = promote_function_mode (data->arg.type, data->arg.mode, &unsignedp, - TREE_TYPE (current_function_decl), 0); +// data->arg.mode +// = promote_function_mode (data->arg.type, data->arg.mode, &unsignedp, +// TREE_TYPE (current_function_decl), 0); + data->arg.mode = promote_function_mode (all->args_so_far, data->arg, + TREE_TYPE (current_function_decl), + &unsignedp, 0); } /* A subroutine of assign_parms. Invoke setup_incoming_varargs. */ @@ -2506,6 +2512,7 @@ assign_parms_setup_varargs (struct assign_parm_data_all *all, function_arg_info last_named_arg = data->arg; last_named_arg.named = true; + last_named_arg.last_named = true; targetm.calls.setup_incoming_varargs (all->args_so_far, last_named_arg, &varargs_pretend_bytes, no_rtl); @@ -2614,7 +2621,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, locate_and_pad_parm (data->arg.mode, data->arg.type, in_regs, all->reg_parm_stack_space, - entry_parm ? data->partial : 0, current_function_decl, + entry_parm ? data->partial : 0, + all->args_so_far, + current_function_decl, &all->stack_args_size, &data->locate); /* Update parm_stack_boundary if this parameter is passed in the @@ -3921,7 +3930,8 @@ gimplify_parameters (gimple_seq *cleanup) if (data.arg.pass_by_reference) { tree type = TREE_TYPE (data.arg.type); - function_arg_info orig_arg (type, data.arg.named); + function_arg_info orig_arg (type, data.arg.named, + data.arg.last_named); if (reference_callee_copied (&all.args_so_far_v, orig_arg)) { tree local, t; @@ -4024,6 +4034,7 @@ gimplify_parameters (gimple_seq *cleanup) void locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, int reg_parm_stack_space, int partial, + cumulative_args_t ca, tree fndecl ATTRIBUTE_UNUSED, struct args_size *initial_offset_ptr, struct locate_and_pad_arg_data *locate) @@ -4061,9 +4072,23 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, ? arg_size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode))); where_pad = targetm.calls.function_arg_padding (passed_mode, type); - boundary = targetm.calls.function_arg_boundary (passed_mode, type); - round_boundary = targetm.calls.function_arg_round_boundary (passed_mode, - type); + + if (flag_stack_use_cumulative_args) + { + boundary = targetm.calls.function_arg_boundary_ca (passed_mode, + type, + ca); + round_boundary = targetm.calls.function_arg_round_boundary_ca + (passed_mode, type, ca); + } + else + { + boundary = targetm.calls.function_arg_boundary (passed_mode, + type); + round_boundary = targetm.calls.function_arg_round_boundary + (passed_mode, type); + } + locate->where_pad = where_pad; /* Alignment can't exceed MAX_SUPPORTED_STACK_ALIGNMENT. */ diff --git a/gcc/function.h b/gcc/function.h index c0ba6cc1531..520fde7694c 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_FUNCTION_H #define GCC_FUNCTION_H +#include "cumulative-args.h" /* Stack of pending (incomplete) sequences saved by `start_sequence'. Each element describes one pending sequence. @@ -680,6 +681,7 @@ extern bool aggregate_value_p (const_tree, const_tree); extern bool use_register_for_decl (const_tree); extern gimple_seq gimplify_parameters (gimple_seq *); extern void locate_and_pad_parm (machine_mode, tree, int, int, int, + cumulative_args_t, tree, struct args_size *, struct locate_and_pad_arg_data *); extern void generate_setjmp_warnings (void); diff --git a/gcc/ginclude/stddef.h b/gcc/ginclude/stddef.h index 349213108ce..be884e96336 100644 --- a/gcc/ginclude/stddef.h +++ b/gcc/ginclude/stddef.h @@ -428,9 +428,8 @@ typedef struct { /* _Float128 is defined as a basic type, so max_align_t must be sufficiently aligned for it. This code must work in C++, so we use __float128 here; that is only available on some - architectures, but only on i386 is extra alignment needed for - __float128. */ -#ifdef __i386__ + architectures. */ +#if defined(__i386__) || (__APPLE__ && __aarch64__) __float128 __max_align_f128 __attribute__((__aligned__(__alignof(__float128)))); #endif } max_align_t; diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 74e847b2dec..58d282046e8 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -21,6 +21,9 @@ along with GCC; see the file COPYING3. If not see #define LIBGCCJIT_H #include +#ifdef __APPLE__ +# include /* For ssize_t. */ +#endif #ifdef __cplusplus extern "C" { diff --git a/gcc/objc/objc-next-runtime-abi-02.cc b/gcc/objc/objc-next-runtime-abi-02.cc index cdf559b9bea..248ef641281 100644 --- a/gcc/objc/objc-next-runtime-abi-02.cc +++ b/gcc/objc/objc-next-runtime-abi-02.cc @@ -72,6 +72,7 @@ along with GCC; see the file COPYING3. If not see #define TAG_MSGSENDSUPER_STRET "objc_msgSendSuper2_stret" #define USE_FIXUP_BEFORE 100600 +#define WEAK_PROTOCOLS_AFTER 100700 #define TAG_FIXUP "_fixup" @@ -1025,7 +1026,7 @@ next_runtime_abi_02_protocol_decl (tree p) /* static struct _objc_protocol _OBJC_Protocol_; */ snprintf (buf, BUFSIZE, "_OBJC_Protocol_%s", IDENTIFIER_POINTER (PROTOCOL_NAME (p))); - if (flag_next_runtime >= USE_FIXUP_BEFORE) + if (flag_next_runtime >= WEAK_PROTOCOLS_AFTER) { decl = create_hidden_decl (objc_v2_protocol_template, buf); DECL_WEAK (decl) = true; @@ -2315,7 +2316,7 @@ build_v2_protocol_list_address_table (void) gcc_assert (ref->id && TREE_CODE (ref->id) == PROTOCOL_INTERFACE_TYPE); snprintf (buf, BUFSIZE, "_OBJC_LabelProtocol_%s", IDENTIFIER_POINTER (PROTOCOL_NAME (ref->id))); - if (flag_next_runtime >= USE_FIXUP_BEFORE) + if (flag_next_runtime >= WEAK_PROTOCOLS_AFTER) { decl = create_hidden_decl (objc_protocol_type, buf, /*is def=*/true); DECL_WEAK (decl) = true; diff --git a/gcc/target.def b/gcc/target.def index fdad7bbc93e..e2f7d107e49 100644 --- a/gcc/target.def +++ b/gcc/target.def @@ -4680,6 +4680,13 @@ if you would like to apply the same rules given by @code{PROMOTE_MODE}.", const_tree funtype, int for_return), default_promote_function_mode) +DEFHOOK +(promote_function_mode_ca, + "Like @code{promote_function_mode}, but takes a cumulative_args pointer \ + and a current arg to supply the input.", + machine_mode, (cumulative_args_t, function_arg_info, const_tree, int *, int), + default_promote_function_mode_ca) + DEFHOOK (promote_prototypes, "This target hook returns @code{true} if an argument declared in a\n\ @@ -5133,6 +5140,18 @@ with the specified mode and type. The default hook returns\n\ unsigned int, (machine_mode mode, const_tree type), default_function_arg_boundary) +DEFHOOK +(function_arg_boundary_ca, + "This is the @code{cumulative_args_t}-based version of\n\ +@code{TARGET_FUNCTION_ARG_BOUNDARY}. Define this hook if you need more\n\ +fine-grained control over argument alignment, e.g. depending on whether\n\ +it is a named argument or not, or any other criteria that you choose to\n\ +place in the @var{ca} structure.\n\ +\n\ +The default hook will call @code{TARGET_FUNCTION_ARG_BOUNDARY}.", + unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), + default_function_arg_boundary_ca) + DEFHOOK (function_arg_round_boundary, "Normally, the size of an argument is rounded up to @code{PARM_BOUNDARY},\n\ @@ -5142,6 +5161,18 @@ value.", unsigned int, (machine_mode mode, const_tree type), default_function_arg_round_boundary) +DEFHOOK +(function_arg_round_boundary_ca, + "This is the @code{cumulative_args_t}-based version of\n\ +@code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}. Define this hook if you need more\n\ +fine-grained control over argument size rounding, e.g. depending on whether\n\ +it is a named argument or not, or any other criteria that you choose to\n\ +place in the @var{ca} structure.\n\ +\n\ +The default hook will call @code{TARGET_FUNCTION_ARG_ROUND_BOUNDARY}.", + unsigned int, (machine_mode mode, const_tree type, cumulative_args_t ca), + default_function_arg_round_boundary_ca) + /* Return the diagnostic message string if function without a prototype is not allowed for this 'val' argument; NULL otherwise. */ DEFHOOK @@ -7378,6 +7409,16 @@ DEFHOOKPOD libatomic. The default value is false.", bool, false) +/* This value represents whether __builtin_unreachable should be expanded + as a trap instruction (or an abort() if the trap is not available). */ +DEFHOOK +(unreachable_should_trap, + "This hook should return @code{true} if the target wants \ + @code{__builtin_unreachable} to expand to a trap or @code{abort ()}.\n\ + The default value is false.", + bool, (void), + hook_bool_void_false) + /* Close the 'struct gcc_target' definition. */ HOOK_VECTOR_END (C90_EMPTY_HACK) diff --git a/gcc/target.h b/gcc/target.h index c1f99b97b86..b51630a9782 100644 --- a/gcc/target.h +++ b/gcc/target.h @@ -51,22 +51,8 @@ #include "insn-codes.h" #include "tm.h" #include "hard-reg-set.h" - -#if CHECKING_P - -struct cumulative_args_t { void *magic; void *p; }; - -#else /* !CHECKING_P */ - -/* When using a GCC build compiler, we could use - __attribute__((transparent_union)) to get cumulative_args_t function - arguments passed like scalars where the ABI would mandate a less - efficient way of argument passing otherwise. However, that would come - at the cost of less type-safe !CHECKING_P compilation. */ - -union cumulative_args_t { void *p; }; - -#endif /* !CHECKING_P */ +#include "tree-core.h" +#include "cumulative-args.h" /* Target properties of _BitInt(N) type. _BitInt(N) is to be represented as series of abi_limb_mode CEIL (N, GET_MODE_PRECISION (abi_limb_mode)) diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc index 8c84deea97d..4f16af8ec1e 100644 --- a/gcc/targhooks.cc +++ b/gcc/targhooks.cc @@ -161,6 +161,15 @@ default_promote_function_mode_always_promote (const_tree type, return promote_mode (type, mode, punsignedp); } +machine_mode +default_promote_function_mode_ca (cumulative_args_t, function_arg_info arg, + const_tree funtype, int *punsignedp, + int for_return) +{ + return promote_function_mode (arg.type, arg.mode, punsignedp, + funtype, for_return); +} + machine_mode default_cc_modes_compatible (machine_mode m1, machine_mode m2) { @@ -868,6 +877,14 @@ default_function_arg_boundary (machine_mode mode ATTRIBUTE_UNUSED, return PARM_BOUNDARY; } +unsigned int +default_function_arg_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + return default_function_arg_boundary (mode, type); +} + unsigned int default_function_arg_round_boundary (machine_mode mode ATTRIBUTE_UNUSED, const_tree type ATTRIBUTE_UNUSED) @@ -875,6 +892,14 @@ default_function_arg_round_boundary (machine_mode mode ATTRIBUTE_UNUSED, return PARM_BOUNDARY; } +unsigned int +default_function_arg_round_boundary_ca (machine_mode mode ATTRIBUTE_UNUSED, + const_tree type ATTRIBUTE_UNUSED, + cumulative_args_t ca ATTRIBUTE_UNUSED) +{ + return default_function_arg_round_boundary (mode, type); +} + void hook_void_bitmap (bitmap regs ATTRIBUTE_UNUSED) { diff --git a/gcc/targhooks.h b/gcc/targhooks.h index ca289f30eda..f7557cb8e81 100644 --- a/gcc/targhooks.h +++ b/gcc/targhooks.h @@ -34,6 +34,9 @@ extern machine_mode default_promote_function_mode (const_tree, machine_mode, extern machine_mode default_promote_function_mode_always_promote (const_tree, machine_mode, int *, const_tree, int); +extern machine_mode default_promote_function_mode_ca + (cumulative_args_t, function_arg_info, const_tree, int *, int); + extern machine_mode default_cc_modes_compatible (machine_mode, machine_mode); @@ -159,6 +162,12 @@ extern unsigned int default_function_arg_boundary (machine_mode, const_tree); extern unsigned int default_function_arg_round_boundary (machine_mode, const_tree); +extern unsigned int default_function_arg_boundary_ca (machine_mode, + const_tree, + cumulative_args_t ca); +extern unsigned int default_function_arg_round_boundary_ca (machine_mode, + const_tree, + cumulative_args_t ca); extern bool hook_bool_const_rtx_commutative_p (const_rtx, int); extern rtx default_function_value (const_tree, const_tree, bool); extern HARD_REG_SET default_zero_call_used_regs (HARD_REG_SET); diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc b/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc new file mode 100644 index 00000000000..4f581694177 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr106435-b.cc @@ -0,0 +1,17 @@ +// PR c++/106435 +#include "pr106435.h" + +//#include + +Foo::Foo() { + ++num_calls; +// std::cout << "Foo::Foo(this=" << this << ")\n"; +} + +int Foo::func() { +// std::cout << "Foo::func(this=" << this << ")\n"; + return num_calls; +} + +thread_local Foo Bar::foo; +thread_local Foo Bar::baz; diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435.C b/gcc/testsuite/g++.dg/cpp0x/pr106435.C new file mode 100644 index 00000000000..d600976f9f9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr106435.C @@ -0,0 +1,20 @@ +// PR c++/106435 +// { dg-do run { target c++11 } } +// { dg-additional-sources "pr106435-b.cc" } + +#include "pr106435.h" + +int num_calls = 0; + +extern "C" __attribute__((__noreturn__)) void abort(); + +thread_local Foo Bar::bat; + +int main() { + int v = Bar::foo.func(); + if (v != 2) + abort(); + v = Bar::bat.func(); + if (v != 3) + abort(); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr106435.h b/gcc/testsuite/g++.dg/cpp0x/pr106435.h new file mode 100644 index 00000000000..240de1ee9a9 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr106435.h @@ -0,0 +1,14 @@ +// PR c++/106435 +#pragma once + +extern int num_calls; +struct Foo { + Foo(); + int func(); +}; + +struct Bar { + thread_local static Foo foo; + thread_local static Foo baz; + thread_local static Foo bat; +}; diff --git a/gcc/testsuite/g++.target/aarch64/float128-darwin-1.C b/gcc/testsuite/g++.target/aarch64/float128-darwin-1.C new file mode 100644 index 00000000000..0dbed063a71 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/float128-darwin-1.C @@ -0,0 +1,41 @@ +/* { dg-do run { target { aarch64*-*-darwin* } } } */ +/* { dg-options "-std=c++11 -std=gnu++98" } */ + +#include +#include +#include + +void foo () +{ + float x1 = 1.0q; + double x2 = 1.0q; + long double x3 = 1.0q; + + _Float128 w1 = 0; + __float128 w2 = 0; + + float y1 = w1; // { dg-warning "with greater conversion rank" } + double y2 = w1; // { dg-warning "with greater conversion rank" } + long double y3 = w1; // { dg-warning "with greater conversion rank" } + + float z1 = w2; + double z2 = w2; + long double z3 = w2; +} + +int main () +{ + // Check the correct mangling of floating-point types + if (typeid(float).name() != std::string("f")) + __builtin_abort(); + if (typeid(double).name() != std::string("d")) + __builtin_abort(); + if (typeid(long double).name() != std::string("e")) + __builtin_abort(); + if (typeid(__float128).name() != std::string("g")) + __builtin_abort(); + if (typeid(_Float128).name() != std::string("DF128_")) + __builtin_abort(); + if (typeid(1.0q).name() != std::string("g")) + __builtin_abort(); +} diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/float128-01.c b/gcc/testsuite/gcc.target/aarch64/darwin/float128-01.c new file mode 100644 index 00000000000..93f6d24cebc --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/darwin/float128-01.c @@ -0,0 +1,48 @@ +/* { dg-do run } */ +/* we need this for _Float128. */ +/* { dg-options "-std=gnu99 " } */ +/* { dg-additional-options "-Wfloat-conversion" } */ + +float f1 (__float128 z1, _Float128 z2) +{ + float x, y; + x = z1; /* { dg-warning "conversion from '_Float128' to 'float'" } */ + y = z2; /* { dg-warning "conversion from '_Float128' to 'float'" } */ + return x + y; +} + +__float128 f2 () { + float f = 0.q; + return f; +} + +_Float128 f3 () { + float f = 0.q; + return f; +} + +int main () +{ + __float128 x1 = __builtin_huge_valq (); + __float128 x2 = __builtin_infq (); + + _Float128 y1 = __builtin_huge_valq (); + _Float128 y2 = __builtin_infq (); + + if (!__builtin_isinf (x1)) + __builtin_abort(); + if (!__builtin_isinf (x2)) + __builtin_abort(); + + if (!__builtin_isinf (y1)) + __builtin_abort(); + if (!__builtin_isinf (y2)) + __builtin_abort(); + + if (x1 != x2) + __builtin_abort(); + if (y1 != y2) + __builtin_abort(); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/darwin/float128-02.c b/gcc/testsuite/gcc.target/aarch64/darwin/float128-02.c new file mode 100644 index 00000000000..5a8522f9622 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/darwin/float128-02.c @@ -0,0 +1,101 @@ +/* { dg-do run } */ +/* we need this for _Float128. */ +/* { dg-options "-std=gnu99 " } */ + +void test (__float128 z1, __float128 z2, __float128 z3, __float128 z4) +{ + __float128 w; + + if (!__builtin_isinf (z1)) + __builtin_abort(); + if (__builtin_isnan (z1)) + __builtin_abort(); + if (__builtin_isfinite (z1)) + __builtin_abort(); + if (__builtin_isnormal (z1)) + __builtin_abort(); + if (__builtin_signbit (z1)) + __builtin_abort(); + + if (__builtin_isinf (z2)) + __builtin_abort(); + if (!__builtin_isnan (z2)) + __builtin_abort(); + if (__builtin_isfinite (z2)) + __builtin_abort(); + if (__builtin_isnormal (z2)) + __builtin_abort(); + if (__builtin_signbit (z2)) + __builtin_abort(); + + if (__builtin_isinf (z3)) + __builtin_abort(); + if (!__builtin_isnan (z3)) + __builtin_abort(); + if (__builtin_isfinite (z3)) + __builtin_abort(); + if (__builtin_isnormal (z3)) + __builtin_abort(); + if (__builtin_signbit (z3)) + __builtin_abort(); + + if (__builtin_isinf (z4)) + __builtin_abort(); + if (__builtin_isnan (z4)) + __builtin_abort(); + if (!__builtin_isfinite (z4)) + __builtin_abort(); + if (!__builtin_isnormal (z4)) + __builtin_abort(); + if (__builtin_signbit (z4)) + __builtin_abort(); + + w = __builtin_copysignq (z1, -z4); + if (!__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z2, -z4); + if (!__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z3, -z4); + if (!__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z4, -z4); + if (!__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z1, -z4); + w = __builtin_fabsq (w); + if (__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z2, -z4); + w = __builtin_fabsq (w); + if (__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z3, -z4); + w = __builtin_fabsq (w); + if (__builtin_signbit (w)) + __builtin_abort(); + + w = __builtin_copysignq (z4, -z4); + w = __builtin_fabsq (w); + if (__builtin_signbit (w)) + __builtin_abort(); + +} + +int main () +{ + __float128 x1 = __builtin_infq (); + __float128 x2 = __builtin_nanq (""); + __float128 x3 = __builtin_nansq (""); + __float128 x4 = 41.1094721q; + + test (x1, x2, x3, x4); + + return 0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp b/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp index 4b2fb4f24ba..c4982183128 100644 --- a/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp +++ b/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp @@ -24,6 +24,11 @@ if {![istarget aarch64*-*-*] } { return } +# Exit immediately if this is Darwin (for now). +if {[istarget *-*-darwin*] } { + return +} + # Load support procs. load_lib gcc-dg.exp diff --git a/libgcc/config.host b/libgcc/config.host index e75a7af647f..d27204f3fb4 100644 --- a/libgcc/config.host +++ b/libgcc/config.host @@ -82,7 +82,7 @@ m32c*-*-*) cpu_type=m32c tmake_file=t-fdpbit ;; -aarch64*-*-*) +aarch64*-*-* | arm64*-*-*) cpu_type=aarch64 ;; alpha*-*-*) @@ -236,7 +236,10 @@ case ${host} in esac tmake_file="$tmake_file t-slibgcc-darwin" case ${host} in - *-*-darwin1[89]* | *-*-darwin2* ) + *-*-darwin2*) + tmake_file="t-darwin-min-11 $tmake_file" + ;; + *-*-darwin1[89]*) tmake_file="t-darwin-min-8 $tmake_file" ;; *-*-darwin9* | *-*-darwin1[0-7]*) @@ -274,7 +277,7 @@ case ${host} in if test "x$enable_darwin_at_rpath" = "xyes"; then tmake_file="$tmake_file t-darwin-rpath " fi - extra_parts="crt3.o libd10-uwfef.a crttms.o crttme.o libemutls_w.a" + extra_parts="crt3.o crttms.o crttme.o libemutls_w.a " ;; *-*-dragonfly*) tmake_file="$tmake_file t-crtstuff-pic t-libgcc-pic t-eh-dw2-dip" @@ -418,6 +421,15 @@ aarch64*-*-elf | aarch64*-*-rtems*) tmake_file="${tmake_file} t-dfprules" md_unwind_header=aarch64/aarch64-unwind.h ;; +aarch64*-*-darwin*) + extra_parts="$extra_parts crtfastmath.o libheapt_w.a" + tmake_file="${tmake_file} ${cpu_type}/t-aarch64" + tmake_file="${tmake_file} ${cpu_type}/t-lse" + tmake_file="${tmake_file} t-crtfm t-dfprules" + tmake_file="${tmake_file} ${cpu_type}/t-softfp t-softfp" + tmake_file="${tmake_file} ${cpu_type}/t-heap-trampoline" + md_unwind_header=aarch64/aarch64-unwind.h + ;; aarch64*-*-freebsd*) extra_parts="$extra_parts crtfastmath.o" tmake_file="${tmake_file} ${cpu_type}/t-aarch64" @@ -725,14 +737,14 @@ i[34567]86-*-darwin*) tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" tm_file="$tm_file i386/darwin-lib.h" extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o" - extra_parts="$extra_parts crtfastmath.o libheapt_w.a" + extra_parts="$extra_parts crtfastmath.o libd10-uwfef.a libheapt_w.a" tmake_file="${tmake_file} i386/t-heap-trampoline" ;; x86_64-*-darwin*) tmake_file="$tmake_file i386/t-crtpc t-crtfm i386/t-msabi" tm_file="$tm_file i386/darwin-lib.h" extra_parts="$extra_parts crtprec32.o crtprec64.o crtprec80.o" - extra_parts="$extra_parts crtfastmath.o libheapt_w.a" + extra_parts="$extra_parts crtfastmath.o libd10-uwfef.a libheapt_w.a" tmake_file="${tmake_file} i386/t-heap-trampoline" ;; i[34567]86-*-elfiamcu) @@ -1215,12 +1227,14 @@ powerpc-*-darwin*) # We build the darwin10 EH shim for Rosetta (running on x86 machines). tm_file="$tm_file i386/darwin-lib.h" tmake_file="$tmake_file rs6000/t-ppc64-fp rs6000/t-ibm-ldouble" + extra_parts="$extra_parts libd10-uwfef.a " extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" ;; powerpc64-*-darwin*) # We build the darwin10 EH shim for Rosetta (running on x86 machines). tm_file="$tm_file i386/darwin-lib.h" tmake_file="$tmake_file rs6000/t-darwin64 rs6000/t-ibm-ldouble" + extra_parts="$extra_parts libd10-uwfef.a " extra_parts="$extra_parts crt2.o crt3_2.o libef_ppc.a dw_ppc.o" ;; powerpc*-*-freebsd*) diff --git a/libgcc/config/aarch64/__arm_sme_state.S b/libgcc/config/aarch64/__arm_sme_state.S index 1fbb8c1ff53..b665769004f 100644 --- a/libgcc/config/aarch64/__arm_sme_state.S +++ b/libgcc/config/aarch64/__arm_sme_state.S @@ -30,14 +30,19 @@ - Takes no argument. - Returns SME state in x0 and TPIDR2_EL0 in x1. */ -HIDDEN (__aarch64_have_sme) +HIDDEN (ASMNAME (__aarch64_have_sme)) -variant_pcs (__arm_sme_state) +variant_pcs (ASMNAME (__arm_sme_state)) -ENTRY (__arm_sme_state) +ENTRY (ASMNAME (__arm_sme_state)) /* Check if SME is available. */ - adrp x1, __aarch64_have_sme - ldrb w1, [x1, :lo12:__aarch64_have_sme] +#ifdef __APPLE__ + adrp x1, ASMNAME (__aarch64_have_sme)@PAGE + ldrb w1, [x1, ASMNAME (__aarch64_have_sme)@PAGEOFF] +#else + adrp x1, ASMNAME (__aarch64_have_sme) + ldrb w1, [x1, :lo12:ASMNAME (__aarch64_have_sme)] +#endif cbz w1, L(nosme) /* Expose the bottom 2 bits of svcr (SM, ZA) in x0 and set the @@ -52,4 +57,4 @@ L(nosme): mov x0, 0 mov x1, 0 ret -END (__arm_sme_state) +ENDm ASMNAME(__arm_sme_state) diff --git a/libgcc/config/aarch64/__arm_tpidr2_restore.S b/libgcc/config/aarch64/__arm_tpidr2_restore.S index 5088c86df32..bcfb935bc96 100644 --- a/libgcc/config/aarch64/__arm_tpidr2_restore.S +++ b/libgcc/config/aarch64/__arm_tpidr2_restore.S @@ -31,9 +31,9 @@ - Does not return a value. - Can abort on failure (then registers are not preserved). */ -variant_pcs (__arm_tpidr2_restore) +variant_pcs (ASMNAME (__arm_tpidr2_restore)) -ENTRY (__arm_tpidr2_restore) +ENTRY (ASMNAME (__arm_tpidr2_restore)) .inst 0xd53bd0ae /* mrs x14, tpidr2_el0 */ cbnz x14, L(fail) @@ -85,5 +85,5 @@ L(fail): str x16, [sp, 16] .cfi_rel_offset 46, 16 .inst 0xd503467f /* smstop */ - bl abort -END (__arm_tpidr2_restore) + bl ASMNAME (abort) +ENDm ASMNAME (__arm_tpidr2_restore) diff --git a/libgcc/config/aarch64/__arm_tpidr2_save.S b/libgcc/config/aarch64/__arm_tpidr2_save.S index 2466b5863e4..28e75ade2d0 100644 --- a/libgcc/config/aarch64/__arm_tpidr2_save.S +++ b/libgcc/config/aarch64/__arm_tpidr2_save.S @@ -35,10 +35,15 @@ HIDDEN (__aarch64_have_sme) variant_pcs (__arm_tpidr2_save) -ENTRY (__arm_tpidr2_save) +ENTRY (ASMNAME (__arm_tpidr2_save)) /* Check if SME is available. */ - adrp x14, __aarch64_have_sme - ldrb w14, [x14, :lo12:__aarch64_have_sme] +#if __APPLE__ + adrp x14, ASMNAME (__aarch64_have_sme)@PAGE + ldrb w14, [x14, ASMNAME (__aarch64_have_sme)@PAGEOFF] +#else + adrp x14, ASMNAME (__aarch64_have_sme) + ldrb w14, [x14, :lo12:ASMNAME (__aarch64_have_sme)] +#endif cbz w14, L(end) .inst 0xd53bd0ae /* mrs x14, tpidr2_el0 */ @@ -92,10 +97,18 @@ L(fail): str x16, [sp, 16] .cfi_rel_offset 46, 16 .inst 0xd503467f /* smstop */ - bl abort -END (__arm_tpidr2_save) - + bl ASMNAME (abort) +ENDm ASMNAME (__arm_tpidr2_save) + + GLOBAL(ASMNAME (__libgcc_arm_tpidr2_save)) + HIDDEN (ASMNAME (__libgcc_arm_tpidr2_save)) +#if __APPLE__ + .text + .p2align 4 +ASMNAME (__libgcc_arm_tpidr2_save): + b ASMNAME (__arm_tpidr2_save) +#else /* Hidden alias used by __arm_za_disable. */ -.global __libgcc_arm_tpidr2_save -HIDDEN (__libgcc_arm_tpidr2_save) -.set __libgcc_arm_tpidr2_save, __arm_tpidr2_save +.set ASMNAME (__libgcc_arm_tpidr2_save), ASMNAME (__arm_tpidr2_save) +#endif + diff --git a/libgcc/config/aarch64/__arm_za_disable.S b/libgcc/config/aarch64/__arm_za_disable.S index c372fcffe18..9aefed6cde7 100644 --- a/libgcc/config/aarch64/__arm_za_disable.S +++ b/libgcc/config/aarch64/__arm_za_disable.S @@ -31,16 +31,33 @@ - Does not return a value. - Can abort on failure (then registers are not preserved). */ -HIDDEN (__aarch64_have_sme) +HIDDEN (ASMNAME(__aarch64_have_sme)) -HIDDEN (__libgcc_arm_tpidr2_save) +HIDDEN (ASMNAME(__libgcc_arm_tpidr2_save)) -variant_pcs (__arm_za_disable) +variant_pcs (ASMNAME(__arm_za_disable)) -ENTRY (__arm_za_disable) +GLOBAL (ASMNAME (__libgcc_arm_za_disable)) +HIDDEN (ASMNAME (__libgcc_arm_za_disable)) +#if __APPLE__ + .text + .p2align 4 +ASMNAME (__libgcc_arm_za_disable): + b ASMNAME (__arm_za_disable) +#else +/* Hidden alias used by the unwinder. */ +.set ASMNAME (__libgcc_arm_za_disable), ASMNAME (__arm_za_disable) +#endif + +ENTRY (ASMNAME (__arm_za_disable)) /* Check if SME is available. */ - adrp x14, __aarch64_have_sme - ldrb w14, [x14, :lo12:__aarch64_have_sme] +#if __APPLE__ + adrp x14, ASMNAME (__aarch64_have_sme)@PAGE + ldrb w14, [x14, ASMNAME (__aarch64_have_sme)@PAGEOFF] +#else + adrp x14, ASMNAME (__aarch64_have_sme) + ldrb w14, [x14, :lo12:ASMNAME (__aarch64_have_sme)] +#endif cbz w14, L(end) .inst 0xd53bd0ae /* mrs x14, tpidr2_el0 */ @@ -52,7 +69,7 @@ ENTRY (__arm_za_disable) .cfi_rel_offset x29, 0 .cfi_rel_offset x30, 8 mov x29, sp - bl __libgcc_arm_tpidr2_save + bl ASMNAME (__libgcc_arm_tpidr2_save) .inst 0xd51bd0bf /* msr tpidr2_el0, xzr */ .inst 0xd503447f /* smstop za */ ldp x29, x30, [sp], 16 @@ -62,9 +79,5 @@ ENTRY (__arm_za_disable) AUTIASP L(end): ret -END (__arm_za_disable) +ENDm ASMNAME(__arm_za_disable) -/* Hidden alias used by the unwinder. */ -.global __libgcc_arm_za_disable -HIDDEN (__libgcc_arm_za_disable) -.set __libgcc_arm_za_disable, __arm_za_disable diff --git a/libgcc/config/aarch64/aarch64-asm.h b/libgcc/config/aarch64/aarch64-asm.h index 83c2e5944b3..7e41e6eb082 100644 --- a/libgcc/config/aarch64/aarch64-asm.h +++ b/libgcc/config/aarch64/aarch64-asm.h @@ -24,8 +24,6 @@ #include "auto-target.h" -#define L(label) .L ## label - /* Marking variant PCS symbol references is important for PLT calls otherwise it is for documenting the PCS in the symbol table. */ #ifdef HAVE_AS_VARIANT_PCS @@ -58,12 +56,31 @@ # define AUTIASP #endif +#define PASTE2(a, b) PASTE2a(a, b) +#define PASTE2a(a, b) a ## b + +#ifdef __USER_LABEL_PREFIX__ +# define ASMNAME(name) PASTE2(__USER_LABEL_PREFIX__, name) +#else +# define ASMNAME(name) name +#endif + #ifdef __ELF__ +#define L(label) .L ## label #define HIDDEN(name) .hidden name +#define GLOBAL(name) .global name #define SYMBOL_SIZE(name) .size name, .-name #define SYMBOL_TYPE(name, _type) .type name, _type +#elif __APPLE__ +#define L(label) L ## label +#define HIDDEN(name) .private_extern name +#define GLOBAL(name) .globl name +#define SYMBOL_SIZE(name) +#define SYMBOL_TYPE(name, _type) #else +#define L(label) .L ## label #define HIDDEN(name) +#define GLOBAL(name) .global name #define SYMBOL_SIZE(name) #define SYMBOL_TYPE(name, _type) #endif @@ -93,16 +110,19 @@ GNU_PROPERTY (FEATURE_1_AND, BTI_FLAG|PAC_FLAG) # endif #endif -#define ENTRY_ALIGN(name, align) \ - .global name; \ - SYMBOL_TYPE(name, %function); \ - .balign align; \ - name: \ - .cfi_startproc; \ - BTI_C - -#define ENTRY(name) ENTRY_ALIGN(name, 16) - -#define END(name) \ - .cfi_endproc; \ - SYMBOL_SIZE(name) +.macro ENTRY_ALIGNP2m, name, align + .text + .p2align \align + GLOBAL (\name) + SYMBOL_TYPE(\name, %function) +\name: + .cfi_startproc + BTI_C +.endm + +#define ENTRY(name) ENTRY_ALIGNP2m name, 4 + +.macro ENDm, name + .cfi_endproc + SYMBOL_SIZE (\name) +.endm diff --git a/libgcc/config/aarch64/lse.S b/libgcc/config/aarch64/lse.S index ecef47086c6..54b85b5ad2a 100644 --- a/libgcc/config/aarch64/lse.S +++ b/libgcc/config/aarch64/lse.S @@ -62,7 +62,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #endif /* Declare the symbol gating the LSE implementations. */ - HIDDEN(__aarch64_have_lse_atomics) + HIDDEN (ASMNAME (__aarch64_have_lse_atomics)) /* Turn size and memory model defines into mnemonic fragments. */ #if SIZE == 1 @@ -85,6 +85,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see # error #endif +#undef L #if MODEL == 1 # define SUFF _relax # define A @@ -167,32 +168,21 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define tmp3 14 #define tmp4 13 -/* Start and end a function. */ -.macro STARTFN name - .text - .balign 16 - .globl \name - HIDDEN(\name) - SYMBOL_TYPE(\name, %function) - .cfi_startproc -\name: -.endm - -.macro ENDFN name - .cfi_endproc - SYMBOL_SIZE(\name) -.endm - /* Branch to LABEL if LSE is disabled. */ .macro JUMP_IF_NOT_LSE label - adrp x(tmp0), __aarch64_have_lse_atomics - ldrb w(tmp0), [x(tmp0), :lo12:__aarch64_have_lse_atomics] +#if __APPLE__ + adrp x(tmp0), ASMNAME (__aarch64_have_lse_atomics)@PAGE + ldrb w(tmp0), [x(tmp0), ASMNAME (__aarch64_have_lse_atomics)@PAGEOFF] +#else + adrp x(tmp0), ASMNAME (__aarch64_have_lse_atomics) + ldrb w(tmp0), [x(tmp0), :lo12:ASMNAME (__aarch64_have_lse_atomics)] +#endif cbz w(tmp0), \label .endm #ifdef L_cas -STARTFN NAME(cas) +ENTRY (ASMNAME (NAME(cas))) JUMP_IF_NOT_LSE 8f #if SIZE < 16 @@ -245,7 +235,7 @@ STARTFN NAME(cas) #endif -ENDFN NAME(cas) +ENDm ASMNAME (NAME(cas)) #endif #ifdef L_swp @@ -255,7 +245,7 @@ ENDFN NAME(cas) # define SWP .inst 0x38208020 + B + N #endif -STARTFN NAME(swp) +ENTRY (ASMNAME (NAME (swp))) JUMP_IF_NOT_LSE 8f SWP /* s(0), s(0), [x1] */ @@ -268,7 +258,7 @@ STARTFN NAME(swp) BARRIER ret -ENDFN NAME(swp) +ENDm ASMNAME (NAME (swp)) #endif #if defined(L_ldadd) || defined(L_ldclr) \ @@ -299,7 +289,7 @@ ENDFN NAME(swp) # define LDOP .inst 0x38200020 + OPN + B + N #endif -STARTFN NAME(LDNM) +ENTRY (ASMNAME (NAME (LDNM))) JUMP_IF_NOT_LSE 8f LDOP /* s(0), s(0), [x1] */ @@ -313,5 +303,5 @@ STARTFN NAME(LDNM) BARRIER ret -ENDFN NAME(LDNM) +ENDm ASMNAME (NAME (LDNM)) #endif diff --git a/libgcc/config/aarch64/sfp-machine.h b/libgcc/config/aarch64/sfp-machine.h index 7fbb2a4288a..3ebc1d5fe44 100644 --- a/libgcc/config/aarch64/sfp-machine.h +++ b/libgcc/config/aarch64/sfp-machine.h @@ -124,6 +124,27 @@ void __sfp_handle_exceptions (int); /* Define ALIASNAME as a strong alias for NAME. */ +#if defined __APPLE__ +/* Mach-O doesn't support aliasing, so we build a secondary function for + the alias - we need to do a bit of a dance to find out what the type of + the arguments is and then apply that to the secondary function. + If these functions ever return anything but CMPtype we need to revisit + this... */ +typedef float alias_HFtype __attribute__ ((mode (HF))); +typedef float alias_SFtype __attribute__ ((mode (SF))); +typedef float alias_DFtype __attribute__ ((mode (DF))); +typedef float alias_TFtype __attribute__ ((mode (TF))); +#define ALIAS_SELECTOR \ + CMPtype (*) (alias_HFtype, alias_HFtype): (alias_HFtype) 0, \ + CMPtype (*) (alias_SFtype, alias_SFtype): (alias_SFtype) 0, \ + CMPtype (*) (alias_DFtype, alias_DFtype): (alias_DFtype) 0, \ + CMPtype (*) (alias_TFtype, alias_TFtype): (alias_TFtype) 0 +#define strong_alias(name, aliasname) \ + CMPtype aliasname (__typeof (_Generic (name, ALIAS_SELECTOR)) a, \ + __typeof (_Generic (name, ALIAS_SELECTOR)) b) \ + { return name (a, b); } +#else # define strong_alias(name, aliasname) _strong_alias(name, aliasname) # define _strong_alias(name, aliasname) \ extern __typeof (name) aliasname __attribute__ ((alias (#name))); +#endif diff --git a/libgcc/config/aarch64/t-darwin b/libgcc/config/aarch64/t-darwin new file mode 100644 index 00000000000..f6ecda7b608 --- /dev/null +++ b/libgcc/config/aarch64/t-darwin @@ -0,0 +1,7 @@ +# Ensure we have a suitable minimum OS version. + +HOST_LIBGCC2_CFLAGS += -mmacosx-version-min=11.0 + +LIB2_SIDITI_CONV_FUNCS = yes + +BUILD_LIBGCCS1 = diff --git a/libgcc/config/t-darwin-min-11 b/libgcc/config/t-darwin-min-11 new file mode 100644 index 00000000000..4009d41addb --- /dev/null +++ b/libgcc/config/t-darwin-min-11 @@ -0,0 +1,3 @@ +# Support building with -mmacosx-version-min back to macOS 11. +DARWIN_MIN_LIB_VERSION = -mmacosx-version-min=11 +DARWIN_MIN_CRT_VERSION = -mmacosx-version-min=11 diff --git a/libitm/config/aarch64/sjlj.S b/libitm/config/aarch64/sjlj.S index 6b248f7c040..dd844e8c9d8 100644 --- a/libitm/config/aarch64/sjlj.S +++ b/libitm/config/aarch64/sjlj.S @@ -57,10 +57,19 @@ .text .align 2 +#if __ELF__ .global _ITM_beginTransaction .type _ITM_beginTransaction, %function _ITM_beginTransaction: + +#elif __MACH__ + .global __ITM_beginTransaction + +__ITM_beginTransaction: + +#endif + cfi_startproc CFI_PAC_KEY PAC_AND_BTI @@ -84,8 +93,13 @@ _ITM_beginTransaction: /* Invoke GTM_begin_transaction with the struct we just built. */ mov x1, sp +#if __ELF__ bl GTM_begin_transaction - +#elif __MACH__ + bl _GTM_begin_transaction +#else +#error "unexpected object format" +#endif /* Return; we don't need to restore any of the call-saved regs. */ ldp x29, x30, [sp], 11*16 cfi_adjust_cfa_offset(-11*16) @@ -95,14 +109,23 @@ _ITM_beginTransaction: CFI_PAC_TOGGLE ret cfi_endproc +#if __ELF__ .size _ITM_beginTransaction, . - _ITM_beginTransaction +#endif .align 2 +#if __ELF__ .global GTM_longjmp .hidden GTM_longjmp .type GTM_longjmp, %function GTM_longjmp: + +#elif __MACH__ + .private_extern _GTM_longjmp + +_GTM_longjmp: +#endif /* The first parameter becomes the return value (x0). The third parameter is ignored for now. */ cfi_startproc @@ -126,7 +149,9 @@ GTM_longjmp: CFI_PAC_TOGGLE br x30 cfi_endproc +#if __ELF__ .size GTM_longjmp, . - GTM_longjmp +#endif /* GNU_PROPERTY_AARCH64_* macros from elf.h for use in asm code. */ #define FEATURE_1_AND 0xc0000000 diff --git a/libitm/configure.tgt b/libitm/configure.tgt index a8276f05d9b..6fad8534372 100644 --- a/libitm/configure.tgt +++ b/libitm/configure.tgt @@ -50,7 +50,7 @@ fi # Map the target cpu to an ARCH sub-directory. At the same time, # work out any special compilation flags as necessary. case "${target_cpu}" in - aarch64*) ARCH=aarch64 ;; + aarch64* | arm64*) ARCH=aarch64 ;; alpha*) ARCH=alpha ;; rs6000 | powerpc*) XCFLAGS="${XCFLAGS} -mhtm"