On 8/6/19 2:42 PM, Martin Liška wrote: > On 8/5/19 3:46 PM, Marc Glisse wrote: >> On Mon, 5 Aug 2019, Martin Liška wrote: >> >>> You are right. It can really lead to confusion of the DCE. >>> >>> What we have is DECL_ABSTRACT_ORIGIN(decl) which we can use to indicate >>> operators >>> that were somehow modified by an IPA optimization. >> >> Looks similar to the cgraph_node->clone_of that Richard was talking about. I >> have no idea which one would be best. > > > Hm, strange that the ISRA clones don't have n->clone_of set. It's created > here: > > #0 cgraph_node::create (decl=<function_decl 0x7ffff721c300 > _ZN1AdlEPvd.isra.0>) at /home/marxin/Programming/gcc/gcc/profile-count.h:751 > #1 0x0000000000bc8342 in cgraph_node::create_version_clone > (this=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, > new_decl=<optimized out>, redirect_callers=..., bbs_to_copy=0x0, > suffix=0x1b74427 "isra") at > /home/marxin/Programming/gcc/gcc/cgraphclones.c:960 > #2 0x0000000000bc9b9a in cgraph_node::create_version_clone_with_body > (this=this@entry=<cgraph_node * const 0x7ffff7208000 "operator delete"/64>, > redirect_callers=redirect_callers@entry=..., tree_map=tree_map@entry=0x0, > args_to_skip=args_to_skip@entry=0x0, > skip_return=skip_return@entry=false, bbs_to_copy=bbs_to_copy@entry=0x0, > new_entry_block=<optimized out>, suffix=<optimized out>, > target_attributes=<optimized out>) at > /home/marxin/Programming/gcc/gcc/cgraphclones.c:1071 > #3 0x00000000010e4611 in modify_function (adjustments=..., node=<cgraph_node > * 0x7ffff7208000 "operator delete"/64>) at > /home/marxin/Programming/gcc/gcc/tree-sra.c:5493 > #4 ipa_early_sra () at /home/marxin/Programming/gcc/gcc/tree-sra.c:5731 > #5 (anonymous namespace)::pass_early_ipa_sra::execute (this=<optimized out>) > at /home/marxin/Programming/gcc/gcc/tree-sra.c:5778 > > @Martin, @Honza: Why do we not set clone_of in this transformation?
If I'm correct cgraph_node::clone is used for inline clones only? Anyway, I'm sending patch that considers only such new/delete operators that are not a clone of an original type. That should make the current DCE code more solid. Patch can bootstrap on x86_64-linux-gnu and survives regression tests. Ready to be installed? Thanks, Martin > >> >>> Do you believe it will be sufficient? >> >> In DCE only consider the operator delete that are not clones? (possibly the >> same for operator new? I don't know how much we can change the return value >> of a function in a clone) I guess that should work, and it wouldn't impact >> the common case with default, global operator new/delete. > > I tent to limit that the only cgraph nodes that are not clones. I'm going to > prepare a patch for it. > >> >> An alternative would be to clear the DECL_IS_OPERATOR_DELETE flag when >> creating a clone (possibly only if it modified the first parameter?). There >> is probably not much information in the fact that a function that doesn't >> even take a pointer used to be an operator delete. >> >> >> By the way, I just thought of something, now that we handle class-specific >> operator new/delete (but you could do the same with the global replacable >> ones as well): >> >> #include <stdio.h> >> int count = 0; >> struct A { >> __attribute__((malloc,noinline)) >> static void* operator new(unsigned long sz){++count;return ::operator >> new(sz);} >> static void operator delete(void* ptr){--count;::operator delete(ptr);} >> }; >> int main(){ >> delete new A; >> printf("%d\n",count); >> } >> >> If we do not inline anything, we can remove the pair and nothing touches >> count. If we inline both new and delete, we can then remove the inner pair >> instead, count increases and decreases, fine. If we inline only one of them, >> and DCE the mismatched pair new/delete, we get something inconsistent (count >> is -1). >> >> This seems to indicate we should check that the new and delete match >> somehow... >> >
>From 94110a47f0c13424d2e39d8f14bcc896a6097bd3 Mon Sep 17 00:00:00 2001 From: Martin Liska <mli...@suse.cz> Date: Tue, 6 Aug 2019 16:14:48 +0200 Subject: [PATCH] Detect not-cloned new/delete operators in DCE. gcc/ChangeLog: 2019-08-06 Martin Liska <mli...@suse.cz> * gimple.c (gimple_call_operator_delete_p): Remove. * gimple.h (gimple_call_operator_delete_p): Likewise. * tree-ssa-dce.c (operator_new_candidate_p): New. (operator_delete_candidate_p): Likewise. (mark_stmt_if_obviously_necessary): Use operator_new_candidate_p and operator_delete_candidate_p in order to detect operators that are not not clones. (mark_all_reaching_defs_necessary_1): Likewise. (propagate_necessity): Likewise. (eliminate_unnecessary_stmts): Likewise. --- gcc/gimple.c | 12 ---------- gcc/gimple.h | 1 - gcc/tree-ssa-dce.c | 59 ++++++++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 38 deletions(-) diff --git a/gcc/gimple.c b/gcc/gimple.c index 633ef512a19..684b8831b4d 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -2707,18 +2707,6 @@ gimple_builtin_call_types_compatible_p (const gimple *stmt, tree fndecl) return true; } -/* Return true when STMT is operator delete call. */ - -bool -gimple_call_operator_delete_p (const gcall *stmt) -{ - tree fndecl; - - if ((fndecl = gimple_call_fndecl (stmt)) != NULL_TREE) - return DECL_IS_OPERATOR_DELETE_P (fndecl); - return false; -} - /* Return true when STMT is builtins call. */ bool diff --git a/gcc/gimple.h b/gcc/gimple.h index 55f5d0d33d9..7a1e1f49099 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -1548,7 +1548,6 @@ extern alias_set_type gimple_get_alias_set (tree); extern bool gimple_ior_addresses_taken (bitmap, gimple *); extern bool gimple_builtin_call_types_compatible_p (const gimple *, tree); extern combined_fn gimple_call_combined_fn (const gimple *); -extern bool gimple_call_operator_delete_p (const gcall *); extern bool gimple_call_builtin_p (const gimple *); extern bool gimple_call_builtin_p (const gimple *, enum built_in_class); extern bool gimple_call_builtin_p (const gimple *, enum built_in_function); diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index afb7bd9dedc..05d30e6c839 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -114,6 +114,25 @@ static bool cfg_altered; /* When non-NULL holds map from basic block index into the postorder. */ static int *bb_postorder; +/* Return true when FNDECL is a new operator and not a clone. */ + +static bool +operator_new_candidate_p (tree fndecl) +{ + return (fndecl != NULL_TREE + && DECL_IS_OPERATOR_NEW_P (fndecl) + && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE); +} + +/* Return true when FNDECL is a delete operator and not a clone. */ + +static bool +operator_delete_candidate_p (tree fndecl) +{ + return (fndecl != NULL_TREE + && DECL_IS_OPERATOR_DELETE_P (fndecl) + && DECL_ABSTRACT_ORIGIN (fndecl) == NULL_TREE); +} /* True if we should treat any stmt with a vdef as necessary. */ @@ -248,7 +267,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive) if (callee != NULL_TREE && flag_allocation_dce - && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) + && operator_new_candidate_p (callee)) return; /* Most, but not all function calls are required. Function calls that @@ -613,8 +632,8 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED, } if (callee != NULL_TREE - && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee) - || DECL_IS_OPERATOR_DELETE_P (callee))) + && (operator_new_candidate_p (callee) + || operator_delete_candidate_p (callee))) return false; } @@ -806,15 +825,10 @@ propagate_necessity (bool aggressive) processing the argument. */ bool is_delete_operator = (is_gimple_call (stmt) - && gimple_call_operator_delete_p (as_a <gcall *> (stmt))); + && operator_delete_candidate_p (gimple_call_fndecl (as_a <gcall *> (stmt)))); if (is_delete_operator || gimple_call_builtin_p (stmt, BUILT_IN_FREE)) { - /* It can happen that a user delete operator has the pointer - argument optimized out already. */ - if (gimple_call_num_args (stmt) == 0) - continue; - tree ptr = gimple_call_arg (stmt, 0); gimple *def_stmt; tree def_callee; @@ -827,7 +841,7 @@ propagate_necessity (bool aggressive) && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC)) - || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee))) + || operator_new_candidate_p (def_callee))) { /* Delete operators can have alignment and (or) size as next arguments. When being a SSA_NAME, they must be marked @@ -900,8 +914,8 @@ propagate_necessity (bool aggressive) continue; if (callee != NULL_TREE - && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee) - || DECL_IS_OPERATOR_DELETE_P (callee))) + && (operator_new_candidate_p (callee) + || operator_delete_candidate_p (callee))) continue; /* Calls implicitly load from memory, their arguments @@ -1326,20 +1340,15 @@ eliminate_unnecessary_stmts (void) if (gimple_plf (stmt, STMT_NECESSARY) && (gimple_call_builtin_p (stmt, BUILT_IN_FREE) || (is_gimple_call (stmt) - && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))) + && operator_delete_candidate_p (gimple_call_fndecl (as_a <gcall *> (stmt)))))) { - /* It can happen that a user delete operator has the pointer - argument optimized out already. */ - if (gimple_call_num_args (stmt) > 0) + tree ptr = gimple_call_arg (stmt, 0); + if (TREE_CODE (ptr) == SSA_NAME) { - tree ptr = gimple_call_arg (stmt, 0); - if (TREE_CODE (ptr) == SSA_NAME) - { - gimple *def_stmt = SSA_NAME_DEF_STMT (ptr); - if (!gimple_nop_p (def_stmt) - && !gimple_plf (def_stmt, STMT_NECESSARY)) - gimple_set_plf (stmt, STMT_NECESSARY, false); - } + gimple *def_stmt = SSA_NAME_DEF_STMT (ptr); + if (!gimple_nop_p (def_stmt) + && !gimple_plf (def_stmt, STMT_NECESSARY)) + gimple_set_plf (stmt, STMT_NECESSARY, false); } } @@ -1394,7 +1403,7 @@ eliminate_unnecessary_stmts (void) && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC && !ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (call)))) - && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call)))) + && !operator_new_candidate_p (call)))) { something_changed = true; if (dump_file && (dump_flags & TDF_DETAILS)) -- 2.22.0