From patchwork Thu Jul 18 04:29:59 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 1961887 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=SZhovkjg; dkim-atps=neutral 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=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.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 (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WPg6Y4lFSz1yY1 for ; Thu, 18 Jul 2024 14:38:29 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9642D386074C for ; Thu, 18 Jul 2024 04:38:27 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) by sourceware.org (Postfix) with ESMTPS id DD8D6385C6C9 for ; Thu, 18 Jul 2024 04:37:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DD8D6385C6C9 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.intel.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=linux.intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DD8D6385C6C9 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277480; cv=none; b=dyl/J83Olc7ZMimF5NouaXmHWAkEU5d0a/pj77dTdbWggHYbxY2Fw8DWdUC8kcdUyynQ3dT04c/HD6NSjJIEozBN2XjNhD4oqroKrDmlKhHDywoTJ4s1tzdvJfcUV1gQVSu1NvA+t3hYRZR1vuY2RQVAmZE7M3A0SrB3G8RoSp4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277480; c=relaxed/simple; bh=V54JdRIwyIHXcHwl1wwZ/9d7GUYZrB8R5/ZnpXBiGI4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=bp7dsylsFhYFOrzKMSa1roKsMCq8FAsMYAUwILx1exO3JpsvSDMV1zaVHW2vC3K5lbbWiIS1zQoOk4JN6tuN2yD77wWPX3FJbuFtrGnB3c8SxM0Kzy+WDhQ5ua9Z9Bazs17SHd0OmIunBfC8rO1u/YG9OP6a4DrfoMNjVvZnGHI= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1721277478; x=1752813478; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=V54JdRIwyIHXcHwl1wwZ/9d7GUYZrB8R5/ZnpXBiGI4=; b=SZhovkjgTRBzeuup+irD8bbV7i50NDoJouaauDlSJK5d5/NWOiaZzBeG TcmmmWgvKvDsSAoWmpJNYlsZ4mP8j/TNnjvAU54/4TKioAwoRW8ovIoku wuYvr61/cMY2a4FqBKraaoniLOAGwAG5mlIHahC1pzsgjSl0oJ/SlI2ix SmjAUXftjdBc9UEpwc+o7zUUUENsCzfBctt6x9tg4PNDqGM8dClrHYYSC mGItNy+URxw5yG2l46FZqg2OwxvnqrjYMiw3vfTAHe43MddfKiO7T/oy8 mQ0JhLs5jLGeLuGVWPGgUGm+0sbHowbitfZNBmURK2f+BNyBD2PGy8nGN w==; X-CSE-ConnectionGUID: FgU+7f5qR0Svs9IIzZqAow== X-CSE-MsgGUID: +cHC/siWSHa6QsE0MFEP7w== X-IronPort-AV: E=McAfee;i="6700,10204,11136"; a="18515139" X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="18515139" Received: from fmviesa003.fm.intel.com ([10.60.135.143]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:56 -0700 X-CSE-ConnectionGUID: rLM3aVIIQY61h8coQpUDvQ== X-CSE-MsgGUID: ODaVS3RQRWe0+sFF5CRcrA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="54810593" Received: from tassilo.jf.intel.com ([10.54.38.190]) by fmviesa003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:57 -0700 From: Andi Kleen To: gcc-patches@gcc.gnu.org Cc: polacek@redhat.com, josmyers@redhat.com, jason@redhat.com, Andi Kleen Subject: [PATCH v10 1/3] C++: Support clang compatible [[musttail]] (PR83324) Date: Wed, 17 Jul 2024 21:29:59 -0700 Message-ID: <20240718043750.2480283-2-ak@linux.intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240718043750.2480283-1-ak@linux.intel.com> References: <20240718043750.2480283-1-ak@linux.intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org This patch implements a clang compatible [[musttail]] attribute for returns. musttail is useful as an alternative to computed goto for interpreters. With computed goto the interpreter function usually ends up very big which causes problems with register allocation and other per function optimizations not scaling. With musttail the interpreter can be instead written as a sequence of smaller functions that call each other. To avoid unbounded stack growth this requires forcing a sibling call, which this attribute does. It guarantees an error if the call cannot be tail called which allows the programmer to fix it instead of risking a stack overflow. Unlike computed goto it is also type-safe. It turns out that David Malcolm had already implemented middle/backend support for a musttail attribute back in 2016, but it wasn't exposed to any frontend other than a special plugin. This patch adds a [[gnu::musttail]] attribute for C++ that can be added to return statements. The return statement must be a direct call (it does not follow dependencies), which is similar to what clang implements. It then uses the existing must tail infrastructure. For compatibility it also detects clang::musttail Passes bootstrap and full test gcc/c-family/ChangeLog: * c-attribs.cc (set_musttail_on_return): New function. * c-common.h (set_musttail_on_return): Declare new function. gcc/cp/ChangeLog: PR c/83324 * cp-tree.h (AGGR_INIT_EXPR_MUST_TAIL): Add. * parser.cc (cp_parser_statement): Handle musttail. (cp_parser_jump_statement): Dito. * pt.cc (tsubst_expr): Copy CALL_EXPR_MUST_TAIL_CALL. * semantics.cc (simplify_aggr_init_expr): Handle musttail. --- gcc/c-family/c-attribs.cc | 20 ++++++++++++++++++++ gcc/c-family/c-common.h | 1 + gcc/cp/cp-tree.h | 4 ++++ gcc/cp/parser.cc | 32 +++++++++++++++++++++++++++++--- gcc/cp/pt.cc | 9 ++++++++- gcc/cp/semantics.cc | 1 + 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index 5adc7b775eaf..685f212683f4 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -672,6 +672,26 @@ attribute_takes_identifier_p (const_tree attr_id) return targetm.attribute_takes_identifier_p (attr_id); } +/* Set a musttail attribute MUSTTAIL_P on return expression RETVAL + at LOC. */ + +void +set_musttail_on_return (tree retval, location_t loc, bool musttail_p) +{ + if (retval && musttail_p) + { + tree t = retval; + if (TREE_CODE (t) == TARGET_EXPR) + t = TARGET_EXPR_INITIAL (t); + if (TREE_CODE (t) != CALL_EXPR) + error_at (loc, "cannot tail-call: return value must be a call"); + else + CALL_EXPR_MUST_TAIL_CALL (t) = 1; + } + else if (musttail_p && !retval) + error_at (loc, "cannot tail-call: return value must be a call"); +} + /* 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 adee822a3ae0..2510ee4dbc9d 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1648,6 +1648,7 @@ extern tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); extern tree handle_musttail_attribute (tree *, tree, tree, int, bool *); extern bool has_attribute (location_t, tree, tree, tree (*)(tree)); extern tree build_attr_access_from_parms (tree, bool); +extern void set_musttail_on_return (tree, location_t, bool); /* In c-format.cc. */ extern bool valid_format_string_type_p (tree); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c6f102564ce0..67ba3274eb1b 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4236,6 +4236,10 @@ templated_operator_saved_lookups (tree t) #define AGGR_INIT_FROM_THUNK_P(NODE) \ (AGGR_INIT_EXPR_CHECK (NODE)->base.protected_flag) +/* Nonzero means that the call was marked musttail. */ +#define AGGR_INIT_EXPR_MUST_TAIL(NODE) \ + (AGGR_INIT_EXPR_CHECK (NODE)->base.static_flag) + /* AGGR_INIT_EXPR accessors. These are equivalent to the CALL_EXPR accessors, except for AGGR_INIT_EXPR_SLOT (which takes the place of CALL_EXPR_STATIC_CHAIN). */ diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index efd5d6f29a71..71bffd4a9311 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -2467,7 +2467,7 @@ static tree cp_parser_perform_range_for_lookup static tree cp_parser_range_for_member_function (tree, tree); static tree cp_parser_jump_statement - (cp_parser *); + (cp_parser *, tree &); static void cp_parser_declaration_statement (cp_parser *); @@ -12757,7 +12757,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, case RID_CO_RETURN: case RID_GOTO: std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); - statement = cp_parser_jump_statement (parser); + statement = cp_parser_jump_statement (parser, std_attrs); break; /* Objective-C++ exception-handling constructs. */ @@ -14845,10 +14845,11 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) jump-statement: goto * expression ; + STD_ATTRS are the statement attributes. They can be modified. Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_EXPR, or GOTO_EXPR. */ static tree -cp_parser_jump_statement (cp_parser* parser) +cp_parser_jump_statement (cp_parser* parser, tree &std_attrs) { tree statement = error_mark_node; cp_token *token; @@ -14925,6 +14926,31 @@ cp_parser_jump_statement (cp_parser* parser) /* If the next token is a `;', then there is no expression. */ expr = NULL_TREE; + + if (keyword == RID_RETURN && expr) + { + bool musttail_p = false; + if (lookup_attribute ("gnu", "musttail", std_attrs)) + { + musttail_p = true; + std_attrs = remove_attribute ("gnu", "musttail", std_attrs); + } + /* Support this for compatibility. */ + if (lookup_attribute ("clang", "musttail", std_attrs)) + { + musttail_p = true; + std_attrs = remove_attribute ("clang", "musttail", std_attrs); + } + + tree ret_expr = expr; + if (TREE_CODE (ret_expr) == TARGET_EXPR) + ret_expr = TARGET_EXPR_INITIAL (ret_expr); + if (TREE_CODE (ret_expr) == AGGR_INIT_EXPR) + AGGR_INIT_EXPR_MUST_TAIL (ret_expr) = musttail_p; + else + set_musttail_on_return (expr, token->location, musttail_p); + } + /* Build the return-statement, check co-return first, since type deduction is not valid there. */ if (keyword == RID_CO_RETURN) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 057797f213f5..148f461d4fb8 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21089,12 +21089,19 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) bool op = CALL_EXPR_OPERATOR_SYNTAX (t); bool ord = CALL_EXPR_ORDERED_ARGS (t); bool rev = CALL_EXPR_REVERSE_ARGS (t); - if (op || ord || rev) + bool mtc = false; + if (TREE_CODE (t) == CALL_EXPR) + mtc = CALL_EXPR_MUST_TAIL_CALL (t); + if (op || ord || rev || mtc) if (tree call = extract_call_expr (ret)) { CALL_EXPR_OPERATOR_SYNTAX (call) = op; CALL_EXPR_ORDERED_ARGS (call) = ord; CALL_EXPR_REVERSE_ARGS (call) = rev; + if (TREE_CODE (call) == CALL_EXPR) + CALL_EXPR_MUST_TAIL_CALL (call) = mtc; + else if (TREE_CODE (call) == AGGR_INIT_EXPR) + AGGR_INIT_EXPR_MUST_TAIL (call) = mtc; } if (warning_suppressed_p (t, OPT_Wpessimizing_move)) /* This also suppresses -Wredundant-move. */ diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index c21572e5d7f7..0f122b839c5f 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -4979,6 +4979,7 @@ simplify_aggr_init_expr (tree *tp) = CALL_EXPR_OPERATOR_SYNTAX (aggr_init_expr); CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (aggr_init_expr); CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (aggr_init_expr); + CALL_EXPR_MUST_TAIL_CALL (call_expr) = AGGR_INIT_EXPR_MUST_TAIL (aggr_init_expr); if (style == ctor) { From patchwork Thu Jul 18 04:30:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 1961888 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=I5vAdxaW; dkim-atps=neutral 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=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.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 (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WPg6l73K0z1yY1 for ; Thu, 18 Jul 2024 14:38:39 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 380793860772 for ; Thu, 18 Jul 2024 04:38:38 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) by sourceware.org (Postfix) with ESMTPS id DA7D9385C6CB for ; Thu, 18 Jul 2024 04:37:59 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org DA7D9385C6CB Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.intel.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=linux.intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org DA7D9385C6CB Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277485; cv=none; b=ikr6clNWxuz3N5SOaDvz5YVcIx5dc35VSwpAr5KSy5OWoJ8F4+pQLf2LU7KDxLJkOQGnOxoFD1461C7wulKNxl32H0I2CIcy2MBKeAcYYF+6ryo4hkeMOsMWl0V03FSHN/O0IK/VQIqidu9kGNuI/SwOr5zDzPNzCdnLb0FyjYc= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277485; c=relaxed/simple; bh=bu7+EX3x6KtsktUZtUBKi6Tx8QbqfpWqx53rLa+KZn4=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=LqQ6fvtDeOJG4dz4vgnZcxFJiykJTAQmzYPbUI1gQGYwfQHzqijy7iLlYUG+TNV+M4cNxc2fiZO89m64XwBeNfQ3ZAG4edDgaXppOAYK1X+OMz43haAdhw2OQ11sPL38EwE0Hp7CtHILJSofJa4VbmCquetlpAgFOD7eY3KkZ28= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1721277480; x=1752813480; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bu7+EX3x6KtsktUZtUBKi6Tx8QbqfpWqx53rLa+KZn4=; b=I5vAdxaWdUCqrpW9yCXJshmad/UA5aEDAZSHjYYW5JO8Z2otQ0aq/+zk L/ak2wpF6d4QN3FSfwfUOZiHqrZ0J7wBHPjnZ0p9gSkLTtaazVJSe1piN nskq8l3raY09kJLRoHUXRXbwbWyrywaItVYOkx0vuDwbbWq+nUIElOkNT 9ZtKAcO8Z/jYR/YkQZy2dCgLs50WjXZrLmMLrrkIyom+C4ylMuCnCSJis yZ9iJqlEfuQZs/EAaM5H6eDldZiuk+8iPMosAD/znRRh3ePLuxlURsrU5 R7UJWvSaRr5EOYXp8pxZx0TQFoN007EziPo5ym51jhr7+XJQuPT8ZPT+5 g==; X-CSE-ConnectionGUID: TeLxf4h6R3uWvIsO7+9Png== X-CSE-MsgGUID: ijeRjG3oTzm3je1n6XTYSg== X-IronPort-AV: E=McAfee;i="6700,10204,11136"; a="18515141" X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="18515141" Received: from fmviesa003.fm.intel.com ([10.60.135.143]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:57 -0700 X-CSE-ConnectionGUID: Thqc0ALOQlGtxlgd3Pm25w== X-CSE-MsgGUID: 6RvHXOeRR4+n6D43pl6AMA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="54810599" Received: from tassilo.jf.intel.com ([10.54.38.190]) by fmviesa003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:57 -0700 From: Andi Kleen To: gcc-patches@gcc.gnu.org Cc: polacek@redhat.com, josmyers@redhat.com, jason@redhat.com, Andi Kleen Subject: [PATCH v10 2/3] C: Implement musttail attribute for returns Date: Wed, 17 Jul 2024 21:30:00 -0700 Message-ID: <20240718043750.2480283-3-ak@linux.intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240718043750.2480283-1-ak@linux.intel.com> References: <20240718043750.2480283-1-ak@linux.intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Implement a C23 clang compatible musttail attribute similar to the earlier C++ implementation in the C parser. gcc/c/ChangeLog: PR c/83324 * c-parser.cc (struct attr_state): Define with musttail_p. (c_parser_statement_after_labels): Handle [[musttail]]. (c_parser_std_attribute): Dito. (c_parser_handle_musttail): Dito. (c_parser_compound_statement_nostart): Dito. (c_parser_all_labels): Dito. (c_parser_statement): Dito. * c-tree.h (c_finish_return): Add musttail_p flag. * c-typeck.cc (c_finish_return): Handle musttail_p flag. --- gcc/c/c-parser.cc | 70 ++++++++++++++++++++++++++++++++++++++--------- gcc/c/c-tree.h | 2 +- gcc/c/c-typeck.cc | 7 +++-- 3 files changed, 63 insertions(+), 16 deletions(-) diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 12c5ed5d92c7..a8848d01f21a 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -1621,6 +1621,12 @@ struct omp_for_parse_data { bool fail : 1; }; +struct attr_state +{ + /* True if we parsed a musttail attribute for return. */ + bool musttail_p; +}; + static bool c_parser_nth_token_starts_std_attributes (c_parser *, unsigned int); static tree c_parser_std_attribute_specifier_sequence (c_parser *); @@ -1665,7 +1671,7 @@ static location_t c_parser_compound_statement_nostart (c_parser *); static void c_parser_label (c_parser *, tree); static void c_parser_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_statement_after_labels (c_parser *, bool *, - vec * = NULL); + vec * = NULL, attr_state = {}); static tree c_parser_c99_block_statement (c_parser *, bool *, location_t * = NULL); static void c_parser_if_statement (c_parser *, bool *, vec *); @@ -6982,6 +6988,29 @@ c_parser_handle_directive_omp_attributes (tree &attrs, } } +/* Check if STD_ATTR contains a musttail attribute and remove if it + precedes a return. PARSER is the parser and ATTR is the output + attr_state. */ + +static tree +c_parser_handle_musttail (c_parser *parser, tree std_attrs, attr_state &attr) +{ + if (c_parser_next_token_is_keyword (parser, RID_RETURN)) + { + if (lookup_attribute ("gnu", "musttail", std_attrs)) + { + std_attrs = remove_attribute ("gnu", "musttail", std_attrs); + attr.musttail_p = true; + } + if (lookup_attribute ("clang", "musttail", std_attrs)) + { + std_attrs = remove_attribute ("clang", "musttail", std_attrs); + attr.musttail_p = true; + } + } + return std_attrs; +} + /* Parse a compound statement except for the opening brace. This is used for parsing both compound statements and statement expressions (which follow different paths to handling the opening). */ @@ -6998,6 +7027,7 @@ c_parser_compound_statement_nostart (c_parser *parser) bool in_omp_loop_block = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; tree sl = NULL_TREE; + attr_state a = {}; if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) { @@ -7138,7 +7168,10 @@ c_parser_compound_statement_nostart (c_parser *parser) = c_parser_nth_token_starts_std_attributes (parser, 1); tree std_attrs = NULL_TREE; if (have_std_attrs) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + std_attrs = c_parser_handle_musttail (parser, std_attrs, a); + } if (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) @@ -7286,7 +7319,7 @@ c_parser_compound_statement_nostart (c_parser *parser) last_stmt = true; mark_valid_location_for_stdc_pragma (false); if (!omp_for_parse_state) - c_parser_statement_after_labels (parser, NULL); + c_parser_statement_after_labels (parser, NULL, NULL, a); else { /* In canonical loop nest form, nested loops can only appear @@ -7328,15 +7361,20 @@ c_parser_compound_statement_nostart (c_parser *parser) /* Parse all consecutive labels, possibly preceded by standard attributes. In this context, a statement is required, not a declaration, so attributes must be followed by a statement that is - not just a semicolon. */ + not just a semicolon. Returns an attr_state. */ -static void +static attr_state c_parser_all_labels (c_parser *parser) { + attr_state attr = {}; bool have_std_attrs; tree std_attrs = NULL; if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1))) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + std_attrs = c_parser_handle_musttail (parser, std_attrs, attr); + } + while (c_parser_next_token_is_keyword (parser, RID_CASE) || c_parser_next_token_is_keyword (parser, RID_DEFAULT) || (c_parser_next_token_is (parser, CPP_NAME) @@ -7346,7 +7384,10 @@ c_parser_all_labels (c_parser *parser) std_attrs = NULL; if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, 1))) - std_attrs = c_parser_std_attribute_specifier_sequence (parser); + { + std_attrs = c_parser_std_attribute_specifier_sequence (parser); + std_attrs = c_parser_handle_musttail (parser, std_attrs, attr); + } } if (std_attrs && (!c_parser_handle_statement_omp_attributes (parser, std_attrs, &have_std_attrs) @@ -7358,6 +7399,7 @@ c_parser_all_labels (c_parser *parser) } else if (have_std_attrs && c_parser_next_token_is (parser, CPP_SEMICOLON)) c_parser_error (parser, "expected statement"); + return attr; } /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). @@ -7601,11 +7643,11 @@ c_parser_label (c_parser *parser, tree std_attrs) static void c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) { - c_parser_all_labels (parser); + attr_state a = c_parser_all_labels (parser); if (loc_after_labels) *loc_after_labels = c_parser_peek_token (parser)->location; parser->omp_attrs_forbidden_p = false; - c_parser_statement_after_labels (parser, if_p, NULL); + c_parser_statement_after_labels (parser, if_p, NULL, a); } /* Parse a statement, other than a labeled statement. CHAIN is a vector @@ -7614,11 +7656,11 @@ c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) IF_P is used to track whether there's a (possibly labeled) if statement which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ + implement -Wparentheses. ASTATE is an earlier parsed attribute state. */ static void c_parser_statement_after_labels (c_parser *parser, bool *if_p, - vec *chain) + vec *chain, attr_state astate) { location_t loc = c_parser_peek_token (parser)->location; tree stmt = NULL_TREE; @@ -7686,7 +7728,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); + stmt = c_finish_return (loc, NULL_TREE, NULL_TREE, + astate.musttail_p); c_parser_consume_token (parser); } else @@ -7695,7 +7738,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, struct c_expr expr = c_parser_expression_conv (parser); mark_exp_read (expr.value); stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), - expr.value, expr.original_type); + expr.value, expr.original_type, + astate.musttail_p); goto expect_semicolon; } break; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 15da875a0290..3dc6338bf061 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -827,7 +827,7 @@ extern tree c_begin_stmt_expr (void); extern tree c_finish_stmt_expr (location_t, tree); extern tree c_process_expr_stmt (location_t, tree); extern tree c_finish_expr_stmt (location_t, tree); -extern tree c_finish_return (location_t, tree, tree); +extern tree c_finish_return (location_t, tree, tree, bool = false); extern tree c_finish_bc_stmt (location_t, tree, bool); extern tree c_finish_goto_label (location_t, tree); extern tree c_finish_goto_ptr (location_t, c_expr val); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7e0f01ed22b9..094e41fa2021 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -11725,10 +11725,11 @@ c_finish_goto_ptr (location_t loc, c_expr val) to return, or a null pointer for `return;' with no value. LOC is the location of the return statement, or the location of the expression, if the statement has any. If ORIGTYPE is not NULL_TREE, it - is the original type of RETVAL. */ + is the original type of RETVAL. MUSTTAIL_P indicates a musttail + attribute. */ tree -c_finish_return (location_t loc, tree retval, tree origtype) +c_finish_return (location_t loc, tree retval, tree origtype, bool musttail_p) { tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt; bool no_warning = false; @@ -11742,6 +11743,8 @@ c_finish_return (location_t loc, tree retval, tree origtype) warning_at (xloc, 0, "function declared % has a % statement"); + set_musttail_on_return (retval, xloc, musttail_p); + if (retval) { tree semantic_type = NULL_TREE; From patchwork Thu Jul 18 04:30:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 1961889 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=UOYFdcXq; dkim-atps=neutral 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=server2.sourceware.org; envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.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 (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4WPg803t3jz1yY1 for ; Thu, 18 Jul 2024 14:39:44 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id CC7B4385E839 for ; Thu, 18 Jul 2024 04:39:42 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.19]) by sourceware.org (Postfix) with ESMTPS id 71C6A385DC1B for ; Thu, 18 Jul 2024 04:38:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 71C6A385DC1B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=linux.intel.com Authentication-Results: sourceware.org; spf=none smtp.mailfrom=linux.intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 71C6A385DC1B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.19 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277485; cv=none; b=WKSXQVc29IYdT3rNHaUw+yn969B73BstWoj3q+AzMArHYSeLudgTPgzYxcLEeHtCRAoyiYu+uSzU2Uv/EXNeFmcp20sdilVyzyjm2on28ZO5BtmRCEwgAxeYudgwK6Pf3Bz3DcV0EqtYDIyKaTL3dxiiGjM1QzzYR2Ny3M8eoZM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1721277485; c=relaxed/simple; bh=HKM/FPCDbDnJxLqgmhj5KP6EMsptPUlTk/Zj8GuFDwc=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=U8Ru20GGmAxrbELFIMMDPnaQWCIje14GM5V8K+bXx/ddwn/WgjLgyNpW7fL5JEtyA/lUijulgyvnuS9GJjGI2BjrLP9vOKHFRGDR8ujvWnXX8L1uXgqfzUEZ79oO7hRt/CPQiPZaDyQ+JKJU4CMrTQCenVgICeH1e2KMYyzLMSw= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1721277480; x=1752813480; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HKM/FPCDbDnJxLqgmhj5KP6EMsptPUlTk/Zj8GuFDwc=; b=UOYFdcXqjf4OSe3bT30XfExommPFoyqN0G2iwXK8+GpXfAgF2g9hPIj5 Y6BruMjLlv1lamXYMBqWnKe1yQx8IcbxRr/pI+4R4ArnlwiKQ5jW6ZGfg 47d/jL1oYWSI6l99LAzXeR4WRSZuN8ZcHES8HVj2yEn1YTNDFV7+FArt2 1r0nwjWH/bfNLgYPhkDMv3tjejHSUD+i0xHIf0gdaVc+3tSi36hKleGAC 8yrmNXLL0kevvkDA4Pj3nmOiT4Q+tqyp0VBygwdu9/Z9dvrFV9/9vaLid wKG3Q3Se4UqYzxPTvjGGVla/bUYVCORzyPPkeSB45r9Leh8gm54OV/jXQ Q==; X-CSE-ConnectionGUID: Img9kq1YQ6etFxMDq0RE1w== X-CSE-MsgGUID: KLb2g/hTRxGNj0d07ufUfQ== X-IronPort-AV: E=McAfee;i="6700,10204,11136"; a="18515143" X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="18515143" Received: from fmviesa003.fm.intel.com ([10.60.135.143]) by fmvoesa113.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:57 -0700 X-CSE-ConnectionGUID: NZ4ipA1BRLWufYZE0ilhwA== X-CSE-MsgGUID: ddX0OJR/QxK6l4Fe+DuDyA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,216,1716274800"; d="scan'208";a="54810600" Received: from tassilo.jf.intel.com ([10.54.38.190]) by fmviesa003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jul 2024 21:37:57 -0700 From: Andi Kleen To: gcc-patches@gcc.gnu.org Cc: polacek@redhat.com, josmyers@redhat.com, jason@redhat.com, Andi Kleen Subject: [PATCH v10 3/3] Add tests for C/C++ musttail attributes Date: Wed, 17 Jul 2024 21:30:01 -0700 Message-ID: <20240718043750.2480283-4-ak@linux.intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240718043750.2480283-1-ak@linux.intel.com> References: <20240718043750.2480283-1-ak@linux.intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-0.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_NONE, TXREP, UNWANTED_LANGUAGE_BODY 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.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org Some adopted from the existing C musttail plugin tests. Also extends the ability to query the sibcall capabilities of the target. gcc/testsuite/ChangeLog: * testsuite/lib/target-supports.exp (check_effective_target_struct_tail_call): New function. * c-c++-common/musttail1.c: New test. * c-c++-common/musttail2.c: New test. * c-c++-common/musttail3.c: New test. * c-c++-common/musttail4.c: New test. * c-c++-common/musttail7.c: New test. * c-c++-common/musttail8.c: New test. * g++.dg/musttail6.C: New test. * g++.dg/musttail9.C: New test. * g++.dg/musttail10.C: New test. * g++.dg/musttail11.C: New test. --- gcc/testsuite/c-c++-common/musttail1.c | 14 ++++++ gcc/testsuite/c-c++-common/musttail2.c | 33 ++++++++++++++ gcc/testsuite/c-c++-common/musttail3.c | 29 +++++++++++++ gcc/testsuite/c-c++-common/musttail4.c | 17 ++++++++ gcc/testsuite/c-c++-common/musttail5.c | 28 ++++++++++++ gcc/testsuite/c-c++-common/musttail7.c | 14 ++++++ gcc/testsuite/c-c++-common/musttail8.c | 17 ++++++++ gcc/testsuite/g++.dg/musttail10.C | 40 +++++++++++++++++ gcc/testsuite/g++.dg/musttail11.C | 33 ++++++++++++++ gcc/testsuite/g++.dg/musttail6.C | 60 ++++++++++++++++++++++++++ gcc/testsuite/g++.dg/musttail9.C | 10 +++++ gcc/testsuite/lib/target-supports.exp | 9 ++++ 12 files changed, 304 insertions(+) create mode 100644 gcc/testsuite/c-c++-common/musttail1.c create mode 100644 gcc/testsuite/c-c++-common/musttail2.c create mode 100644 gcc/testsuite/c-c++-common/musttail3.c create mode 100644 gcc/testsuite/c-c++-common/musttail4.c create mode 100644 gcc/testsuite/c-c++-common/musttail5.c create mode 100644 gcc/testsuite/c-c++-common/musttail7.c create mode 100644 gcc/testsuite/c-c++-common/musttail8.c create mode 100644 gcc/testsuite/g++.dg/musttail10.C create mode 100644 gcc/testsuite/g++.dg/musttail11.C create mode 100644 gcc/testsuite/g++.dg/musttail6.C create mode 100644 gcc/testsuite/g++.dg/musttail9.C diff --git a/gcc/testsuite/c-c++-common/musttail1.c b/gcc/testsuite/c-c++-common/musttail1.c new file mode 100644 index 000000000000..74efcc2a0bc6 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail1.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +int __attribute__((noinline,noclone,noipa)) +callee (int i) +{ + return i * i; +} + +int __attribute__((noinline,noclone,noipa)) +caller (int i) +{ + [[gnu::musttail]] return callee (i + 1); +} diff --git a/gcc/testsuite/c-c++-common/musttail2.c b/gcc/testsuite/c-c++-common/musttail2.c new file mode 100644 index 000000000000..86f2c3d77404 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail2.c @@ -0,0 +1,33 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ + +struct box { char field[256]; int i; }; + +int __attribute__((noinline,noclone,noipa)) +test_2_callee (int i, struct box b) +{ + if (b.field[0]) + return 5; + return i * i; +} + +int __attribute__((noinline,noclone,noipa)) +test_2_caller (int i) +{ + struct box b; + [[gnu::musttail]] return test_2_callee (i + 1, b); /* { dg-error "cannot tail-call: " } */ +} + +extern void setjmp (void); +void +test_3 (void) +{ + [[gnu::musttail]] return setjmp (); /* { dg-error "cannot tail-call: " } */ +} + +extern float f7(void); + +int +test_6 (void) +{ + [[gnu::musttail]] return f7(); /* { dg-error "cannot tail-call: " } */ +} diff --git a/gcc/testsuite/c-c++-common/musttail3.c b/gcc/testsuite/c-c++-common/musttail3.c new file mode 100644 index 000000000000..ea9589c59ef2 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail3.c @@ -0,0 +1,29 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ + +extern int foo2 (int x, ...); + +struct str +{ + int a, b; +}; + +struct str +cstruct (int x) +{ + if (x < 10) + [[clang::musttail]] return cstruct (x + 1); + return ((struct str){ x, 0 }); +} + +int +foo (int x) +{ + if (x < 10) + [[clang::musttail]] return foo2 (x, 29); + if (x < 100) + { + int k = foo (x + 1); + [[clang::musttail]] return k; /* { dg-error "cannot tail-call: " } */ + } + return x; +} diff --git a/gcc/testsuite/c-c++-common/musttail4.c b/gcc/testsuite/c-c++-common/musttail4.c new file mode 100644 index 000000000000..23f4b5e1cd68 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail4.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ + +struct box { char field[64]; int i; }; + +struct box __attribute__((noinline,noclone,noipa)) +returns_struct (int i) +{ + struct box b; + b.i = i * i; + return b; +} + +int __attribute__((noinline,noclone)) +test_1 (int i) +{ + [[gnu::musttail]] return returns_struct (i * 5).i; /* { dg-error "cannot tail-call: " } */ +} diff --git a/gcc/testsuite/c-c++-common/musttail5.c b/gcc/testsuite/c-c++-common/musttail5.c new file mode 100644 index 000000000000..234da0d3f2a9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail5.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-std=c23" { target c } } */ +/* { dg-options "-std=gnu++11" { target c++ } } */ + +[[musttail]] int j; /* { dg-warning "attribute" } */ +__attribute__((musttail)) int k; /* { dg-warning "attribute" } */ + +void foo(void) +{ + [[gnu::musttail]] j++; /* { dg-warning "attribute" } */ + [[gnu::musttail]] if (k > 0) /* { dg-warning "attribute" } */ + [[gnu::musttail]] k++; /* { dg-warning "attribute" } */ +} + +int foo2(int p) +{ + [[gnu::musttail(1)]] return foo2(p + 1); /* { dg-error "\(before numeric constant|attribute\)" } */ +} + +int i; + +int foo3(void) +{ + [[musttail]] i++; /* { dg-warning "attribute" } */ + [[musttail]] if (i > 10) /* { dg-warning "attribute" } */ + [[musttail]] return foo2(i); /* { dg-warning "attribute" } */ + return 0; +} diff --git a/gcc/testsuite/c-c++-common/musttail7.c b/gcc/testsuite/c-c++-common/musttail7.c new file mode 100644 index 000000000000..c753a3fe9b2a --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail7.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +void __attribute__((noipa)) f() {} + +void f2() +{ + [[gnu::musttail]] return f2(); +} + +void f3() +{ + [[gnu::musttail]] return f(); +} diff --git a/gcc/testsuite/c-c++-common/musttail8.c b/gcc/testsuite/c-c++-common/musttail8.c new file mode 100644 index 000000000000..9fa10e0b54c4 --- /dev/null +++ b/gcc/testsuite/c-c++-common/musttail8.c @@ -0,0 +1,17 @@ +/* { dg-do compile { target { tail_call && { c || c++11 } } } } */ + +float f1(void); + +int f2(void) +{ + [[gnu::musttail]] return f1 (); /* { dg-error "changed after call" } */ +} + + +int f3(int *); + +int f4(void) +{ + int x; + [[gnu::musttail]] return f3(&x); /* { dg-error "\(refers to locals|other reasons\)" } */ +} diff --git a/gcc/testsuite/g++.dg/musttail10.C b/gcc/testsuite/g++.dg/musttail10.C new file mode 100644 index 000000000000..ff7fcc7d8755 --- /dev/null +++ b/gcc/testsuite/g++.dg/musttail10.C @@ -0,0 +1,40 @@ +/* { dg-do compile { target { tail_call } } } */ +/* { dg-options "-std=gnu++11" } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +template T f(); + +double g() { [[gnu::musttail]] return f(); } /* { dg-error "cannot tail-call" } */ + +template +__attribute__((noinline, noclone, noipa)) +T g1() { [[gnu::musttail]] return f(); } /* { dg-error "target is not able" "" { target powerpc*-*-* } } */ + +template +__attribute__((noinline, noclone, noipa)) +T g2() { [[gnu::musttail]] return f(); } + +template +__attribute__((noinline, noclone, noipa)) +/* Would work with -O1. */ +T g3() { [[gnu::musttail]] return f(); } /* { dg-error "cannot tail-call" } */ + +template +__attribute__((noinline, noclone, noipa)) +T g4() { [[gnu::musttail]] return f(); } /* { dg-error "cannot tail-call" } */ + +class C +{ + double x; +public: + C(double x) : x(x) {} + ~C() { asm("":::"memory"); } +}; + +int main() +{ + g1(); + g2(); + g3(); + g4(); +} diff --git a/gcc/testsuite/g++.dg/musttail11.C b/gcc/testsuite/g++.dg/musttail11.C new file mode 100644 index 000000000000..1779e3287a93 --- /dev/null +++ b/gcc/testsuite/g++.dg/musttail11.C @@ -0,0 +1,33 @@ +/* { dg-do compile { target { tail_call } } } */ +/* { dg-options "-std=gnu++11" } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +template T f(); + +class C +{ + double x; +public: + C(double x) : x(x) {} + ~C() { asm("":::"memory"); } + operator int() { return x; } +}; + +template +__attribute__((noinline, noclone, noipa)) +T g5() { [[gnu::musttail]] return f (); } /* { dg-error "cannot tail-call" } */ + +C h(); + +__attribute__((noinline, noclone, noipa)) +int g6() { [[gnu::musttail]] return h (); } /* { dg-error "cannot tail-call" } */ + +__attribute__((noinline, noclone, noipa)) +C g7() { [[gnu::musttail]] return h (); } /* { dg-error "cannot tail-call" } */ + +int main() +{ + g5 (); + g6 (); + g7 (); +} diff --git a/gcc/testsuite/g++.dg/musttail6.C b/gcc/testsuite/g++.dg/musttail6.C new file mode 100644 index 000000000000..434a54a441c8 --- /dev/null +++ b/gcc/testsuite/g++.dg/musttail6.C @@ -0,0 +1,60 @@ +/* { dg-do compile { target { struct_tail_call } } } */ +/* A lot of architectures will not run this due to PR115606 and PR115607 */ +/* { dg-skip-if "powerpc does not support sibcall to templates" { powerpc*-*-* } } */ +/* { dg-options "-std=gnu++11" } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +class Foo { +public: + int a, b; + Foo(int a, int b) : a(a), b(b) {} +}; + +Foo __attribute__((noinline,noclone,noipa)) +callee (int i) +{ + return Foo(i, i+1); +} + +Foo __attribute__((noinline,noclone,noipa)) +caller (int i) +{ + [[gnu::musttail]] return callee (i + 1); +} + +template +T __attribute__((noinline,noclone,noipa)) foo (T i) +{ + return i + 1; +} + +int +caller2 (int k) +{ + [[gnu::musttail]] return foo(1); +} + +template +T caller3 (T v) +{ + [[gnu::musttail]] return foo(v); +} + +int call3(int i) +{ + [[gnu::musttail]] return caller3(i + 1); +} + +struct Bar { + int a; + Bar(int a) : a(a) {} + Bar operator+(Bar o) { return Bar(a + o.a); } +}; + +#if __OPTIMIZE__ >= 1 +Bar +caller4 (Bar k) +{ + [[gnu::musttail]] return caller3(Bar(99)); +} +#endif diff --git a/gcc/testsuite/g++.dg/musttail9.C b/gcc/testsuite/g++.dg/musttail9.C new file mode 100644 index 000000000000..fb0262e751be --- /dev/null +++ b/gcc/testsuite/g++.dg/musttail9.C @@ -0,0 +1,10 @@ +/* { dg-do compile { target { tail_call } } } */ +/* { dg-options "-std=gnu++11" } */ +/* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ + +extern void foo(); + +void f() noexcept +{ + [[gnu::musttail]] return foo(); /* { dg-error "call may throw exception that does not propagate" } */ +} diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp index daa0c75d2bc3..37188880f6c2 100644 --- a/gcc/testsuite/lib/target-supports.exp +++ b/gcc/testsuite/lib/target-supports.exp @@ -12744,6 +12744,15 @@ proc check_effective_target_tail_call { } { } {-O2 -fdump-rtl-expand-all}] ;# The "SIBCALL" note requires a detailed dump. } +# Return 1 if the target can perform tail-call optimizations for structures +proc check_effective_target_struct_tail_call { } { + return [check_no_messages_and_pattern tail_call ",SIBCALL" rtl-expand { + struct foo { int a, b }; + __attribute__((__noipa__)) struct foo foo (void) { return {}; } + __attribute__((__noipa__)) struct foo bar (void) { return foo(); } + } {-O2 -fdump-rtl-expand-all}] ;# The "SIBCALL" note requires a detailed dump. +} + # Return 1 if the target's calling sequence or its ABI # create implicit stack probes at or prior to function entry. proc check_effective_target_caller_implicit_probes { } {