From patchwork Wed May 3 16:48:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1776589 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=ckhWonGo; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QBNFJ5rFkz1ydV for ; Thu, 4 May 2023 02:48:51 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 092CD38582BD for ; Wed, 3 May 2023 16:48:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 092CD38582BD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1683132529; bh=ggvhsl5UlpQseEk7XWicTDdaJ+L3O9Dp02bUb/ryAVA=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=ckhWonGo9HEqLwb7IglofUAlI79aKXfcXRXvJvSkHjzCSDm/TVUmuJX+FAcEGfMUi aUADqhR59WQICKmsAOSXEvof7H2aiZiA2af8fRln5Y8Q/cOiOGSb6CXCrtTkdlNEOV q9GsZj/WJ0OcI/NH7/1q0yg8W+nBSZ3h/DLZ0i1U= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 35CC73858C50 for ; Wed, 3 May 2023 16:48:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 35CC73858C50 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 087F12F4 for ; Wed, 3 May 2023 09:49:11 -0700 (PDT) Received: from localhost (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 6BBF03F64C for ; Wed, 3 May 2023 09:48:26 -0700 (PDT) To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [PATCH 1/2] aarch64: Rename abi_break parameters [PR109661] Date: Wed, 03 May 2023 17:48:25 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-30.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Richard Sandiford via Gcc-patches From: Richard Sandiford Reply-To: Richard Sandiford Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" aarch64_function_arg_alignment has two related abi_break parameters: abi_break for a change in GCC 9, and abi_break_packed for a related follow-on change in GCC 13. In a sense, abi_break_packed is a "subfix" of abi_break. PR109661 now requires a third ABI break that is independent of the other two. Having abi_break for the GCC 9 break and abi_break_ for the GCC 13 and GCC 14 breaks might give the impression that they're all related, and that the GCC 14 fix (like the GCC 13 fix) is a "subfix" of the GCC 9 one. It therefore seemed like a good idea to rename the existing variables first. It would be difficult to choose names that describe briefly and precisely what went wrong in each case. The next best thing seemed to be to name them after the relevant GCC version. (Of course, this might break down in future if we need two independent fixes in the same version. Let's hope not.) I wondered about putting all the variables in a structure, but one advantage of using independent variables is that it's harder to forget to update a caller. Maybe a fourth parameter would be a tipping point. Tested on aarch64-linux-gnu & pushed. Richard gcc/ PR target/109661 * config/aarch64/aarch64.cc (aarch64_function_arg_alignment): Rename ABI break variables to abi_break_gcc_9 and abi_break_gcc_13. (aarch64_layout_arg, aarch64_function_arg_boundary): Likewise. (aarch64_gimplify_va_arg_expr): Likewise. --- gcc/config/aarch64/aarch64.cc | 70 ++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 2b0de7ca038..70916ad63d2 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -7464,19 +7464,20 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, /* Given MODE and TYPE of a function argument, return the alignment in bits. The idea is to suppress any stronger alignment requested by the user and opt for the natural alignment (specified in AAPCS64 \S - 4.1). ABI_BREAK is set to the old alignment if the alignment was - incorrectly calculated in versions of GCC prior to GCC-9. - ABI_BREAK_PACKED is set to the old alignment if it was incorrectly - calculated in versions between GCC-9 and GCC-13. This is a helper - function for local use only. */ + 4.1). ABI_BREAK_GCC_9 is set to the old alignment if the alignment + was incorrectly calculated in versions of GCC prior to GCC 9. + ABI_BREAK_GCC_13 is set to the old alignment if it was incorrectly + calculated in versions between GCC 9 and GCC 13. + + This is a helper function for local use only. */ static unsigned int aarch64_function_arg_alignment (machine_mode mode, const_tree type, - unsigned int *abi_break, - unsigned int *abi_break_packed) + unsigned int *abi_break_gcc_9, + unsigned int *abi_break_gcc_13) { - *abi_break = 0; - *abi_break_packed = 0; + *abi_break_gcc_9 = 0; + *abi_break_gcc_13 = 0; if (!type) return GET_MODE_ALIGNMENT (mode); @@ -7547,11 +7548,11 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type, 'packed' attribute into account. */ if (bitfield_alignment != bitfield_alignment_with_packed && bitfield_alignment_with_packed > alignment) - *abi_break_packed = bitfield_alignment_with_packed; + *abi_break_gcc_13 = bitfield_alignment_with_packed; if (bitfield_alignment > alignment) { - *abi_break = alignment; + *abi_break_gcc_9 = alignment; return bitfield_alignment; } @@ -7573,8 +7574,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) int ncrn, nvrn, nregs; bool allocate_ncrn, allocate_nvrn; HOST_WIDE_INT size; - unsigned int abi_break; - unsigned int abi_break_packed; + unsigned int abi_break_gcc_9; + unsigned int abi_break_gcc_13; /* We need to do this once per argument. */ if (pcum->aapcs_arg_processed) @@ -7612,7 +7613,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) Versions prior to GCC 9.1 ignored a bitfield's underlying type and so could calculate an alignment that was too small. If this - happened for TYPE then ABI_BREAK is this older, too-small alignment. + happened for TYPE then ABI_BREAK_GCC_9 is this older, too-small alignment. Although GCC 9.1 fixed that bug, it introduced a different one: it would consider the alignment of a bitfield's underlying type even @@ -7620,7 +7621,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) the alignment of the underlying type). This was fixed in GCC 13.1. As a result of this bug, GCC 9 to GCC 12 could calculate an alignment - that was too big. If this happened for TYPE, ABI_BREAK_PACKED is + that was too big. If this happened for TYPE, ABI_BREAK_GCC_13 is this older, too-big alignment. Also, the fact that GCC 9 to GCC 12 considered irrelevant @@ -7713,12 +7714,12 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) gcc_assert (!sve_p || !allocate_nvrn); unsigned int alignment - = aarch64_function_arg_alignment (mode, type, &abi_break, - &abi_break_packed); + = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, + &abi_break_gcc_13); gcc_assert ((allocate_nvrn || alignment <= 16 * BITS_PER_UNIT) - && (!alignment || abi_break < alignment) - && (!abi_break_packed || alignment < abi_break_packed)); + && (!alignment || abi_break_gcc_9 < alignment) + && (!abi_break_gcc_13 || alignment < abi_break_gcc_13)); /* allocate_ncrn may be false-positive, but allocate_nvrn is quite reliable. The following code thus handles passing by SIMD/FP registers first. */ @@ -7792,8 +7793,8 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) /* Emit a warning if the alignment changed when taking the 'packed' attribute into account. */ if (warn_pcs_change - && abi_break_packed - && ((abi_break_packed == 16 * BITS_PER_UNIT) + && abi_break_gcc_13 + && ((abi_break_gcc_13 == 16 * BITS_PER_UNIT) != (alignment == 16 * BITS_PER_UNIT))) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); @@ -7804,7 +7805,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) passed by reference rather than value. */ if (alignment == 16 * BITS_PER_UNIT) { - if (warn_pcs_change && abi_break) + if (warn_pcs_change && abi_break_gcc_9) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 9.1", type); ++ncrn; @@ -7863,8 +7864,8 @@ on_stack: pcum->aapcs_stack_words = size / UNITS_PER_WORD; if (warn_pcs_change - && abi_break_packed - && ((abi_break_packed >= 16 * BITS_PER_UNIT) + && abi_break_gcc_13 + && ((abi_break_gcc_13 >= 16 * BITS_PER_UNIT) != (alignment >= 16 * BITS_PER_UNIT))) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); @@ -7874,7 +7875,7 @@ on_stack: int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); if (pcum->aapcs_stack_size != new_size) { - if (warn_pcs_change && abi_break) + if (warn_pcs_change && abi_break_gcc_9) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 9.1", type); pcum->aapcs_stack_size = new_size; @@ -7991,11 +7992,11 @@ aarch64_function_arg_regno_p (unsigned regno) static unsigned int aarch64_function_arg_boundary (machine_mode mode, const_tree type) { - unsigned int abi_break; - unsigned int abi_break_packed; + unsigned int abi_break_gcc_9; + unsigned int abi_break_gcc_13; unsigned int alignment = aarch64_function_arg_alignment (mode, type, - &abi_break, - &abi_break_packed); + &abi_break_gcc_9, + &abi_break_gcc_13); /* We rely on aarch64_layout_arg and aarch64_gimplify_va_arg_expr to emit warnings about ABI incompatibility. */ alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); @@ -19762,10 +19763,11 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, f_stack, NULL_TREE); size = int_size_in_bytes (type); - unsigned int abi_break; - unsigned int abi_break_packed; + unsigned int abi_break_gcc_9; + unsigned int abi_break_gcc_13; align - = aarch64_function_arg_alignment (mode, type, &abi_break, &abi_break_packed) + = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, + &abi_break_gcc_13) / BITS_PER_UNIT; dw_align = false; @@ -19809,13 +19811,13 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, rsize = ROUND_UP (size, UNITS_PER_WORD); nregs = rsize / UNITS_PER_WORD; - if (align <= 8 && abi_break_packed && warn_psabi) + if (align <= 8 && abi_break_gcc_13 && warn_psabi) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); if (align > 8) { - if (abi_break && warn_psabi) + if (abi_break_gcc_9 && warn_psabi) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 9.1", type); dw_align = true; From patchwork Wed May 3 16:48:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1776590 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=qk07nb0Y; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4QBNFn4d9Jz1ydV for ; Thu, 4 May 2023 02:49:17 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 948133857734 for ; Wed, 3 May 2023 16:49:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 948133857734 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1683132555; bh=ofMcbhUHqWSetI9QGSz9AXrnQY7YSu4oQz6hSUTUhHM=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=qk07nb0YrP1CohM9jDtt+lDDawQnAwBQjEbbYSbmV7Ml7NC/HK7uqppWfd7Hg5KwU Kbvsh912wKZOY9lHWsCnGONXSicZ0bdQdRGOsIWPMyIPozbLkQaYGhcuibM4yMga/X wkE2hXRYU5Xjl0zSWyQ+dJqLktg2grDpBZLJb9No= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 9EFC03857712 for ; Wed, 3 May 2023 16:48:51 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 9EFC03857712 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 908AF2F4 for ; Wed, 3 May 2023 09:49:35 -0700 (PDT) Received: from localhost (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id BCEF73F64C for ; Wed, 3 May 2023 09:48:50 -0700 (PDT) To: gcc-patches@gcc.gnu.org Mail-Followup-To: gcc-patches@gcc.gnu.org, richard.sandiford@arm.com Subject: [PATCH 2/2] aarch64: Fix ABI handling of aligned enums [PR109661] Date: Wed, 03 May 2023 17:48:49 +0100 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.3 (gnu/linux) MIME-Version: 1.0 X-Spam-Status: No, score=-30.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Richard Sandiford via Gcc-patches From: Richard Sandiford Reply-To: Richard Sandiford Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" aarch64_function_arg_alignment has traditionally taken the alignment of a scalar type T from TYPE_ALIGN (TYPE_MAIN_VARIANT (T)). This is supposed to discard any user alignment and give the alignment of the underlying fundamental type. PR109661 shows that this did the wrong thing for enums with a defined underlying type, because: (1) The enum itself could be aligned, using attributes. (2) The enum would pick up any user alignment on the underlying type. We get the right behaviour if we look at the TYPE_MAIN_VARIANT of the underlying type instead. As always, this affects register and stack arguments differently, because: (a) The code that handles register arguments only considers the alignment of types that occupy two registers, whereas the stack alignment is applied regardless of size. (b) The code that handles register arguments tests the alignment for equality with 16 bytes, so that (unexpected) greater alignments are ignored. The code that handles stack arguments instead caps the alignment to 16 bytes. There is now (since GCC 13) an assert to trap the difference between (a) and (b), which is how the new incompatiblity showed up. Clang alredy handled the testcases correctly, so this patch aligns the GCC behaviour with the Clang behaviour. I'm planning to remove the asserts on the branches, since we don't want to change the ABI there. Tested on aarch64-linux-gnu & pushed. Richard gcc/ PR target/109661 * config/aarch64/aarch64.cc (aarch64_function_arg_alignment): Add a new ABI break parameter for GCC 14. Set it to the alignment of enums that have an underlying type. Take the true alignment of such enums from the TYPE_ALIGN of the underlying type's TYPE_MAIN_VARIANT. (aarch64_function_arg_boundary): Update accordingly. (aarch64_layout_arg, aarch64_gimplify_va_arg_expr): Likewise. Warn about ABI differences. gcc/testsuite/ * g++.target/aarch64/pr109661-1.C: New test. * g++.target/aarch64/pr109661-2.C: Likewise. * g++.target/aarch64/pr109661-3.C: Likewise. * g++.target/aarch64/pr109661-4.C: Likewise. * gcc.target/aarch64/pr109661-1.c: Likewise. --- gcc/config/aarch64/aarch64.cc | 43 ++- gcc/testsuite/g++.target/aarch64/pr109661-1.C | 253 ++++++++++++++++++ gcc/testsuite/g++.target/aarch64/pr109661-2.C | 253 ++++++++++++++++++ gcc/testsuite/g++.target/aarch64/pr109661-3.C | 253 ++++++++++++++++++ gcc/testsuite/g++.target/aarch64/pr109661-4.C | 253 ++++++++++++++++++ gcc/testsuite/gcc.target/aarch64/pr109661-1.c | 11 + 6 files changed, 1061 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.target/aarch64/pr109661-1.C create mode 100644 gcc/testsuite/g++.target/aarch64/pr109661-2.C create mode 100644 gcc/testsuite/g++.target/aarch64/pr109661-3.C create mode 100644 gcc/testsuite/g++.target/aarch64/pr109661-4.C create mode 100644 gcc/testsuite/gcc.target/aarch64/pr109661-1.c diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 70916ad63d2..546cb121331 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -7467,17 +7467,21 @@ aarch64_vfp_is_call_candidate (cumulative_args_t pcum_v, machine_mode mode, 4.1). ABI_BREAK_GCC_9 is set to the old alignment if the alignment was incorrectly calculated in versions of GCC prior to GCC 9. ABI_BREAK_GCC_13 is set to the old alignment if it was incorrectly - calculated in versions between GCC 9 and GCC 13. + calculated in versions between GCC 9 and GCC 13. If the alignment + might have changed between GCC 13 and GCC 14, ABI_BREAK_GCC_14 + is the old GCC 13 alignment, otherwise it is zero. This is a helper function for local use only. */ static unsigned int aarch64_function_arg_alignment (machine_mode mode, const_tree type, unsigned int *abi_break_gcc_9, - unsigned int *abi_break_gcc_13) + unsigned int *abi_break_gcc_13, + unsigned int *abi_break_gcc_14) { *abi_break_gcc_9 = 0; *abi_break_gcc_13 = 0; + *abi_break_gcc_14 = 0; if (!type) return GET_MODE_ALIGNMENT (mode); @@ -7498,6 +7502,11 @@ aarch64_function_arg_alignment (machine_mode mode, const_tree type, gcc_assert (known_eq (POINTER_SIZE, GET_MODE_BITSIZE (mode))); return POINTER_SIZE; } + if (TREE_CODE (type) == ENUMERAL_TYPE && TREE_TYPE (type)) + { + *abi_break_gcc_14 = TYPE_ALIGN (type); + type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); + } gcc_assert (!TYPE_USER_ALIGN (type)); return TYPE_ALIGN (type); } @@ -7576,6 +7585,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) HOST_WIDE_INT size; unsigned int abi_break_gcc_9; unsigned int abi_break_gcc_13; + unsigned int abi_break_gcc_14; /* We need to do this once per argument. */ if (pcum->aapcs_arg_processed) @@ -7715,7 +7725,7 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) unsigned int alignment = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, - &abi_break_gcc_13); + &abi_break_gcc_13, &abi_break_gcc_14); gcc_assert ((allocate_nvrn || alignment <= 16 * BITS_PER_UNIT) && (!alignment || abi_break_gcc_9 < alignment) @@ -7799,6 +7809,13 @@ aarch64_layout_arg (cumulative_args_t pcum_v, const function_arg_info &arg) inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); + if (warn_pcs_change + && abi_break_gcc_14 + && ((abi_break_gcc_14 == 16 * BITS_PER_UNIT) + != (alignment == 16 * BITS_PER_UNIT))) + inform (input_location, "parameter passing for argument of type " + "%qT changed in GCC 14.1", type); + /* The == 16 * BITS_PER_UNIT instead of >= 16 * BITS_PER_UNIT comparison is there because for > 16 * BITS_PER_UNIT alignment nregs should be > 2 and therefore it should be @@ -7870,6 +7887,13 @@ on_stack: inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); + if (warn_pcs_change + && abi_break_gcc_14 + && ((abi_break_gcc_14 >= 16 * BITS_PER_UNIT) + != (alignment >= 16 * BITS_PER_UNIT))) + inform (input_location, "parameter passing for argument of type " + "%qT changed in GCC 14.1", type); + if (alignment == 16 * BITS_PER_UNIT) { int new_size = ROUND_UP (pcum->aapcs_stack_size, 16 / UNITS_PER_WORD); @@ -7994,9 +8018,11 @@ aarch64_function_arg_boundary (machine_mode mode, const_tree type) { 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_13, + &abi_break_gcc_14); /* We rely on aarch64_layout_arg and aarch64_gimplify_va_arg_expr to emit warnings about ABI incompatibility. */ alignment = MIN (MAX (alignment, PARM_BOUNDARY), STACK_BOUNDARY); @@ -19765,9 +19791,10 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, unsigned int abi_break_gcc_9; unsigned int abi_break_gcc_13; + unsigned int abi_break_gcc_14; align = aarch64_function_arg_alignment (mode, type, &abi_break_gcc_9, - &abi_break_gcc_13) + &abi_break_gcc_13, &abi_break_gcc_14) / BITS_PER_UNIT; dw_align = false; @@ -19815,6 +19842,12 @@ aarch64_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, inform (input_location, "parameter passing for argument of type " "%qT changed in GCC 13.1", type); + if (warn_psabi + && abi_break_gcc_14 + && (abi_break_gcc_14 > 8 * BITS_PER_UNIT) != (align > 8)) + inform (input_location, "parameter passing for argument of type " + "%qT changed in GCC 14.1", type); + if (align > 8) { if (abi_break_gcc_9 && warn_psabi) diff --git a/gcc/testsuite/g++.target/aarch64/pr109661-1.C b/gcc/testsuite/g++.target/aarch64/pr109661-1.C new file mode 100644 index 00000000000..d668a544fa7 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr109661-1.C @@ -0,0 +1,253 @@ +/* { dg-options "-O2 -Wpsabi" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +#define ALIGN + +typedef __uint128_t u128_4 __attribute__((aligned(4))); +typedef __uint128_t u128_8 __attribute__((aligned(8))); +typedef __uint128_t u128_16 __attribute__((aligned(16))); +typedef __uint128_t u128_32 __attribute__((aligned(32))); +typedef __uint128_t u128; + +typedef __UINT64_TYPE__ u64_4 __attribute__((aligned(4))); +typedef __UINT64_TYPE__ u64_8 __attribute__((aligned(8))); +typedef __UINT64_TYPE__ u64_16 __attribute__((aligned(16))); +typedef __UINT64_TYPE__ u64_32 __attribute__((aligned(32))); +typedef __UINT64_TYPE__ u64; + +enum class ALIGN e128_4 : u128_4 { A }; +enum class ALIGN e128_8 : u128_8 { A }; +enum class ALIGN e128_16 : u128_16 { A }; +enum class ALIGN e128_32 : u128_32 { A }; +enum class ALIGN e128 : u128 { A }; + +enum class ALIGN e64_4 : u64_4 { A }; +enum class ALIGN e64_8 : u64_8 { A }; +enum class ALIGN e64_16 : u64_16 { A }; +enum class ALIGN e64_32 : u64_32 { A }; +enum class ALIGN e64 : u64 { A }; + +extern "C" { + +/* +** reg_e128_4: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_4 reg_e128_4 (int x, e128_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + +/* +** reg_e128_8: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_8 reg_e128_8 (int x, e128_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + +/* +** reg_e128_16: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_16 reg_e128_16 (int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e128_32: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_32 reg_e128_32 (int x, e128_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + +/* +** reg_e128: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128 reg_e128 (int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_4: +** mov x0, x1 +** ret +*/ +e64_4 reg_e64_4 (int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_8: +** mov x0, x1 +** ret +*/ +e64_8 reg_e64_8 (int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_16: +** mov x0, x1 +** ret +*/ +e64_16 reg_e64_16 (int x, e64_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_32: +** mov x0, x1 +** ret +*/ +e64_32 reg_e64_32 (int x, e64_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64: +** mov x0, x1 +** ret +*/ +e64 reg_e64 (int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_4: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_4 stack_e128_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + +/* +** stack_e128_8: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_8 stack_e128_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + +/* +** stack_e128_16: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_16 stack_e128_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_32: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_32 stack_e128_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128 stack_e128 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_4: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_4 stack_e64_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_8: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_8 stack_e64_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_16: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_16 stack_e64_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_16 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + +/* +** stack_e64_32: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_32 stack_e64_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + +/* +** stack_e64: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64 stack_e64 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +void callee (int n, ...); + +void +caller () +{ + callee (1, e128_4::A); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + callee (1, e128_8::A); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + callee (1, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e128_32::A); /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + callee (1, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (1, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_32::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64::A); /* { dg-bogus {parameter passing} } */ + +#define LOTS 1, 2, 3, 4, 5, 6, 7, 8, 9 + + callee (LOTS, e128_4::A); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + callee (LOTS, e128_8::A); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + callee (LOTS, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_32::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (LOTS, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e64_16::A); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + callee (LOTS, e64_32::A); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + callee (LOTS, e64::A); /* { dg-bogus {parameter passing} } */ +} + +void +va (volatile void *ptr, ...) +{ + va_list ap; + va_start (ap, ptr); + *(volatile e128_4 *) ptr = va_arg (ap, e128_4); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + *(volatile e128_8 *) ptr = va_arg (ap, e128_8); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + *(volatile e128_16 *) ptr = va_arg (ap, e128_16); /* { dg-bogus {parameter passing} } */ + *(volatile e128_32 *) ptr = va_arg (ap, e128_32); /* { dg-bogus {parameter passing} } */ + *(volatile e128 *) ptr = va_arg (ap, e128); /* { dg-bogus {parameter passing} } */ + *(volatile e64_4 *) ptr = va_arg (ap, e64_4); /* { dg-bogus {parameter passing} } */ + *(volatile e64_8 *) ptr = va_arg (ap, e64_8); /* { dg-bogus {parameter passing} } */ + *(volatile e64_16 *) ptr = va_arg (ap, e64_16); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + *(volatile e64_32 *) ptr = va_arg (ap, e64_32); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + *(volatile e64 *) ptr = va_arg (ap, e64); /* { dg-bogus {parameter passing} } */ +} + +} diff --git a/gcc/testsuite/g++.target/aarch64/pr109661-2.C b/gcc/testsuite/g++.target/aarch64/pr109661-2.C new file mode 100644 index 00000000000..f081417da95 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr109661-2.C @@ -0,0 +1,253 @@ +/* { dg-options "-O2 -Wpsabi" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +#define ALIGN __attribute__((aligned(8))) + +typedef __uint128_t u128_4 __attribute__((aligned(4))); +typedef __uint128_t u128_8 __attribute__((aligned(8))); +typedef __uint128_t u128_16 __attribute__((aligned(16))); +typedef __uint128_t u128_32 __attribute__((aligned(32))); +typedef __uint128_t u128; + +typedef __UINT64_TYPE__ u64_4 __attribute__((aligned(4))); +typedef __UINT64_TYPE__ u64_8 __attribute__((aligned(8))); +typedef __UINT64_TYPE__ u64_16 __attribute__((aligned(16))); +typedef __UINT64_TYPE__ u64_32 __attribute__((aligned(32))); +typedef __UINT64_TYPE__ u64; + +enum class ALIGN e128_4 : u128_4 { A }; +enum class ALIGN e128_8 : u128_8 { A }; +enum class ALIGN e128_16 : u128_16 { A }; +enum class ALIGN e128_32 : u128_32 { A }; +enum class ALIGN e128 : u128 { A }; + +enum class ALIGN e64_4 : u64_4 { A }; +enum class ALIGN e64_8 : u64_8 { A }; +enum class ALIGN e64_16 : u64_16 { A }; +enum class ALIGN e64_32 : u64_32 { A }; +enum class ALIGN e64 : u64 { A }; + +extern "C" { + +/* +** reg_e128_4: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_4 reg_e128_4 (int x, e128_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + +/* +** reg_e128_8: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_8 reg_e128_8 (int x, e128_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + +/* +** reg_e128_16: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_16 reg_e128_16 (int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e128_32: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_32 reg_e128_32 (int x, e128_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + +/* +** reg_e128: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128 reg_e128 (int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_4: +** mov x0, x1 +** ret +*/ +e64_4 reg_e64_4 (int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_8: +** mov x0, x1 +** ret +*/ +e64_8 reg_e64_8 (int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_16: +** mov x0, x1 +** ret +*/ +e64_16 reg_e64_16 (int x, e64_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_32: +** mov x0, x1 +** ret +*/ +e64_32 reg_e64_32 (int x, e64_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64: +** mov x0, x1 +** ret +*/ +e64 reg_e64 (int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_4: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_4 stack_e128_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + +/* +** stack_e128_8: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_8 stack_e128_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + +/* +** stack_e128_16: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_16 stack_e128_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_32: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_32 stack_e128_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128 stack_e128 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_4: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_4 stack_e64_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_8: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_8 stack_e64_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_16: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_16 stack_e64_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_16 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + +/* +** stack_e64_32: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_32 stack_e64_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + +/* +** stack_e64: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64 stack_e64 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +void callee (int n, ...); + +void +caller () +{ + callee (1, e128_4::A); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + callee (1, e128_8::A); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + callee (1, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e128_32::A); /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + callee (1, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (1, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_32::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64::A); /* { dg-bogus {parameter passing} } */ + +#define LOTS 1, 2, 3, 4, 5, 6, 7, 8, 9 + + callee (LOTS, e128_4::A); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + callee (LOTS, e128_8::A); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + callee (LOTS, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_32::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (LOTS, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e64_16::A); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + callee (LOTS, e64_32::A); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + callee (LOTS, e64::A); /* { dg-bogus {parameter passing} } */ +} + +void +va (volatile void *ptr, ...) +{ + va_list ap; + va_start (ap, ptr); + *(volatile e128_4 *) ptr = va_arg (ap, e128_4); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + *(volatile e128_8 *) ptr = va_arg (ap, e128_8); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + *(volatile e128_16 *) ptr = va_arg (ap, e128_16); /* { dg-bogus {parameter passing} } */ + *(volatile e128_32 *) ptr = va_arg (ap, e128_32); /* { dg-bogus {parameter passing} } */ + *(volatile e128 *) ptr = va_arg (ap, e128); /* { dg-bogus {parameter passing} } */ + *(volatile e64_4 *) ptr = va_arg (ap, e64_4); /* { dg-bogus {parameter passing} } */ + *(volatile e64_8 *) ptr = va_arg (ap, e64_8); /* { dg-bogus {parameter passing} } */ + *(volatile e64_16 *) ptr = va_arg (ap, e64_16); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + *(volatile e64_32 *) ptr = va_arg (ap, e64_32); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + *(volatile e64 *) ptr = va_arg (ap, e64); /* { dg-bogus {parameter passing} } */ +} + +} diff --git a/gcc/testsuite/g++.target/aarch64/pr109661-3.C b/gcc/testsuite/g++.target/aarch64/pr109661-3.C new file mode 100644 index 00000000000..dab2fb295d3 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr109661-3.C @@ -0,0 +1,253 @@ +/* { dg-options "-O2 -Wpsabi" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +#define ALIGN __attribute__((aligned(16))) + +typedef __uint128_t u128_4 __attribute__((aligned(4))); +typedef __uint128_t u128_8 __attribute__((aligned(8))); +typedef __uint128_t u128_16 __attribute__((aligned(16))); +typedef __uint128_t u128_32 __attribute__((aligned(32))); +typedef __uint128_t u128; + +typedef __UINT64_TYPE__ u64_4 __attribute__((aligned(4))); +typedef __UINT64_TYPE__ u64_8 __attribute__((aligned(8))); +typedef __UINT64_TYPE__ u64_16 __attribute__((aligned(16))); +typedef __UINT64_TYPE__ u64_32 __attribute__((aligned(32))); +typedef __UINT64_TYPE__ u64; + +enum class ALIGN e128_4 : u128_4 { A }; +enum class ALIGN e128_8 : u128_8 { A }; +enum class ALIGN e128_16 : u128_16 { A }; +enum class ALIGN e128_32 : u128_32 { A }; +enum class ALIGN e128 : u128 { A }; + +enum class ALIGN e64_4 : u64_4 { A }; +enum class ALIGN e64_8 : u64_8 { A }; +enum class ALIGN e64_16 : u64_16 { A }; +enum class ALIGN e64_32 : u64_32 { A }; +enum class ALIGN e64 : u64 { A }; + +extern "C" { + +/* +** reg_e128_4: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_4 reg_e128_4 (int x, e128_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e128_8: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_8 reg_e128_8 (int x, e128_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e128_16: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_16 reg_e128_16 (int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e128_32: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_32 reg_e128_32 (int x, e128_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + +/* +** reg_e128: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128 reg_e128 (int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_4: +** mov x0, x1 +** ret +*/ +e64_4 reg_e64_4 (int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_8: +** mov x0, x1 +** ret +*/ +e64_8 reg_e64_8 (int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_16: +** mov x0, x1 +** ret +*/ +e64_16 reg_e64_16 (int x, e64_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_32: +** mov x0, x1 +** ret +*/ +e64_32 reg_e64_32 (int x, e64_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64: +** mov x0, x1 +** ret +*/ +e64 reg_e64 (int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_4: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_4 stack_e128_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_8: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_8 stack_e128_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_16: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_16 stack_e128_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_32: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_32 stack_e128_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128 stack_e128 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_4: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_4 stack_e64_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + +/* +** stack_e64_8: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_8 stack_e64_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + +/* +** stack_e64_16: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_16 stack_e64_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_16 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + +/* +** stack_e64_32: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_32 stack_e64_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + +/* +** stack_e64: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64 stack_e64 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ + +void callee (int n, ...); + +void +caller () +{ + callee (1, e128_4::A); /* { dg-bogus {parameter passing} } */ + callee (1, e128_8::A); /* { dg-bogus {parameter passing} } */ + callee (1, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e128_32::A); /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + callee (1, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (1, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_32::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64::A); /* { dg-bogus {parameter passing} } */ + +#define LOTS 1, 2, 3, 4, 5, 6, 7, 8, 9 + + callee (LOTS, e128_4::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_8::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_32::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (LOTS, e64_4::A); /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + callee (LOTS, e64_8::A); /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + callee (LOTS, e64_16::A); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + callee (LOTS, e64_32::A); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + callee (LOTS, e64::A); /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ +} + +void +va (volatile void *ptr, ...) +{ + va_list ap; + va_start (ap, ptr); + *(volatile e128_4 *) ptr = va_arg (ap, e128_4); /* { dg-bogus {parameter passing} } */ + *(volatile e128_8 *) ptr = va_arg (ap, e128_8); /* { dg-bogus {parameter passing} } */ + *(volatile e128_16 *) ptr = va_arg (ap, e128_16); /* { dg-bogus {parameter passing} } */ + *(volatile e128_32 *) ptr = va_arg (ap, e128_32); /* { dg-bogus {parameter passing} } */ + *(volatile e128 *) ptr = va_arg (ap, e128); /* { dg-bogus {parameter passing} } */ + *(volatile e64_4 *) ptr = va_arg (ap, e64_4); /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + *(volatile e64_8 *) ptr = va_arg (ap, e64_8); /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + *(volatile e64_16 *) ptr = va_arg (ap, e64_16); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + *(volatile e64_32 *) ptr = va_arg (ap, e64_32); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + *(volatile e64 *) ptr = va_arg (ap, e64); /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ +} + +} diff --git a/gcc/testsuite/g++.target/aarch64/pr109661-4.C b/gcc/testsuite/g++.target/aarch64/pr109661-4.C new file mode 100644 index 00000000000..d87e60fcc5d --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/pr109661-4.C @@ -0,0 +1,253 @@ +/* { dg-options "-O2 -Wpsabi" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include + +#define ALIGN __attribute__((aligned(32))) + +typedef __uint128_t u128_4 __attribute__((aligned(4))); +typedef __uint128_t u128_8 __attribute__((aligned(8))); +typedef __uint128_t u128_16 __attribute__((aligned(16))); +typedef __uint128_t u128_32 __attribute__((aligned(32))); +typedef __uint128_t u128; + +typedef __UINT64_TYPE__ u64_4 __attribute__((aligned(4))); +typedef __UINT64_TYPE__ u64_8 __attribute__((aligned(8))); +typedef __UINT64_TYPE__ u64_16 __attribute__((aligned(16))); +typedef __UINT64_TYPE__ u64_32 __attribute__((aligned(32))); +typedef __UINT64_TYPE__ u64; + +enum class ALIGN e128_4 : u128_4 { A }; +enum class ALIGN e128_8 : u128_8 { A }; +enum class ALIGN e128_16 : u128_16 { A }; +enum class ALIGN e128_32 : u128_32 { A }; +enum class ALIGN e128 : u128 { A }; + +enum class ALIGN e64_4 : u64_4 { A }; +enum class ALIGN e64_8 : u64_8 { A }; +enum class ALIGN e64_16 : u64_16 { A }; +enum class ALIGN e64_32 : u64_32 { A }; +enum class ALIGN e64 : u64 { A }; + +extern "C" { + +/* +** reg_e128_4: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_4 reg_e128_4 (int x, e128_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + +/* +** reg_e128_8: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_8 reg_e128_8 (int x, e128_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + +/* +** reg_e128_16: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_16 reg_e128_16 (int x, e128_16 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_16' changed in GCC 14.1} } */ + +/* +** reg_e128_32: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128_32 reg_e128_32 (int x, e128_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + +/* +** reg_e128: +** ( +** mov x1, x3 +** mov x0, x2 +** | +** mov x0, x2 +** mov x1, x3 +** ) +** ret +*/ +e128 reg_e128 (int x, e128 y) { return y; } /* { dg-note {parameter passing for argument of type 'e128' changed in GCC 14.1} } */ + +/* +** reg_e64_4: +** mov x0, x1 +** ret +*/ +e64_4 reg_e64_4 (int x, e64_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_8: +** mov x0, x1 +** ret +*/ +e64_8 reg_e64_8 (int x, e64_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_16: +** mov x0, x1 +** ret +*/ +e64_16 reg_e64_16 (int x, e64_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64_32: +** mov x0, x1 +** ret +*/ +e64_32 reg_e64_32 (int x, e64_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** reg_e64: +** mov x0, x1 +** ret +*/ +e64 reg_e64 (int x, e64 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_4: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_4 stack_e128_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_4 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_8: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_8 stack_e128_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_8 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_16: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_16 stack_e128_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_16 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128_32: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128_32 stack_e128_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128_32 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e128: +** ldp x0, x1, \[sp, #?16\] +** ret +*/ +e128 stack_e128 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e128 y) { return y; } /* { dg-bogus {parameter passing} } */ + +/* +** stack_e64_4: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_4 stack_e64_4 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_4 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + +/* +** stack_e64_8: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_8 stack_e64_8 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_8 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + +/* +** stack_e64_16: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_16 stack_e64_16 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_16 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + +/* +** stack_e64_32: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64_32 stack_e64_32 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64_32 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + +/* +** stack_e64: +** ldr x0, \[sp, #?8\] +** ret +*/ +e64 stack_e64 (u128 x0, u128 x2, u128 x4, u128 x6, int x, e64 y) { return y; } /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ + +void callee (int n, ...); + +void +caller () +{ + callee (1, e128_4::A); /* { dg-note {parameter passing for argument of type 'e128_4' changed in GCC 14.1} } */ + callee (1, e128_8::A); /* { dg-note {parameter passing for argument of type 'e128_8' changed in GCC 14.1} } */ + callee (1, e128_16::A); /* { dg-note {parameter passing for argument of type 'e128_16' changed in GCC 14.1} } */ + callee (1, e128_32::A); /* { dg-note {parameter passing for argument of type 'e128_32' changed in GCC 14.1} } */ + callee (1, e128::A); /* { dg-note {parameter passing for argument of type 'e128' changed in GCC 14.1} } */ + + callee (1, e64_4::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_8::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_16::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64_32::A); /* { dg-bogus {parameter passing} } */ + callee (1, e64::A); /* { dg-bogus {parameter passing} } */ + +#define LOTS 1, 2, 3, 4, 5, 6, 7, 8, 9 + + callee (LOTS, e128_4::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_8::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_16::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128_32::A); /* { dg-bogus {parameter passing} } */ + callee (LOTS, e128::A); /* { dg-bogus {parameter passing} } */ + + callee (LOTS, e64_4::A); /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + callee (LOTS, e64_8::A); /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + callee (LOTS, e64_16::A); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + callee (LOTS, e64_32::A); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + callee (LOTS, e64::A); /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ +} + +void +va (volatile void *ptr, ...) +{ + va_list ap; + va_start (ap, ptr); + *(volatile e128_4 *) ptr = va_arg (ap, e128_4); /* { dg-bogus {parameter passing} } */ + *(volatile e128_8 *) ptr = va_arg (ap, e128_8); /* { dg-bogus {parameter passing} } */ + *(volatile e128_16 *) ptr = va_arg (ap, e128_16); /* { dg-bogus {parameter passing} } */ + *(volatile e128_32 *) ptr = va_arg (ap, e128_32); /* { dg-bogus {parameter passing} } */ + *(volatile e128 *) ptr = va_arg (ap, e128); /* { dg-bogus {parameter passing} } */ + *(volatile e64_4 *) ptr = va_arg (ap, e64_4); /* { dg-note {parameter passing for argument of type 'e64_4' changed in GCC 14.1} } */ + *(volatile e64_8 *) ptr = va_arg (ap, e64_8); /* { dg-note {parameter passing for argument of type 'e64_8' changed in GCC 14.1} } */ + *(volatile e64_16 *) ptr = va_arg (ap, e64_16); /* { dg-note {parameter passing for argument of type 'e64_16' changed in GCC 14.1} } */ + *(volatile e64_32 *) ptr = va_arg (ap, e64_32); /* { dg-note {parameter passing for argument of type 'e64_32' changed in GCC 14.1} } */ + *(volatile e64 *) ptr = va_arg (ap, e64); /* { dg-note {parameter passing for argument of type 'e64' changed in GCC 14.1} } */ +} + +} diff --git a/gcc/testsuite/gcc.target/aarch64/pr109661-1.c b/gcc/testsuite/gcc.target/aarch64/pr109661-1.c new file mode 100644 index 00000000000..5686b2b1cb5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/pr109661-1.c @@ -0,0 +1,11 @@ +/* { dg-options "-O2 -Wpsabi" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +enum __attribute__((aligned(16))) e { E }; + +/* +** test: +** mov w0, w1 +** ret +*/ +enum e test (int x, enum e y) { return y; } /* { dg-bogus {parameter passing} } */