From patchwork Mon Jul 8 16:55:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andi Kleen X-Patchwork-Id: 1958055 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=Fp1MAKES; 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 4WHr4r47PHz1xpP for ; Tue, 9 Jul 2024 03:01:48 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id DD149384A459 for ; Mon, 8 Jul 2024 17:01:46 +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.11]) by sourceware.org (Postfix) with ESMTPS id 5B1B1384A4A8 for ; Mon, 8 Jul 2024 17:00:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 5B1B1384A4A8 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 5B1B1384A4A8 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720458057; cv=none; b=ZPeXEV8YTo1UgUauz+q2XfVF5B7rlxGZYumZZhcVtJjIlL6E15rO/WMAGq5KCyMfYNLLAsgzpaxdXlUH9DFVWl40TDw0IfbG/XL9V9ZdiQipB+WElNTyXekc0u5ioDDLPRdescQSDLHfVlYBChh8Kx6WUa1saHHshrSQrIGMkDE= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1720458057; c=relaxed/simple; bh=XjLO5Y+ROUJYE4A4iZy8ZKoyroVGGoc4md1nGHJH5M8=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=cP4rpXnp/TARZRGDUeWdrLQCYXh7V2zU4FjvaeJVEOTRKlnt0dytGBHao+y3aIQuO8vl5jTbixEMq9sKQ31+WNbVGbpEWhgdzenJorOS5FWFiAlVZ47YmEfZMjAt0Tfh0h1UtWwRkeDX92FGBgPSdZJTyKoy5HIekBKSmDUXxaA= 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=1720458054; x=1751994054; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=XjLO5Y+ROUJYE4A4iZy8ZKoyroVGGoc4md1nGHJH5M8=; b=Fp1MAKES5f1/krfzwTFycJ0JRAFW/PhsBdpNGHICq+u+U94/18q5lz/S JiXvtTzjAFaK1A9VKJpf+cLHgZma0uPmVyJBGScGR5+OBH1mTAh2sC2NK fXaeam6v1fZK3jJQU1oLHy+7eaOqjuas3PjyCBRjV4d7mjMZaGaMBOFkO gOT7tKiW4Ac6B83iRjTLys4QmJ742YBr7jcsq5kAedT7FIbRikv44z2Sq 31NpaEvya2WuA5dTUvxeok2Io04RAJ4jgFPSmR1j332Kk1FQjmQ0LxrcX 4XoscVD9WiqrNtO0qUvzrANM/vmXwossj60fDWBw+uAaMdR9zTbcrIvgh Q==; X-CSE-ConnectionGUID: m6rSM2+eQuag9Yy5ydw++A== X-CSE-MsgGUID: epKiDEo6RSCnSESPXRFszg== X-IronPort-AV: E=McAfee;i="6700,10204,11127"; a="28279685" X-IronPort-AV: E=Sophos;i="6.09,192,1716274800"; d="scan'208";a="28279685" Received: from orviesa010.jf.intel.com ([10.64.159.150]) by fmvoesa105.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jul 2024 10:00:37 -0700 X-CSE-ConnectionGUID: 4oHY8ycUQj+ZwSVHQu0l5w== X-CSE-MsgGUID: 7JRmFBxwTw+GQu1La8/iOQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.09,192,1716274800"; d="scan'208";a="47486298" Received: from tassilo.jf.intel.com ([10.54.38.190]) by orviesa010-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 08 Jul 2024 10:00:37 -0700 From: Andi Kleen To: gcc-patches@gcc.gnu.org Cc: richard.guenther@gmail.com, josmyers@redhat.com, polacek@redhat.com, jakub@redhat.com, Andi Kleen Subject: [PATCH v9 06/10] Enable musttail tail conversion even when not optimizing Date: Mon, 8 Jul 2024 09:55:58 -0700 Message-ID: <20240708170031.1621184-7-ak@linux.intel.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240708170031.1621184-1-ak@linux.intel.com> References: <20240708170031.1621184-1-ak@linux.intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-11.1 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 Enable the tailcall optimization for non optimizing builds, but in this case only checks calls that have the musttail attribute set. This makes musttail work without optimization. This is done with a new late musttail pass that is only active when not optimizing. The new pass relies on tree-cfg to discover musttails. This avoids a ~0.8% compiler run time penalty at -O0. gcc/ChangeLog: PR83324 * function.h (struct function): Add has_musttail. * lto-streamer-in.cc (input_struct_function_base): Stream has_musttail. * lto-streamer-out.cc (output_struct_function_base): Dito. * passes.def (pass_musttail): Add. * tree-cfg.cc (notice_special_calls): Record has_musttail. (clear_special_calls): Clear has_musttail. * tree-pass.h (make_pass_musttail): Add. * tree-tailcall.cc (find_tail_calls): Handle only_musttail argument. (tree_optimize_tail_calls_1): Pass on only_musttail. (execute_tail_calls): Pass only_musttail as false. (class pass_musttail): Add. (make_pass_musttail): Add. --- gcc/function.h | 3 ++ gcc/lto-streamer-in.cc | 1 + gcc/lto-streamer-out.cc | 1 + gcc/passes.def | 1 + gcc/tree-cfg.cc | 3 ++ gcc/tree-pass.h | 1 + gcc/tree-tailcall.cc | 68 +++++++++++++++++++++++++++++++++++------ 7 files changed, 69 insertions(+), 9 deletions(-) diff --git a/gcc/function.h b/gcc/function.h index c0ba6cc1531a..fbeadeaf4104 100644 --- a/gcc/function.h +++ b/gcc/function.h @@ -430,6 +430,9 @@ struct GTY(()) function { /* Nonzero when the tail call has been identified. */ unsigned int tail_call_marked : 1; + /* Has musttail marked calls. */ + unsigned int has_musttail : 1; + /* Nonzero if the current function contains a #pragma GCC unroll. */ unsigned int has_unroll : 1; diff --git a/gcc/lto-streamer-in.cc b/gcc/lto-streamer-in.cc index ad0ca24007a0..2e592be80823 100644 --- a/gcc/lto-streamer-in.cc +++ b/gcc/lto-streamer-in.cc @@ -1325,6 +1325,7 @@ input_struct_function_base (struct function *fn, class data_in *data_in, fn->calls_eh_return = bp_unpack_value (&bp, 1); fn->has_force_vectorize_loops = bp_unpack_value (&bp, 1); fn->has_simduid_loops = bp_unpack_value (&bp, 1); + fn->has_musttail = bp_unpack_value (&bp, 1); fn->assume_function = bp_unpack_value (&bp, 1); fn->va_list_fpr_size = bp_unpack_value (&bp, 8); fn->va_list_gpr_size = bp_unpack_value (&bp, 8); diff --git a/gcc/lto-streamer-out.cc b/gcc/lto-streamer-out.cc index d4f728094ed5..0be381abbd96 100644 --- a/gcc/lto-streamer-out.cc +++ b/gcc/lto-streamer-out.cc @@ -2290,6 +2290,7 @@ output_struct_function_base (struct output_block *ob, struct function *fn) bp_pack_value (&bp, fn->calls_eh_return, 1); bp_pack_value (&bp, fn->has_force_vectorize_loops, 1); bp_pack_value (&bp, fn->has_simduid_loops, 1); + bp_pack_value (&bp, fn->has_musttail, 1); bp_pack_value (&bp, fn->assume_function, 1); bp_pack_value (&bp, fn->va_list_fpr_size, 8); bp_pack_value (&bp, fn->va_list_gpr_size, 8); diff --git a/gcc/passes.def b/gcc/passes.def index b8c21b1e4351..49ab89387552 100644 --- a/gcc/passes.def +++ b/gcc/passes.def @@ -444,6 +444,7 @@ along with GCC; see the file COPYING3. If not see NEXT_PASS (pass_tsan_O0); NEXT_PASS (pass_sanopt); NEXT_PASS (pass_cleanup_eh); + NEXT_PASS (pass_musttail); NEXT_PASS (pass_lower_resx); NEXT_PASS (pass_nrv); NEXT_PASS (pass_gimple_isel); diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index 7fb7b92966be..e6fd1294b958 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -2290,6 +2290,8 @@ notice_special_calls (gcall *call) cfun->calls_alloca = true; if (flags & ECF_RETURNS_TWICE) cfun->calls_setjmp = true; + if (gimple_call_must_tail_p (call)) + cfun->has_musttail = true; } @@ -2301,6 +2303,7 @@ clear_special_calls (void) { cfun->calls_alloca = false; cfun->calls_setjmp = false; + cfun->has_musttail = false; } /* Remove PHI nodes associated with basic block BB and all edges out of BB. */ diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 9843d189d27d..8093b363bf14 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -368,6 +368,7 @@ extern gimple_opt_pass *make_pass_sra (gcc::context *ctxt); extern gimple_opt_pass *make_pass_sra_early (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tail_recursion (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tail_calls (gcc::context *ctxt); +extern gimple_opt_pass *make_pass_musttail (gcc::context *ctxt); extern gimple_opt_pass *make_pass_fix_loops (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tree_loop (gcc::context *ctxt); extern gimple_opt_pass *make_pass_tree_no_loop (gcc::context *ctxt); diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc index e9f7f8a12b3a..43e8c25215cb 100644 --- a/gcc/tree-tailcall.cc +++ b/gcc/tree-tailcall.cc @@ -408,10 +408,10 @@ static live_vars_map *live_vars; static vec live_vars_vec; /* Finds tailcalls falling into basic block BB. The list of found tailcalls is - added to the start of RET. */ + added to the start of RET. When ONLY_MUSTTAIL is set only handle musttail. */ static void -find_tail_calls (basic_block bb, struct tailcall **ret) +find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail) { tree ass_var = NULL_TREE, ret_var, func, param; gimple *stmt; @@ -445,6 +445,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret) if (is_gimple_call (stmt)) { call = as_a (stmt); + /* Handle only musttail calls when not optimizing. */ + if (only_musttail && !gimple_call_must_tail_p (call)) + return; ass_var = gimple_call_lhs (call); break; } @@ -467,7 +470,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret) edge_iterator ei; /* Recurse to the predecessors. */ FOR_EACH_EDGE (e, ei, bb->preds) - find_tail_calls (e->src, ret); + find_tail_calls (e->src, ret, only_musttail); return; } @@ -528,7 +531,8 @@ find_tail_calls (basic_block bb, struct tailcall **ret) func = gimple_call_fndecl (call); if (func && !fndecl_built_in_p (func) - && recursive_call_p (current_function_decl, func)) + && recursive_call_p (current_function_decl, func) + && !only_musttail) { tree arg; @@ -1094,10 +1098,11 @@ create_tailcall_accumulator (const char *label, basic_block bb, tree init) } /* Optimizes tail calls in the function, turning the tail recursion - into iteration. */ + into iteration. When ONLY_MUSTCALL is true only optimize mustcall + marked calls. */ static unsigned int -tree_optimize_tail_calls_1 (bool opt_tailcalls) +tree_optimize_tail_calls_1 (bool opt_tailcalls, bool only_mustcall) { edge e; bool phis_constructed = false; @@ -1117,7 +1122,7 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls) /* Only traverse the normal exits, i.e. those that end with return statement. */ if (safe_is_a (*gsi_last_bb (e->src))) - find_tail_calls (e->src, &tailcalls); + find_tail_calls (e->src, &tailcalls, only_mustcall); } if (live_vars) @@ -1228,7 +1233,7 @@ gate_tail_calls (void) static unsigned int execute_tail_calls (void) { - return tree_optimize_tail_calls_1 (true); + return tree_optimize_tail_calls_1 (true, false); } namespace { @@ -1261,7 +1266,7 @@ public: bool gate (function *) final override { return gate_tail_calls (); } unsigned int execute (function *) final override { - return tree_optimize_tail_calls_1 (false); + return tree_optimize_tail_calls_1 (false, false); } }; // class pass_tail_recursion @@ -1312,3 +1317,48 @@ make_pass_tail_calls (gcc::context *ctxt) { return new pass_tail_calls (ctxt); } + +namespace { + +const pass_data pass_data_musttail = +{ + GIMPLE_PASS, /* type */ + "musttail", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + ( PROP_cfg | PROP_ssa ), /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0, /* todo_flags_finish */ +}; + +class pass_musttail : public gimple_opt_pass +{ +public: + pass_musttail (gcc::context *ctxt) + : gimple_opt_pass (pass_data_musttail, ctxt) + {} + + /* opt_pass methods: */ + /* This pass is only used when the other tail call pass + doesn't run to make [[musttail]] still work. But only + run it when there is actually a musttail in the function. */ + bool gate (function *f) final override + { + return !flag_optimize_sibling_calls && f->has_musttail; + } + unsigned int execute (function *) final override + { + return tree_optimize_tail_calls_1 (true, true); + } + +}; // class pass_musttail + +} // anon namespace + +gimple_opt_pass * +make_pass_musttail (gcc::context *ctxt) +{ + return new pass_musttail (ctxt); +}