From 978b62e554ffb4b34844c72d259ce71fcbd87591 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 18 May 2021 10:10:17 +0200 Subject: function: Set dummy DECL_ASSEMBLER_NAME in push_dummy_function [PR100580] Last year I've added cgraph_node::get_create calls for the dummy functions used for -fdump-passes, so that it interacts well with pass disabling/enabling which is cgraph uid based. Unfortunately, as the following testcase shows, when assembler hash is present, that wants to compute DECL_ASSEMBLER_NAME and the C++ FE is unprepared to handle it on the dummy functions which don't have DECL_NAME etc. The following patch fixes it by setting up a dummy DECL_ASSEMBLER_NAME on these, so that the FEs don't need to compute it. 2021-05-18 Jakub Jelinek PR c++/100580 * function.c (push_dummy_function): Set DECL_ARTIFICIAL and DECL_ASSEMBLER_NAME on the fn_decl. * g++.dg/other/pr100580.C: New test. --- gcc/function.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'gcc/function.c') diff --git a/gcc/function.c b/gcc/function.c index a3ed398..fc7b147 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4930,6 +4930,9 @@ push_dummy_function (bool with_decl) fn_result_decl = build_decl (UNKNOWN_LOCATION, RESULT_DECL, NULL_TREE, void_type_node); DECL_RESULT (fn_decl) = fn_result_decl; + DECL_ARTIFICIAL (fn_decl) = 1; + tree fn_name = get_identifier (" "); + SET_DECL_ASSEMBLER_NAME (fn_decl, fn_name); } else fn_decl = NULL_TREE; -- cgit v1.1 From 586d6f7aee0ba9faf3d9b7afd6ff89d57763a775 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 19 May 2021 18:27:05 +0200 Subject: Common API for accessing global and on-demand ranges. This patch provides a generic API for accessing global ranges. It is meant to replace get_range_info() and get_ptr_nonnull() with one common interface. It uses the same API as the ranger (class range_query), so there will now be one API for accessing local and global ranges alike. Follow-up patches will convert all users of get_range_info and get_ptr_nonnull to this API. For get_range_info, instead of: if (!POINTER_TYPE_P (TREE_TYPE (name)) && SSA_NAME_RANGE_INFO (name)) get_range_info (name, vr); You can now do: get_range_query (cfun)->range_of_expr (vr, name, [stmt]); ...as well as any other of the range_query methods (range_on_edge, range_of_stmt, value_of_expr, value_on_edge, value_on_stmt, etc). As per the API, range_of_expr will work on constants, SSA names, and anything we support in irange::supports_type_p(). For pointers, the interface is the same, so instead of: else if (POINTER_TYPE_P (TREE_TYPE (name)) && SSA_NAME_PTR_INFO (name)) { if (get_ptr_nonnull (name)) stuff(); } One can do: get_range_query (cfun)->range_of_expr (vr, name, [stmt]); if (vr.nonzero_p ()) stuff (); Along with this interface, we are providing a mechanism by which a pass can use an on-demand ranger transparently, without having to change its code. Of course, this assumes all get_range_info() and get_ptr_nonnull() users have been converted to the new API, which follow-up patches will do. If a pass would prefer to use an on-demand ranger with finer grained and context aware ranges, all it would have to do is call enable_ranger() at the beginning of the pass, and disable_ranger() at the end of the pass. Note, that to use context aware ranges, any user of range_of_expr() would need to pass additional context. For example, the optional gimple statement (or perhaps use range_on_edge or range_of_stmt). The observant reader will note that get_range_query is tied to a struct function, which may not be available in certain contexts, such as at RTL time, gimple-fold, or some other places where we may or may not have cfun set. For cases where we are sure there is no function, you can use get_global_range_query() instead of get_range_query(fun). The API is the same. For cases where a function may be called with or without a function, you could use the following idiom: range_query *query = cfun ? get_range_query (cfun) : get_global_range_query (); query->range_of_expr (range, expr, [stmt]); The default range query obtained by get_range_query() is the global range query, unless the user has enabled an on-demand ranger with enable_ranger(), in which case it will use the currently active ranger. That is, until disable_ranger() is called, at which point, we revert back to global ranges. We think this provides a generic way of accessing ranges, both globally and locally, without having to keep track of types, SSA_NAME_RANGE_INFO, and SSA_NAME_PTR_INFO. We also hope this can be used to transition passes from global to on-demand ranges when appropriate. gcc/ChangeLog: * function.c (allocate_struct_function): Set cfun->x_range_query. * function.h (struct function): Declare x_range_query. (get_range_query): New. (get_global_range_query): New. * gimple-range-cache.cc (ssa_global_cache::ssa_global_cache): Remove call to safe_grow_cleared. * gimple-range.cc (get_range_global): New. (gimple_range_global): Move from gimple-range.h. (get_global_range_query): New. (global_range_query::range_of_expr): New. (enable_ranger): New. (disable_ranger): New. * gimple-range.h (gimple_range_global): Move to gimple-range.cc. (class global_range_query): New. (enable_ranger): New. (disable_ranger): New. * gimple-ssa-evrp.c (evrp_folder::~evrp_folder): Rename dump_all_value_ranges to dump. * tree-vrp.c (vrp_prop::finalize): Same. * value-query.cc (range_query::dump): New. * value-query.h (range_query::dump): New. * vr-values.c (vr_values::dump_all_value_ranges): Rename to... (vr_values::dump): ...this. * vr-values.h (class vr_values): Rename dump_all_value_ranges to dump and make virtual. --- gcc/function.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'gcc/function.c') diff --git a/gcc/function.c b/gcc/function.c index fc7b147..6757695 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -82,6 +82,8 @@ along with GCC; see the file COPYING3. If not see #include "gimple.h" #include "options.h" #include "function-abi.h" +#include "value-range.h" +#include "gimple-range.h" /* So we can assign to cfun in this file. */ #undef cfun @@ -4856,6 +4858,8 @@ allocate_struct_function (tree fndecl, bool abstract_p) binding annotations among them. */ cfun->debug_nonbind_markers = lang_hooks.emits_begin_stmt && MAY_HAVE_DEBUG_MARKER_STMTS; + + cfun->x_range_query = &global_ranges; } /* This is like allocate_struct_function, but pushes a new cfun for FNDECL -- cgit v1.1 From 7232f7c4c2d727431096a7ecfcf4ad4db71dcf2a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 13 Jun 2021 14:00:12 -0400 Subject: expand: empty class return optimization [PR88529] The x86_64 psABI says that an empty class isn't passed or returned in memory or registers, so we shouldn't set %eax in this function. The df-scan hunk catches the case where we look at a 0-length reg and build a range the length of unsigned int, which happened before I changed assign_parms to match expand_function_end. PR target/88529 gcc/ChangeLog: * df-scan.c (df_ref_record): Check that regno < endregno. * function.c (assign_parms, expand_function_end): Do nothing with a TYPE_EMPTY_P result. gcc/testsuite/ChangeLog: * g++.target/i386/empty-class1.C: New test. --- gcc/function.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'gcc/function.c') diff --git a/gcc/function.c b/gcc/function.c index 6757695..6abaf3d 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3821,9 +3821,11 @@ assign_parms (tree fndecl) tree decl_result = DECL_RESULT (fndecl); rtx decl_rtl = DECL_RTL (decl_result); - if (REG_P (decl_rtl) - ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER - : DECL_REGISTER (decl_result)) + if ((REG_P (decl_rtl) + ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER + : DECL_REGISTER (decl_result)) + /* Unless the psABI says not to. */ + && !TYPE_EMPTY_P (TREE_TYPE (decl_result))) { rtx real_decl_rtl; @@ -5410,9 +5412,11 @@ expand_function_end (void) tree decl_result = DECL_RESULT (current_function_decl); rtx decl_rtl = DECL_RTL (decl_result); - if (REG_P (decl_rtl) - ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER - : DECL_REGISTER (decl_result)) + if ((REG_P (decl_rtl) + ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER + : DECL_REGISTER (decl_result)) + /* Unless the psABI says not to. */ + && !TYPE_EMPTY_P (TREE_TYPE (decl_result))) { rtx real_decl_rtl = crtl->return_rtx; complex_mode cmode; -- cgit v1.1 From 9b613e825d706b18f69e40edaee3eaf27d28f5cb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 22 Jun 2021 15:21:35 +0200 Subject: expand: Fix up empty class return optimization [PR101160] On Mon, Jun 14, 2021 at 11:24:22PM -0400, Jason Merrill via Gcc-patches wrote: > The x86_64 psABI says that an empty class isn't passed or returned in memory or > registers, so we shouldn't set %eax in this function. Is this a reasonable > place to implement that? Another possibility would be to remove the hack to > prevent i386.c:function_value_64 from returning NULL in this case and fix the > callers to deal, but that seems like more work. > > The df-scan hunk catches the case where we look at a 0-length reg and build > a range the length of unsigned int, which happened before I changed > assign_parms to match expand_function_end. The assign_params change unfortunately breaks e.g. the following testcase. The problem is that some passes (e.g. subreg lowering but assign_parms comments also talk about delayed slot scheduling) rely on crtl->return_rtx not to contain pseudo registers, and the assign_parms change results in the pseudo in there not being replaced with a hard register. The following patch instead clears the crtl->return_rtx if a function returns TYPE_EMPTY_P structure, that way (use (pseudo)) is not emitted into the IL and it is treated like more like functions returning void. I've also changed the effective target on the empty-class1.C testcase, so that it doesn't fail on x86_64-linux with -m32 testing. 2021-06-22 Jakub Jelinek PR middle-end/101160 * function.c (assign_parms): For decl_result with TYPE_EMPTY_P type clear crtl->return_rtx instead of keeping it referencing a pseudo. * g++.target/i386/empty-class1.C: Require lp64 effective target instead of x86_64-*-*. * g++.target/i386/empty-class2.C: New test. --- gcc/function.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'gcc/function.c') diff --git a/gcc/function.c b/gcc/function.c index 6abaf3d..00b2fe7 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3821,17 +3821,22 @@ assign_parms (tree fndecl) tree decl_result = DECL_RESULT (fndecl); rtx decl_rtl = DECL_RTL (decl_result); - if ((REG_P (decl_rtl) - ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER - : DECL_REGISTER (decl_result)) - /* Unless the psABI says not to. */ - && !TYPE_EMPTY_P (TREE_TYPE (decl_result))) + if (REG_P (decl_rtl) + ? REGNO (decl_rtl) >= FIRST_PSEUDO_REGISTER + : DECL_REGISTER (decl_result)) { rtx real_decl_rtl; - real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result), - fndecl, true); - REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; + /* Unless the psABI says not to. */ + if (TYPE_EMPTY_P (TREE_TYPE (decl_result))) + real_decl_rtl = NULL_RTX; + else + { + real_decl_rtl + = targetm.calls.function_value (TREE_TYPE (decl_result), + fndecl, true); + REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; + } /* The delay slot scheduler assumes that crtl->return_rtx holds the hard register containing the return value, not a temporary pseudo. */ -- cgit v1.1 From 818203714e8640ce29c886b5060c91b12ad3a7c4 Mon Sep 17 00:00:00 2001 From: Jeff Law Date: Tue, 20 Jul 2021 14:49:54 -0400 Subject: Attach MEM_EXPR information when flushing BLKmode args to the stack - V2 gcc/ * function.c (assign_parm_setup_block): Use adjust_address instead of change_address to preserve MEM_EXPR and friends. --- gcc/function.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'gcc/function.c') diff --git a/gcc/function.c b/gcc/function.c index 00b2fe7..af3d57b 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -3036,7 +3036,15 @@ assign_parm_setup_block (struct assign_parm_data_all *all, reg = gen_rtx_REG (word_mode, REGNO (entry_parm)); reg = convert_to_mode (mode, copy_to_reg (reg), 1); } - emit_move_insn (change_address (mem, mode, 0), reg); + + /* We use adjust_address to get a new MEM with the mode + changed. adjust_address is better than change_address + for this purpose because adjust_address does not lose + the MEM_EXPR associated with the MEM. + + If the MEM_EXPR is lost, then optimizations like DSE + assume the MEM escapes and thus is not subject to DSE. */ + emit_move_insn (adjust_address (mem, mode, 0), reg); } #ifdef BLOCK_REG_PADDING -- cgit v1.1