From patchwork Sun May 5 18:14:55 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 1931592 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=g2nonCCa; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; 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 [8.43.85.97]) (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 4VXXm91V2Jz1xnS for ; Mon, 6 May 2024 04:16:09 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 549483858435 for ; Sun, 5 May 2024 18:16:07 +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.9]) by sourceware.org (Postfix) with ESMTPS id 532CD3858D35 for ; Sun, 5 May 2024 18:15:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 532CD3858D35 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 532CD3858D35 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.9 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714932933; cv=none; b=FogapYf1xucPuDvbtiFu1KS8TX9nBPshnkx+65tGdo6fOvn2RmRsx0kKx3O+83XJ16K5/tRivlZuzc66seYOEeOU7fFFfKtj0kgHfvJ0bfW+3fSNMoXqck0kygFmIno7hbjbfcoe9zhbFlDZrn3S5VY+0YzvxPyfTnz4YgS5MpE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1714932933; c=relaxed/simple; bh=9J9sbtv8A6LHNs0ilXvbSjKAkPTTRw/1lhn8CnwGQ84=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=TGJzzu1jo/tsG/Z++HGz0v3JkdrTiQPg2cyOgMsXYjq74j8Z6WJ37hKSwoyxqOf5R2GMNpJOvQ6gd268mp2Fomt3qSnBYQ4h+eGjpNVzKrzshT2FqMJ87jZ6Lzm9YxIZUeWO8jQk17U8CMNYWQJd0R9FcTVyew9u3+oTuswkddc= 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=1714932930; x=1746468930; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9J9sbtv8A6LHNs0ilXvbSjKAkPTTRw/1lhn8CnwGQ84=; b=g2nonCCaqD4AvA2Ceukw3CuvBa4EoMrSxValQr5D3nq4ZosnGUK5k7xv Bbov8uyFchDiJhA8w+bitd7MVMErzj/ByJR4f1WVUOvf0c2a597fcTtSh W54CshSWCNoy82BXo9ovstvimor7auW7UEZMl8Dxiw80rb/fpWS7g2ynF 7zaTYUvgGv5xHUtXIQ9kLDBO6yNnItoCmByejfYdEzgPSwWgTEFTuoPnW Q3Gaf684TBt14ZxoGH4SL3VXcswVHBsbUI+7J1MwzfjXvGSuMojnFuQz2 bPxRR9KFgCsNrIEvzSBoWDPr7b2XgIksoKShCcRfFyLMdj7pENgnRy6SA A==; X-CSE-ConnectionGUID: dc0Mn9AzQo+RYVG/why+Dw== X-CSE-MsgGUID: jf5/jfJrQ4W/mvs99Rmmag== X-IronPort-AV: E=McAfee;i="6600,9927,11064"; a="21356319" X-IronPort-AV: E=Sophos;i="6.07,256,1708416000"; d="scan'208";a="21356319" Received: from orviesa007.jf.intel.com ([10.64.159.147]) by fmvoesa103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 May 2024 11:15:26 -0700 X-CSE-ConnectionGUID: mZlHPADWRLSt8VR3NFO4Og== X-CSE-MsgGUID: MtosvtTPSFGodR+STJEouA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.07,256,1708416000"; d="scan'208";a="28457579" Received: from tassilo.jf.intel.com ([10.54.38.190]) by orviesa007-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 05 May 2024 11:15:25 -0700 From: Andi Kleen To: gcc-patches@gcc.gnu.org Cc: nathan@acm.org, josmyers@redhat.com, richard.sandiford@arm.com, jason@redhat.com, Andi Kleen Subject: [PATCH v5 2/5] C++: Support clang compatible [[musttail]] (PR83324) Date: Sun, 5 May 2024 11:14:55 -0700 Message-ID: <20240505181458.2903045-2-ak@linux.intel.com> X-Mailer: git-send-email 2.44.0 In-Reply-To: <20240505181458.2903045-1-ak@linux.intel.com> References: <20240505181458.2903045-1-ak@linux.intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.3 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 One problem is that tree-tailcall usually fails when optimization is disabled, which implies the attribute only really works with optimization on. But that seems to be a reasonable limitation. Passes bootstrap and full test PR83324 gcc/cp/ChangeLog: * cp-tree.h (finish_return_stmt): Add musttail_p. (check_return_expr): Dito. * parser.cc (cp_parser_statement): Handle [[musttail]]. (cp_parser_std_attribute): Dito. (cp_parser_init_statement): Dito. (cp_parser_jump_statement): Dito. * semantics.cc (finish_return_stmt): Dito. * typeck.cc (check_return_expr): Handle musttail_p flag. --- gcc/cp/cp-tree.h | 4 ++-- gcc/cp/parser.cc | 30 ++++++++++++++++++++++++------ gcc/cp/semantics.cc | 6 +++--- gcc/cp/typeck.cc | 20 ++++++++++++++++++-- 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 52d6841559ca..ef5f0039ece2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7782,7 +7782,7 @@ extern void finish_while_stmt (tree); extern tree begin_do_stmt (void); extern void finish_do_body (tree); extern void finish_do_stmt (tree, tree, bool, tree, bool); -extern tree finish_return_stmt (tree); +extern tree finish_return_stmt (tree, bool = false); extern tree begin_for_scope (tree *); extern tree begin_for_stmt (tree, tree); extern void finish_init_stmt (tree); @@ -8294,7 +8294,7 @@ extern tree composite_pointer_type (const op_location_t &, tsubst_flags_t); extern tree merge_types (tree, tree); extern tree strip_array_domain (tree); -extern tree check_return_expr (tree, bool *, bool *); +extern tree check_return_expr (tree, bool *, bool *, bool); extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error); extern tree genericize_spaceship (location_t, tree, tree, tree); extern tree cp_build_binary_op (const op_location_t &, diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 66ce161252c7..e1bf92628ac3 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 *, bool = false); static void cp_parser_declaration_statement (cp_parser *); @@ -12734,9 +12734,27 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, NULL_TREE, false); break; + case RID_RETURN: + { + bool musttail_p = false; + std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); + 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); + } + statement = cp_parser_jump_statement (parser, musttail_p); + } + break; + case RID_BREAK: case RID_CONTINUE: - case RID_RETURN: case RID_CO_RETURN: case RID_GOTO: std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc); @@ -14782,7 +14800,7 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) return false; } -/* Parse a jump-statement. +/* Parse a jump-statement. MUSTTAIL_P indicates a musttail attribute. jump-statement: break ; @@ -14800,7 +14818,7 @@ cp_parser_init_statement (cp_parser *parser, tree *decl) 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, bool musttail_p) { tree statement = error_mark_node; cp_token *token; @@ -14884,7 +14902,7 @@ cp_parser_jump_statement (cp_parser* parser) else if (FNDECL_USED_AUTO (current_function_decl) && in_discarded_stmt) /* Don't deduce from a discarded return statement. */; else - statement = finish_return_stmt (expr); + statement = finish_return_stmt (expr, musttail_p); /* Look for the final `;'. */ cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON); } @@ -30189,7 +30207,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) /* Maybe we don't expect to see any arguments for this attribute. */ const attribute_spec *as = lookup_attribute_spec (TREE_PURPOSE (attribute)); - if (as && as->max_length == 0) + if ((as && as->max_length == 0) || is_attribute_p ("musttail", attr_id)) { error_at (token->location, "%qE attribute does not take any arguments", attr_id); diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index b8c2bf8771fc..cac1a949c7d3 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -1387,16 +1387,16 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll, } /* Finish a return-statement. The EXPRESSION returned, if any, is as - indicated. */ + indicated. MUSTTAIL_P indicates a mustcall attribute. */ tree -finish_return_stmt (tree expr) +finish_return_stmt (tree expr, bool musttail_p) { tree r; bool no_warning; bool dangling; - expr = check_return_expr (expr, &no_warning, &dangling); + expr = check_return_expr (expr, &no_warning, &dangling, musttail_p); if (error_operand_p (expr) || (flag_openmp && !check_omp_return ())) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index a25f8622651d..9a5668796d2e 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -11036,10 +11036,12 @@ maybe_warn_pessimizing_move (tree expr, tree type, bool return_p) the DECL_RESULT for the function. Set *NO_WARNING to true if code reaches end of non-void function warning shouldn't be issued on this RETURN_EXPR. Set *DANGLING to true if code returns the - address of a local variable. */ + address of a local variable. MUSTTAIL_P indicates a musttail + return. */ tree -check_return_expr (tree retval, bool *no_warning, bool *dangling) +check_return_expr (tree retval, bool *no_warning, bool *dangling, + bool musttail_p) { tree result; /* The type actually returned by the function. */ @@ -11053,6 +11055,20 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling) *no_warning = false; *dangling = false; + if (musttail_p) + { + tree t = retval; + if (TREE_CODE (t) == TARGET_EXPR) + t = TARGET_EXPR_INITIAL (retval); + if (TREE_CODE (t) != CALL_EXPR) + { + error_at (loc, "cannot tail-call: return value must be a call"); + return error_mark_node; + } + else + CALL_EXPR_MUST_TAIL_CALL (t) = 1; + } + /* A `volatile' function is one that isn't supposed to return, ever. (This is a G++ extension, used to get better code for functions that call the `volatile' function.) */