Forgot attachment, sorry. --- >From dac55e9dbc765ccfcc5a1f49baa4662dae3c3923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Radek=20Barto=C5=88?= <radek.bar...@microsoft.com> Date: Mon, 4 Nov 2024 18:13:30 +0100 Subject: [PATCH] Fix function call handling according to Microsoft Arm64 variadic function call ABI
--- gcc/config.gcc | 5 +- gcc/config/aarch64/aarch64-builtins.cc | 30 +++ gcc/config/aarch64/aarch64-protos.h | 2 + gcc/config/aarch64/aarch64.cc | 315 +++++++++++++++++++++++-- gcc/config/aarch64/aarch64.h | 10 + gcc/config/aarch64/cross-stdarg.h | 42 ++++ gcc/config/aarch64/cygming.h | 13 +- gcc/config/mingw/winnt.cc | 22 ++ gcc/config/mingw/winnt.h | 1 + 9 files changed, 422 insertions(+), 18 deletions(-) create mode 100644 gcc/config/aarch64/cross-stdarg.h diff --git a/gcc/config.gcc b/gcc/config.gcc index 0d8dbc4fb19..5357690840b 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -347,7 +347,10 @@ m32c*-*-*) ;; aarch64*-*-*) cpu_type=aarch64 - extra_headers="arm_fp16.h arm_neon.h arm_bf16.h arm_acle.h arm_sve.h arm_sme.h arm_neon_sve_bridge.h arm_private_fp8.h arm_private_neon_types.h" + extra_headers="arm_fp16.h arm_neon.h arm_bf16.h arm_acle.h arm_sve.h + arm_sme.h arm_neon_sve_bridge.h arm_private_fp8.h + arm_private_neon_types.h + cross-stdarg.h" c_target_objs="aarch64-c.o" cxx_target_objs="aarch64-c.o" d_target_objs="aarch64-d.o" diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 408099a50e8..878d4e76f55 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -2519,6 +2519,36 @@ aarch64_general_init_builtins (void) handle_arm_acle_h (); } +/* Internal method for aarch64_ms_variadic_abi_init_builtins. */ + +void +aarch64_ms_variadic_abi_init_builtins (void) +{ + tree ms_va_ref; + tree fnvoid_va_end_ms; + tree fnvoid_va_start_ms; + tree fnvoid_va_copy_ms; + tree fnattr_ms = NULL_TREE; + + fnattr_ms = build_tree_list (get_identifier ("ms_abi"), NULL_TREE); + ms_va_ref = build_reference_type (ms_va_list_type_node); + + fnvoid_va_end_ms = build_function_type_list (void_type_node, ms_va_ref, + NULL_TREE); + fnvoid_va_start_ms + = build_varargs_function_type_list (void_type_node, ms_va_ref, NULL_TREE); + fnvoid_va_copy_ms + = build_function_type_list (void_type_node, ms_va_ref, ms_va_list_type_node, + NULL_TREE); + + add_builtin_function ("__builtin_ms_va_start", fnvoid_va_start_ms, + BUILT_IN_VA_START, BUILT_IN_NORMAL, NULL, fnattr_ms); + add_builtin_function ("__builtin_ms_va_end", fnvoid_va_end_ms, + BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL, fnattr_ms); + add_builtin_function ("__builtin_ms_va_copy", fnvoid_va_copy_ms, + BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL, fnattr_ms); +} + /* 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-protos.h b/gcc/config/aarch64/aarch64-protos.h index 38c307cdc3a..1c021615754 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -1121,6 +1121,8 @@ 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_ms_variadic_abi_init_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.cc b/gcc/config/aarch64/aarch64.cc index 5502d0b4807..03dd8d87843 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -541,6 +541,9 @@ const sysreg_t aarch64_sysregs[] = using sysreg_map_t = hash_map<nofree_string_hash, const sysreg_t *>; static sysreg_map_t *sysreg_map = nullptr; +/* Microsoft Arm64 variadic function call ABI specific va_list type node. */ +tree ms_va_list_type_node; + /* Map system register names to their hardware metadata: encoding, feature flags and architectural feature requirements, all of which are encoded in a sysreg_t struct. */ @@ -750,6 +753,7 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree name, tree, *no_add_attrs = true; return NULL_TREE; + case ARM_PCS_MS_VARIADIC: case ARM_PCS_TLSDESC: case ARM_PCS_UNKNOWN: break; @@ -1313,6 +1317,21 @@ aarch64_sve_abi (void) return sve_abi; } +/* Return the descriptor of the Microsoft Arm64 variadic function call ABI. */ + +static const predefined_function_abi & +aarch64_ms_variadic_abi (void) +{ + predefined_function_abi &ms_variadic_abi = function_abis[ARM_PCS_MS_VARIADIC]; + if (!ms_variadic_abi.initialized_p ()) + { + HARD_REG_SET full_reg_clobbers + = default_function_abi.full_reg_clobbers (); + ms_variadic_abi.initialize (ARM_PCS_MS_VARIADIC, full_reg_clobbers); + } + return ms_variadic_abi; +} + /* If X is an UNSPEC_SALT_ADDR expression, return the address that it wraps, otherwise return X itself. */ @@ -2300,11 +2319,37 @@ aarch64_takes_arguments_in_sve_regs_p (const_tree fntype) return false; } +/* Return true if a function has variadic arguments. */ + +static bool +is_variadic_function_type (const_tree fntype) { + if (TYPE_NO_NAMED_ARGS_STDARG_P (fntype)) + return true; + + int arg_count = 0; + for (tree arg = TYPE_ARG_TYPES (fntype); arg; arg = TREE_CHAIN (arg)) + { + if (TREE_VALUE (arg) == void_type_node) + return false; + arg_count++; + } + + return arg_count > 0; +} + /* Implement TARGET_FNTYPE_ABI. */ static const predefined_function_abi & aarch64_fntype_abi (const_tree fntype) { +#if defined(TARGET_AARCH64_MS_ABI) + if (is_variadic_function_type (fntype)) + return aarch64_ms_variadic_abi (); +#endif + + if (lookup_attribute ("ms_abi", TYPE_ATTRIBUTES (fntype))) + return aarch64_ms_variadic_abi (); + if (lookup_attribute ("aarch64_vector_pcs", TYPE_ATTRIBUTES (fntype))) return aarch64_simd_abi (); @@ -2519,6 +2564,10 @@ aarch64_reg_save_mode (unsigned int regno) /* Only the low 64 bits are saved by the base PCS. */ return DFmode; + case ARM_PCS_MS_VARIADIC: + /* Microsoft only uses GP registers for variadic arguments. */ + return DImode; + case ARM_PCS_SIMD: /* The vector PCS saves the low 128 bits (which is the full register on non-SVE targets). */ @@ -7220,6 +7269,86 @@ bitint_or_aggr_of_bitint_p (tree type) return false; } +static int +aarch64_arg_size (const function_arg_info &arg) +{ + HOST_WIDE_INT size; + + /* Size in bytes, rounded to the nearest multiple of 8 bytes. */ + if (arg.type) + size = int_size_in_bytes (arg.type); + else + /* No frontends can create types with variable-sized modes, so we + shouldn't be asked to pass or return them. */ + size = GET_MODE_SIZE (arg.mode).to_constant (); + + return ROUND_UP (size, UNITS_PER_WORD); +} + +/* Layout a function argument according to the AAPCS64 rules. The rule + numbers refer to the rule numbers in the AAPCS64. The Microsoft Arm64 + variadic function call ABI uses only C.12-C15 rules. + See: https://learn.microsoft.com/en-us/cpp/build/arm64-windows-abi-conventions?view=msvc-170#addendum-variadic-functions */ + +static void +aarch64_ms_variadic_abi_layout_arg (cumulative_args_t pcum_v, + const function_arg_info &arg) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); + tree type = arg.type; + machine_mode mode = arg.mode; + int ncrn, nregs; + HOST_WIDE_INT size; + + size = aarch64_arg_size (arg); + ncrn = pcum->aapcs_ncrn; + nregs = size / UNITS_PER_WORD; + + if (ncrn < NUM_ARG_REGS) + { + /* The argument bytes are copied to the core registers. */ + if (nregs == 1 || GET_MODE_CLASS (mode) == MODE_INT) + { + pcum->aapcs_reg = gen_rtx_REG (mode, R0_REGNUM + ncrn); + } + else + { + rtx par; + int i; + + /* Handle the case when argument is split between the last registers + and the stack. */ + if (ncrn + nregs > NUM_ARG_REGS) { + pcum->aapcs_stack_words = ncrn + nregs - NUM_ARG_REGS; + nregs -= pcum->aapcs_stack_words; + } + + /* Generate load arg to registers intructions. */ + par = gen_rtx_PARALLEL (mode, rtvec_alloc (nregs)); + for (i = 0; i < nregs; i++) + { + rtx tmp = gen_rtx_REG (word_mode, R0_REGNUM + ncrn + i); + tmp = gen_rtx_EXPR_LIST (VOIDmode, tmp, + GEN_INT (i * UNITS_PER_WORD)); + XVECEXP (par, 0, i) = tmp; + } + pcum->aapcs_reg = par; + } + + pcum->aapcs_nextncrn = ncrn + nregs; + } + else + { + /* The remaining arguments are passed on stack; record the needed + number of words for this argument and align the total size if + necessary. */ + pcum->aapcs_nextncrn = NUM_ARG_REGS; + pcum->aapcs_stack_words = nregs; + } + + pcum->aapcs_arg_processed = true; +} + /* Layout a function argument according to the AAPCS64 rules. The rule numbers refer to the rule numbers in the AAPCS64. ORIG_MODE is the mode that was originally given to us by the target hook, whereas the @@ -7243,6 +7372,11 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) if (pcum->aapcs_arg_processed) return; + if (pcum->pcs_variant == ARM_PCS_MS_VARIADIC) { + aarch64_ms_variadic_abi_layout_arg (pcum_v, arg); + return; + } + bool warn_pcs_change = (warn_psabi && !pcum->silent_p @@ -7359,15 +7493,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) && (aarch64_some_values_include_pst_objects_p (type) || (vec_flags & VEC_PARTIAL))); - /* Size in bytes, rounded to the nearest multiple of 8 bytes. */ - if (type) - size = int_size_in_bytes (type); - else - /* 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 (); - size = ROUND_UP (size, UNITS_PER_WORD); - + size = aarch64_arg_size (arg); allocate_ncrn = (type) ? !(FLOAT_TYPE_P (type)) : !FLOAT_MODE_P (mode); allocate_nvrn = aarch64_vfp_is_call_candidate (pcum_v, mode, @@ -7600,6 +7726,25 @@ aarch64_finish_sme_mode_switch_args (CUMULATIVE_ARGS *pcum) return gen_rtx_PARALLEL (VOIDmode, argvec); } +/* Implement TARGET_ARG_PARTIAL_BYTES. */ + +static int +aarch64_arg_partial_bytes (cumulative_args_t pcum_v, + const function_arg_info &arg) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); + + if (pcum->pcs_variant != ARM_PCS_MS_VARIADIC) + return 0; + + /* Handle the case when argument is split between the last registers and + the stack. */ + if ((pcum->aapcs_reg != NULL_RTX) && (pcum->aapcs_stack_words != 0)) + return pcum->aapcs_stack_words * UNITS_PER_WORD; + + return 0; +} + /* Implement TARGET_FUNCTION_ARG. */ static rtx @@ -7608,7 +7753,8 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg) CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); gcc_assert (pcum->pcs_variant == ARM_PCS_AAPCS64 || pcum->pcs_variant == ARM_PCS_SIMD - || pcum->pcs_variant == ARM_PCS_SVE); + || pcum->pcs_variant == ARM_PCS_SVE + || pcum->pcs_variant == ARM_PCS_MS_VARIADIC); if (arg.end_marker_p ()) { @@ -7700,11 +7846,13 @@ aarch64_function_arg_advance (cumulative_args_t pcum_v, CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); if (pcum->pcs_variant == ARM_PCS_AAPCS64 || pcum->pcs_variant == ARM_PCS_SIMD - || pcum->pcs_variant == ARM_PCS_SVE) + || pcum->pcs_variant == ARM_PCS_SVE + || pcum->pcs_variant == ARM_PCS_MS_VARIADIC) { aarch64_layout_arg (pcum_v, arg); - gcc_assert ((pcum->aapcs_reg != NULL_RTX) - != (pcum->aapcs_stack_words != 0)); + gcc_assert ((pcum->pcs_variant == ARM_PCS_MS_VARIADIC) + || (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); @@ -21671,6 +21819,21 @@ aarch64_build_builtin_va_list (void) return va_list_type; } +/* Setup the builtin va_list data type and for 64-bit the additional + calling convention specific va_list data types. */ + +static tree +aarch64_ms_variadic_abi_build_builtin_va_list (void) +{ + /* For MS_ABI we use plain pointer to argument area. */ + tree char_ptr_type = build_pointer_type (char_type_node); + tree attr = tree_cons (get_identifier ("ms_abi va_list"), NULL_TREE, + TYPE_ATTRIBUTES (char_ptr_type)); + ms_va_list_type_node = build_type_attribute_variant (char_ptr_type, attr); + + return ms_va_list_type_node; +} + /* Implement TARGET_EXPAND_BUILTIN_VA_START. */ static void aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) @@ -21754,6 +21917,75 @@ aarch64_expand_builtin_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED) expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL); } +/* Implement TARGET_EXPAND_BUILTIN_VA_START. */ + +static void +aarch64_ms_variadic_abi_expand_builtin_va_start (tree valist, rtx nextarg) +{ + rtx va_r = expand_expr (valist, NULL_RTX, VOIDmode, EXPAND_WRITE); + + /* TODO: Should we initialize and use cfun->va_list_gpr_size instead of + defining single purpose + cfun->machine->frame.unaligned_saved_varargs_size field? + Currently, the cfun->va_list_gpr_size contains only value 255? */ + int offset = cfun->machine->frame.unaligned_saved_varargs_size; + nextarg = plus_constant (GET_MODE (nextarg), nextarg, -offset); + + convert_move (va_r, nextarg, 0); +} + +/* Iterate through the target-specific builtin types for va_list. + IDX denotes the iterator, *PTREE is set to the result type of + the va_list builtin, and *PNAME to its internal type. + Returns zero if there is no element for this index, otherwise + IDX should be increased upon the next call. + Note, do not iterate a base builtin's name like __builtin_va_list. + Used from c_common_nodes_and_builtins. */ + +static int +aarch64_ms_variadic_abi_enum_va_list (int idx, const char **pname, tree *ptree) +{ + switch (idx) + { + default: + break; + + case 0: + *ptree = ms_va_list_type_node; + *pname = "__builtin_ms_va_list"; + return 1; + } + + return 0; +} + +/* This function returns the calling abi specific va_list type node. + It returns the FNDECL specific va_list type. */ + +static tree +aarch64_ms_variadic_abi_fn_abi_va_list (tree fndecl) +{ + gcc_assert (fndecl != NULL_TREE); + + arm_pcs pcs = (arm_pcs) fndecl_abi (fndecl).id (); + if (pcs == ARM_PCS_MS_VARIADIC) + return ms_va_list_type_node; + + return std_fn_abi_va_list (fndecl); +} + +/* Returns the canonical va_list type specified by TYPE. If there + is no valid TYPE provided, it return NULL_TREE. */ + +static tree +aarch64_ms_variadic_abi_canonical_va_list_type (tree type) +{ + if (lookup_attribute ("ms_abi va_list", TYPE_ATTRIBUTES (type))) + return ms_va_list_type_node; + + return NULL_TREE; +} + /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. */ static tree @@ -22077,7 +22309,10 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v, vr_saved = MIN (NUM_FP_ARG_REGS - local_cum.aapcs_nvrn, cfun->va_list_fpr_size / UNITS_PER_VREG); + /* Microsoft variadic function calls ABI never uses vector registers. */ +#if !defined (TARGET_AARCH64_MS_ABI) if (!TARGET_FLOAT) +#endif { gcc_assert (local_cum.aapcs_nvrn == 0); vr_saved = 0; @@ -22128,8 +22363,9 @@ aarch64_setup_incoming_varargs (cumulative_args_t cum_v, /* We don't save the size into *PRETEND_SIZE because we want to avoid any complication of having crtl->args.pretend_args_size changed. */ + cfun->machine->frame.unaligned_saved_varargs_size = gr_saved * UNITS_PER_WORD; cfun->machine->frame.saved_varargs_size - = (ROUND_UP (gr_saved * UNITS_PER_WORD, + = (ROUND_UP (cfun->machine->frame.unaligned_saved_varargs_size, STACK_BOUNDARY / BITS_PER_UNIT) + vr_saved * UNITS_PER_VREG); } @@ -22922,9 +23158,13 @@ static const char * aarch64_mangle_type (const_tree type) { /* The AArch64 ABI documents say that "__va_list" has to be - mangled as if it is in the "std" namespace. */ + mangled as if it is in the "std" namespace. + The Windows Arm64 ABI uses just an address of the first variadic + argument. */ +#if !defined (TARGET_AARCH64_MS_ABI) if (lang_hooks.types_compatible_p (CONST_CAST_TREE (type), va_list_type)) return "St9__va_list"; +#endif /* Half-precision floating point types. */ if (SCALAR_FLOAT_TYPE_P (type) && TYPE_PRECISION (type) == 16) @@ -25550,6 +25790,25 @@ aarch64_post_cfi_startproc (FILE *f, tree ignored ATTRIBUTE_UNUSED) asm_fprintf (f, "\t.cfi_b_key_frame\n"); } +/* Implement TARGET_STRICT_ARGUMENT_NAMING. + + Return true if the location where a function argument is passed + depends on whether or not it is a named argument. + + For Microsoft ABI of variadic function calls, treat the named arguments as + unnamed as they are handled the same way as variadic arguments. */ + +static bool +aarch64_ms_variadic_abi_strict_argument_naming (cumulative_args_t pcum_v) +{ + CUMULATIVE_ARGS *pcum = get_cumulative_args (pcum_v); + + if (pcum->pcs_variant == ARM_PCS_MS_VARIADIC) + return false; + + return hook_bool_CUMULATIVE_ARGS_true(pcum_v); +} + /* Implements TARGET_ASM_FILE_START. Output the assembly header. */ static void @@ -32095,8 +32354,13 @@ aarch64_run_selftests (void) #undef TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY #define TARGET_ASM_PRINT_PATCHABLE_FUNCTION_ENTRY aarch64_print_patchable_function_entry +#if defined (TARGET_AARCH64_MS_ABI) +#undef TARGET_BUILD_BUILTIN_VA_LIST +#define TARGET_BUILD_BUILTIN_VA_LIST aarch64_ms_variadic_abi_build_builtin_va_list +#else #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST aarch64_build_builtin_va_list +#endif #undef TARGET_CALLEE_COPIES #define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_arg_info_false @@ -32166,12 +32430,31 @@ aarch64_run_selftests (void) #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN aarch64_expand_builtin +#if defined (TARGET_AARCH64_MS_ABI) +#undef TARGET_ENUM_VA_LIST_P +#define TARGET_ENUM_VA_LIST_P aarch64_ms_variadic_abi_enum_va_list + +#undef TARGET_FN_ABI_VA_LIST +#define TARGET_FN_ABI_VA_LIST aarch64_ms_variadic_abi_fn_abi_va_list + +#undef TARGET_CANONICAL_VA_LIST_TYPE +#define TARGET_CANONICAL_VA_LIST_TYPE aarch64_ms_variadic_abi_canonical_va_list_type + +#undef TARGET_EXPAND_BUILTIN_VA_START +#define TARGET_EXPAND_BUILTIN_VA_START aarch64_ms_variadic_abi_expand_builtin_va_start +#else #undef TARGET_EXPAND_BUILTIN_VA_START #define TARGET_EXPAND_BUILTIN_VA_START aarch64_expand_builtin_va_start +#endif #undef TARGET_FOLD_BUILTIN #define TARGET_FOLD_BUILTIN aarch64_fold_builtin +#if defined (TARGET_AARCH64_MS_ABI) +#undef TARGET_ARG_PARTIAL_BYTES +#define TARGET_ARG_PARTIAL_BYTES aarch64_arg_partial_bytes +#endif + #undef TARGET_FUNCTION_ARG #define TARGET_FUNCTION_ARG aarch64_function_arg @@ -32207,8 +32490,10 @@ aarch64_run_selftests (void) #undef TARGET_GIMPLE_FOLD_BUILTIN #define TARGET_GIMPLE_FOLD_BUILTIN aarch64_gimple_fold_builtin +#if !defined (TARGET_AARCH64_MS_ABI) #undef TARGET_GIMPLIFY_VA_ARG_EXPR #define TARGET_GIMPLIFY_VA_ARG_EXPR aarch64_gimplify_va_arg_expr +#endif #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS aarch64_init_builtins diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 096c853af7f..c1b858563fb 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -1003,6 +1003,9 @@ struct GTY (()) aarch64_frame STACK_BOUNDARY. */ HOST_WIDE_INT saved_varargs_size; + /* The same as above except it is the original unaligned stack size. */ + HOST_WIDE_INT unaligned_saved_varargs_size; + /* The number of bytes between the bottom of the static frame (the bottom of the outgoing arguments) and the bottom of the register save area. This value is always a multiple of STACK_BOUNDARY. */ @@ -1166,6 +1169,10 @@ enum arm_pcs ARM_PCS_SVE, /* For functions that pass or return values in SVE registers. */ ARM_PCS_TLSDESC, /* For targets of tlsdesc calls. */ + ARM_PCS_MS_VARIADIC, /* Microsoft handles variadic functions + differently. All composites are treated + alike. SIMD and floating-point registers + aren't used. */ ARM_PCS_UNKNOWN }; @@ -1549,6 +1556,9 @@ extern GTY(()) tree aarch64_fp16_ptr_type_node; bfloat16_type_node. Defined in aarch64-builtins.cc. */ extern GTY(()) tree aarch64_bf16_ptr_type_node; +/* Microsoft Arm64 variadic function call ABI specific va_list type node. */ +extern GTY(()) tree ms_va_list_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/cross-stdarg.h b/gcc/config/aarch64/cross-stdarg.h new file mode 100644 index 00000000000..573e856998f --- /dev/null +++ b/gcc/config/aarch64/cross-stdarg.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2025 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef __CROSS_STDARG_H_INCLUDED +#define __CROSS_STDARG_H_INCLUDED + +#define __ms_va_copy(__d,__s) __builtin_ms_va_copy(__d,__s) +#define __ms_va_start(__v,__l) __builtin_ms_va_start(__v,__l) +#define __ms_va_arg(__v,__l) __builtin_va_arg(__v,__l) +#define __ms_va_end(__v) __builtin_ms_va_end(__v) + +#ifndef __GNUC_MS_VA_LIST +#define __GNUC_MS_VA_LIST +typedef __builtin_ms_va_list __gnuc_ms_va_list; +#endif + +#ifndef _MS_VA_LIST_DEFINED +#define _MS_VA_LIST_DEFINED +typedef __gnuc_ms_va_list ms_va_list; +#endif + +#endif /* __CROSS_STDARG_H_INCLUDED */ diff --git a/gcc/config/aarch64/cygming.h b/gcc/config/aarch64/cygming.h index 7e2203c3e92..aa580f4be27 100644 --- a/gcc/config/aarch64/cygming.h +++ b/gcc/config/aarch64/cygming.h @@ -204,8 +204,11 @@ still needed for compilation. */ } while (0) #define SUBTARGET_ATTRIBUTE_TABLE \ - { "selectany", 0, 0, true, false, false, false, \ - mingw_handle_selectany_attribute, NULL } + { "selectany", 0, 0, true, false, false, false, \ + mingw_handle_selectany_attribute, NULL }, \ + { "ms_abi", 0, 0, false, true, true, true, \ + aarch64_handle_ms_abi_attribute, NULL }, \ + { "ms_abi va_list", 0, 0, false, false, false, false, NULL, NULL } #undef SUB_TARGET_RECORD_STUB #define SUB_TARGET_RECORD_STUB(NAME, DECL) mingw_pe_record_stub((NAME), \ @@ -252,3 +255,9 @@ still needed for compilation. */ #define TARGET_ASM_LTO_END mingw_pe_asm_lto_end #endif + +#undef SUBTARGET_INIT_BUILTINS +#define SUBTARGET_INIT_BUILTINS \ + do { \ + aarch64_ms_variadic_abi_init_builtins (); \ + } while(0) diff --git a/gcc/config/mingw/winnt.cc b/gcc/config/mingw/winnt.cc index f22496615ed..fc85425d1a2 100644 --- a/gcc/config/mingw/winnt.cc +++ b/gcc/config/mingw/winnt.cc @@ -94,6 +94,28 @@ mingw_handle_selectany_attribute (tree *node, tree name, tree, int, return NULL_TREE; } +/* Handle a "ms_abi" attribute; arguments as in struct + attribute_spec.handler. */ + +tree +aarch64_handle_ms_abi_attribute (tree *node, tree name, tree, int, + bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_TYPE + && TREE_CODE (*node) != METHOD_TYPE + && TREE_CODE (*node) != FIELD_DECL + && TREE_CODE (*node) != TYPE_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + + return NULL_TREE; + } + + return NULL_TREE; +} + /* Return the type that we should use to determine if DECL is imported or exported. */ diff --git a/gcc/config/mingw/winnt.h b/gcc/config/mingw/winnt.h index 23f4dc94ec5..5ef11c14ec0 100644 --- a/gcc/config/mingw/winnt.h +++ b/gcc/config/mingw/winnt.h @@ -21,6 +21,7 @@ http://www.gnu.org/licenses/. */ #ifndef USED_FOR_TARGET extern tree mingw_handle_selectany_attribute (tree *, tree, tree, int, bool *); +extern tree aarch64_handle_ms_abi_attribute (tree *, tree, tree, int, bool *); extern void mingw_pe_asm_named_section (const char *, unsigned int, tree); extern void mingw_pe_asm_lto_start (void); -- 2.50.1.vfs.0.0
0001-Fix-function-call-handling-according-to-Microsoft-Arm64-variadic-function-call-ABI.patch
Description: 0001-Fix-function-call-handling-according-to-Microsoft-Arm64-variadic-function-call-ABI.patch