static int *bb_postorder;
+/* True if we should treat any stmt with a vdef as necessary. */
+
+static inline bool
+keep_all_vdefs_p ()
+{
+ return optimize_debug;
+}
+
/* If STMT is not already marked necessary, mark it, and add it to the
worklist if ADD_TO_WORKLIST is true. */
default:;
}
+
+ if (callee != NULL_TREE
+ && flag_allocation_dce
+ && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee))
+ return;
+
/* Most, but not all function calls are required. Function calls that
produce no result and have no side effects (i.e. const pure
functions) are unnecessary. */
mark_stmt_necessary (stmt, true);
return;
}
+ /* IFN_GOACC_LOOP calls are necessary in that they are used to
+ represent parameter (i.e. step, bound) of a lowered OpenACC
+ partitioned loop. But this kind of partitioned loop might not
+ survive from aggressive loop removal for it has loop exit and
+ is assumed to be finite. Therefore, we need to explicitly mark
+ these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */
+ if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP))
+ {
+ mark_stmt_necessary (stmt, true);
+ return;
+ }
if (!gimple_call_lhs (stmt))
return;
break;
return;
}
+ if (gimple_vdef (stmt) && keep_all_vdefs_p ())
+ {
+ mark_stmt_necessary (stmt, true);
+ return;
+ }
+
return;
}
/* Prevent the empty possibly infinite loops from being removed. */
if (aggressive)
{
- struct loop *loop;
+ class loop *loop;
if (mark_irreducible_loops ())
FOR_EACH_BB_FN (bb, cfun)
{
static void
mark_aliased_reaching_defs_necessary (gimple *stmt, tree ref)
{
+ /* Should have been caught before calling this function. */
+ gcc_checking_assert (!keep_all_vdefs_p ());
+
unsigned int chain;
ao_ref refd;
gcc_assert (!chain_ovfl);
default:;
}
+
+ if (callee != NULL_TREE
+ && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+ || DECL_IS_OPERATOR_DELETE_P (callee)))
+ return false;
}
if (! gimple_clobber_p (def_stmt))
static void
mark_all_reaching_defs_necessary (gimple *stmt)
{
+ /* Should have been caught before calling this function. */
+ gcc_checking_assert (!keep_all_vdefs_p ());
walk_aliased_vdefs (NULL, gimple_vuse (stmt),
mark_all_reaching_defs_necessary_1, NULL, &visited);
}
/* If this is a call to free which is directly fed by an
allocation function do not mark that necessary through
processing the argument. */
- if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ bool is_delete_operator
+ = (is_gimple_call (stmt)
+ && gimple_call_operator_delete_p (as_a <gcall *> (stmt)));
+ if (is_delete_operator
+ || gimple_call_builtin_p (stmt, BUILT_IN_FREE))
{
tree ptr = gimple_call_arg (stmt, 0);
gimple *def_stmt;
if (TREE_CODE (ptr) == SSA_NAME
&& is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
&& (def_callee = gimple_call_fndecl (def_stmt))
- && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
- && (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))
- continue;
+ && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
+ && (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)))
+ {
+ /* Delete operators can have alignment and (or) size as next
+ arguments. When being a SSA_NAME, they must be marked
+ as necessary. */
+ if (is_delete_operator && gimple_call_num_args (stmt) >= 2)
+ for (unsigned i = 1; i < gimple_call_num_args (stmt); i++)
+ {
+ tree arg = gimple_call_arg (stmt, i);
+ if (TREE_CODE (arg) == SSA_NAME)
+ mark_operand_necessary (arg);
+ }
+
+ continue;
+ }
}
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
if (!use)
continue;
+ /* No need to search for vdefs if we intrinsicly keep them all. */
+ if (keep_all_vdefs_p ())
+ continue;
+
/* If we dropped to simple mode make all immediately
reachable definitions necessary. */
if (chain_ovfl)
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
continue;
+ if (callee != NULL_TREE
+ && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)
+ || DECL_IS_OPERATOR_DELETE_P (callee)))
+ continue;
+
/* Calls implicitly load from memory, their arguments
in addition may explicitly perform memory loads. */
mark_all_reaching_defs_necessary (stmt);
defining statement of its argument is not necessary
(and thus is getting removed). */
if (gimple_plf (stmt, STMT_NECESSARY)
- && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ && (gimple_call_builtin_p (stmt, BUILT_IN_FREE)
+ || (is_gimple_call (stmt)
+ && gimple_call_operator_delete_p (as_a <gcall *> (stmt)))))
{
tree ptr = gimple_call_arg (stmt, 0);
if (TREE_CODE (ptr) == SSA_NAME)
did not mark as necessary, it will confuse the
special logic we apply to malloc/free pair removal. */
&& (!(call = gimple_call_fndecl (stmt))
- || DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
- || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
- && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
- && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
- && !ALLOCA_FUNCTION_CODE_P
- (DECL_FUNCTION_CODE (call)))))
+ || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
+ || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
+ && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+ && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
+ && !ALLOCA_FUNCTION_CODE_P
+ (DECL_FUNCTION_CODE (call))))
+ && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call))))
{
something_changed = true;
if (dump_file && (dump_flags & TDF_DETAILS))
update_stmt (stmt);
release_ssa_name (name);
- /* GOMP_SIMD_LANE (unless two argument) or ASAN_POISON
+ /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON
without lhs is not needed. */
if (gimple_call_internal_p (stmt))
switch (gimple_call_internal_fn (stmt))
{
case IFN_GOMP_SIMD_LANE:
- if (gimple_call_num_args (stmt) >= 2
- && !integer_nonzerop (gimple_call_arg (stmt, 1)))
+ if (gimple_call_num_args (stmt) >= 3
+ && !integer_nonzerop (gimple_call_arg (stmt, 2)))
break;
/* FALLTHRU */
case IFN_ASAN_POISON: