Add CLOBBER_EOL to mark storage end-of-life clobbers
This adds a flag to CONSTRUCTOR nodes indicating that for clobbers this marks the end-of-life of storage as opposed to just ending the lifetime of the object that occupied it. The dangling pointer diagnostics uses CLOBBERs but is confused by those emitted by the C++ frontend for example which emits them for the second purpose at the start of CTORs. The issue is also appearant for aarch64 in PR104092. Distinguishing the two cases is also necessary for the PR90348 fix. Since I'm going to add another flag I added an enum clobber_flags and a defaulted argument to build_clobber plus a convenient way to query the enum from the CTOR tree and specify it for gimple_clobber_p. Since 'CLOBBER' is already taken and I needed a name for the unspecified clobber we have now I used 'CLOBBER_UNDEF'. 2022-02-03 Richard Biener <rguenther@suse.de> PR middle-end/90348 PR middle-end/104092 gcc/ * tree-core.h (clobber_kind): New enum. (tree_base::u::bits::address_space): Document use in CONSTRUCTORs. * tree.h (CLOBBER_KIND): Add. (build_clobber): Add clobber kind argument, defaulted to CLOBBER_UNDEF. * tree.cc (build_clobber): Likewise. * gimple.h (gimple_clobber_p): New overload with specified kind. * tree-streamer-in.cc (streamer_read_tree_bitfields): Stream CLOBBER_KIND. * tree-streamer-out.cc (streamer_write_tree_bitfields): Likewise. * tree-pretty-print.cc (dump_generic_node): Mark EOL CLOBBERs. * gimplify.cc (gimplify_bind_expr): Build storage end-of-life clobbers with CLOBBER_EOL. (gimplify_target_expr): Likewise. * tree-inline.cc (expand_call_inline): Likewise. * tree-ssa-ccp.cc (insert_clobber_before_stack_restore): Likewise. * gimple-ssa-warn-access.cc (pass_waccess::check_stmt): Only treat CLOBBER_EOL clobbers as ending lifetime of storage. gcc/lto/ * lto-common.cc (compare_tree_sccs_1): Compare CLOBBER_KIND. gcc/testsuite/ * gcc.dg/pr87052.c: Adjust.
This commit is contained in:
parent
e78d98f76f
commit
551aa75778
|
@ -4328,7 +4328,8 @@ is_auto_decl (tree x)
|
|||
void
|
||||
pass_waccess::check_stmt (gimple *stmt)
|
||||
{
|
||||
if (m_check_dangling_p && gimple_clobber_p (stmt))
|
||||
if (m_check_dangling_p
|
||||
&& gimple_clobber_p (stmt, CLOBBER_EOL))
|
||||
{
|
||||
/* Ignore clobber statemts in blocks with exceptional edges. */
|
||||
basic_block bb = gimple_bb (stmt);
|
||||
|
|
|
@ -2939,6 +2939,15 @@ gimple_clobber_p (const gimple *s)
|
|||
&& TREE_CLOBBER_P (gimple_assign_rhs1 (s));
|
||||
}
|
||||
|
||||
/* Return true if S is a clobber statement. */
|
||||
|
||||
static inline bool
|
||||
gimple_clobber_p (const gimple *s, enum clobber_kind kind)
|
||||
{
|
||||
return gimple_clobber_p (s)
|
||||
&& CLOBBER_KIND (gimple_assign_rhs1 (s)) == kind;
|
||||
}
|
||||
|
||||
/* Return true if GS is a GIMPLE_CALL. */
|
||||
|
||||
static inline bool
|
||||
|
|
|
@ -1475,7 +1475,7 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
|
|||
&& !is_gimple_reg (t)
|
||||
&& flag_stack_reuse != SR_NONE)
|
||||
{
|
||||
tree clobber = build_clobber (TREE_TYPE (t));
|
||||
tree clobber = build_clobber (TREE_TYPE (t), CLOBBER_EOL);
|
||||
gimple *clobber_stmt;
|
||||
clobber_stmt = gimple_build_assign (t, clobber);
|
||||
gimple_set_location (clobber_stmt, end_locus);
|
||||
|
@ -6981,7 +6981,7 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
|
|||
{
|
||||
if (flag_stack_reuse == SR_ALL)
|
||||
{
|
||||
tree clobber = build_clobber (TREE_TYPE (temp));
|
||||
tree clobber = build_clobber (TREE_TYPE (temp), CLOBBER_EOL);
|
||||
clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber);
|
||||
gimple_push_cleanup (temp, clobber, false, pre_p, true);
|
||||
}
|
||||
|
|
|
@ -1309,7 +1309,10 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
|
|||
return false;
|
||||
|
||||
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
|
||||
compare_values (CONSTRUCTOR_NELTS);
|
||||
{
|
||||
compare_values (CLOBBER_KIND);
|
||||
compare_values (CONSTRUCTOR_NELTS);
|
||||
}
|
||||
|
||||
if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
|
||||
if (IDENTIFIER_LENGTH (t1) != IDENTIFIER_LENGTH (t2)
|
||||
|
|
|
@ -38,4 +38,4 @@ void test (void)
|
|||
{ dg-final { scan-tree-dump-times "c = \"\";" 1 "gimple" } }
|
||||
{ dg-final { scan-tree-dump-times "d = { *};" 1 "gimple" } }
|
||||
{ dg-final { scan-tree-dump-times "e = " 1 "gimple" } }
|
||||
{ dg-final { scan-tree-dump-times "e = {CLOBBER}" 1 "gimple" } } */
|
||||
{ dg-final { scan-tree-dump-times "e = {CLOBBER\\(eol\\)}" 1 "gimple" } } */
|
||||
|
|
|
@ -963,6 +963,15 @@ enum annot_expr_kind {
|
|||
annot_expr_kind_last
|
||||
};
|
||||
|
||||
/* The kind of a TREE_CLOBBER_P CONSTRUCTOR node. */
|
||||
enum clobber_kind {
|
||||
/* Unspecified, this clobber acts as a store of an undefined value. */
|
||||
CLOBBER_UNDEF,
|
||||
/* This clobber ends the lifetime of the storage. */
|
||||
CLOBBER_EOL,
|
||||
CLOBBER_LAST
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------
|
||||
Type definitions
|
||||
---------------------------------------------------------------------------*/
|
||||
|
@ -1055,7 +1064,8 @@ struct GTY(()) tree_base {
|
|||
|
||||
/* This field is only used with TREE_TYPE nodes; the only reason it is
|
||||
present in tree_base instead of tree_type is to save space. The size
|
||||
of the field must be large enough to hold addr_space_t values. */
|
||||
of the field must be large enough to hold addr_space_t values.
|
||||
For CONSTRUCTOR nodes this holds the clobber_kind enum. */
|
||||
unsigned address_space : 8;
|
||||
} bits;
|
||||
|
||||
|
|
|
@ -5138,7 +5138,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
|
|||
&& !is_gimple_reg (*varp)
|
||||
&& !(id->debug_map && id->debug_map->get (p)))
|
||||
{
|
||||
tree clobber = build_clobber (TREE_TYPE (*varp));
|
||||
tree clobber = build_clobber (TREE_TYPE (*varp), CLOBBER_EOL);
|
||||
gimple *clobber_stmt;
|
||||
clobber_stmt = gimple_build_assign (*varp, clobber);
|
||||
gimple_set_location (clobber_stmt, gimple_location (stmt));
|
||||
|
@ -5207,7 +5207,7 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id,
|
|||
&& !is_gimple_reg (id->retvar)
|
||||
&& !stmt_ends_bb_p (stmt))
|
||||
{
|
||||
tree clobber = build_clobber (TREE_TYPE (id->retvar));
|
||||
tree clobber = build_clobber (TREE_TYPE (id->retvar), CLOBBER_EOL);
|
||||
gimple *clobber_stmt;
|
||||
clobber_stmt = gimple_build_assign (id->retvar, clobber);
|
||||
gimple_set_location (clobber_stmt, gimple_location (old_stmt));
|
||||
|
|
|
@ -2500,7 +2500,11 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
|
|||
}
|
||||
pp_left_brace (pp);
|
||||
if (TREE_CLOBBER_P (node))
|
||||
pp_string (pp, "CLOBBER");
|
||||
{
|
||||
pp_string (pp, "CLOBBER");
|
||||
if (CLOBBER_KIND (node) == CLOBBER_EOL)
|
||||
pp_string (pp, "(eol)");
|
||||
}
|
||||
else if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE
|
||||
|| TREE_CODE (TREE_TYPE (node)) == UNION_TYPE)
|
||||
is_struct_init = true;
|
||||
|
|
|
@ -2505,7 +2505,7 @@ insert_clobber_before_stack_restore (tree saved_val, tree var,
|
|||
FOR_EACH_IMM_USE_STMT (stmt, iter, saved_val)
|
||||
if (gimple_call_builtin_p (stmt, BUILT_IN_STACK_RESTORE))
|
||||
{
|
||||
clobber = build_clobber (TREE_TYPE (var));
|
||||
clobber = build_clobber (TREE_TYPE (var), CLOBBER_EOL);
|
||||
clobber_stmt = gimple_build_assign (var, clobber);
|
||||
|
||||
i = gsi_for_stmt (stmt);
|
||||
|
|
|
@ -559,6 +559,8 @@ streamer_read_tree_bitfields (class lto_input_block *ib,
|
|||
|
||||
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
|
||||
{
|
||||
CLOBBER_KIND (expr)
|
||||
= bp_unpack_enum (&bp, clobber_kind, CLOBBER_LAST);
|
||||
unsigned HOST_WIDE_INT length = bp_unpack_var_len_unsigned (&bp);
|
||||
if (length > 0)
|
||||
vec_safe_grow (CONSTRUCTOR_ELTS (expr), length, true);
|
||||
|
|
|
@ -504,7 +504,10 @@ streamer_write_tree_bitfields (struct output_block *ob, tree expr)
|
|||
cl_optimization_stream_out (ob, &bp, TREE_OPTIMIZATION (expr));
|
||||
|
||||
if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
|
||||
bp_pack_var_len_unsigned (&bp, CONSTRUCTOR_NELTS (expr));
|
||||
{
|
||||
bp_pack_enum (&bp, clobber_kind, CLOBBER_LAST, CLOBBER_KIND (expr));
|
||||
bp_pack_var_len_unsigned (&bp, CONSTRUCTOR_NELTS (expr));
|
||||
}
|
||||
|
||||
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)
|
||||
/* Don't stream these when passing things to a different target. */
|
||||
|
|
|
@ -2311,10 +2311,11 @@ build_constructor_va (tree type, int nelts, ...)
|
|||
/* Return a node of type TYPE for which TREE_CLOBBER_P is true. */
|
||||
|
||||
tree
|
||||
build_clobber (tree type)
|
||||
build_clobber (tree type, enum clobber_kind kind)
|
||||
{
|
||||
tree clobber = build_constructor (type, NULL);
|
||||
TREE_THIS_VOLATILE (clobber) = true;
|
||||
CLOBBER_KIND (clobber) = kind;
|
||||
return clobber;
|
||||
}
|
||||
|
||||
|
|
|
@ -1155,6 +1155,10 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
|
|||
#define TREE_CLOBBER_P(NODE) \
|
||||
(TREE_CODE (NODE) == CONSTRUCTOR && TREE_THIS_VOLATILE (NODE))
|
||||
|
||||
/* Return the clobber_kind of a CLOBBER CONSTRUCTOR. */
|
||||
#define CLOBBER_KIND(NODE) \
|
||||
(CONSTRUCTOR_CHECK (NODE)->base.u.bits.address_space)
|
||||
|
||||
/* Define fields and accessors for some nodes that represent expressions. */
|
||||
|
||||
/* Nonzero if NODE is an empty statement (NOP_EXPR <0>). */
|
||||
|
@ -4559,7 +4563,7 @@ extern tree build_constructor_single (tree, tree, tree);
|
|||
extern tree build_constructor_from_list (tree, tree);
|
||||
extern tree build_constructor_from_vec (tree, const vec<tree, va_gc> *);
|
||||
extern tree build_constructor_va (tree, int, ...);
|
||||
extern tree build_clobber (tree);
|
||||
extern tree build_clobber (tree, enum clobber_kind = CLOBBER_UNDEF);
|
||||
extern tree build_real_from_int_cst (tree, const_tree);
|
||||
extern tree build_real_from_wide (tree, const wide_int_ref &, signop);
|
||||
extern tree build_complex (tree, tree, tree);
|
||||
|
|
Loading…
Reference in New Issue