"libstdc++-v3/ChangeLog-2006" did not exist on "d99ae870ff9b0b5e1817a09a74302f94fcb87d06"
Newer
Older
static inline void
unmark_visited (tree *tp)
{
walk_tree (tp, unmark_visited_r, NULL, NULL);
}
/* Likewise, but mark all trees as not visited. */
static void
unvisit_body (tree fndecl)
{
struct cgraph_node *cgn = cgraph_node::get (fndecl);
unmark_visited (&DECL_SAVED_TREE (fndecl));
unmark_visited (&DECL_SIZE (DECL_RESULT (fndecl)));
unmark_visited (&DECL_SIZE_UNIT (DECL_RESULT (fndecl)));
for (cgn = first_nested_function (cgn);
cgn; cgn = next_nested_function (cgn))
}
/* Unconditionally make an unshared copy of EXPR. This is used when using
stored expressions which span multiple functions, such as BINFO_VTABLE,
as the normal unsharing process can't tell that they're shared. */
tree
unshare_expr (tree expr)
{
walk_tree (&expr, mostly_copy_tree_r, NULL, NULL);
return expr;
}
Richard Biener
committed
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
/* Worker for unshare_expr_without_location. */
static tree
prune_expr_location (tree *tp, int *walk_subtrees, void *)
{
if (EXPR_P (*tp))
SET_EXPR_LOCATION (*tp, UNKNOWN_LOCATION);
else
*walk_subtrees = 0;
return NULL_TREE;
}
/* Similar to unshare_expr but also prune all expression locations
from EXPR. */
tree
unshare_expr_without_location (tree expr)
{
walk_tree (&expr, mostly_copy_tree_r, NULL, NULL);
if (EXPR_P (expr))
walk_tree (&expr, prune_expr_location, NULL, NULL);
return expr;
}
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
/* Return the EXPR_LOCATION of EXPR, if it (maybe recursively) has
one, OR_ELSE otherwise. The location of a STATEMENT_LISTs
comprising at least one DEBUG_BEGIN_STMT followed by exactly one
EXPR is the location of the EXPR. */
static location_t
rexpr_location (tree expr, location_t or_else = UNKNOWN_LOCATION)
{
if (!expr)
return or_else;
if (EXPR_HAS_LOCATION (expr))
return EXPR_LOCATION (expr);
if (TREE_CODE (expr) != STATEMENT_LIST)
return or_else;
tree_stmt_iterator i = tsi_start (expr);
bool found = false;
while (!tsi_end_p (i) && TREE_CODE (tsi_stmt (i)) == DEBUG_BEGIN_STMT)
{
found = true;
tsi_next (&i);
}
if (!found || !tsi_one_before_end_p (i))
return or_else;
return rexpr_location (tsi_stmt (i), or_else);
}
/* Return TRUE iff EXPR (maybe recursively) has a location; see
rexpr_location for the potential recursion. */
static inline bool
rexpr_has_location (tree expr)
{
return rexpr_location (expr) != UNKNOWN_LOCATION;
}
/* WRAPPER is a code such as BIND_EXPR or CLEANUP_POINT_EXPR which can both
contain statements and have a value. Assign its value to a temporary
and give it void_type_node. Return the temporary, or NULL_TREE if
WRAPPER was already void. */
tree
voidify_wrapper_expr (tree wrapper, tree temp)
tree type = TREE_TYPE (wrapper);
if (type && !VOID_TYPE_P (type))
tree *p;
/* Set p to point to the body of the wrapper. Loop until we find
something that isn't a wrapper. */
for (p = &wrapper; p && *p; )
switch (TREE_CODE (*p))
case BIND_EXPR:
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
/* For a BIND_EXPR, the body is operand 1. */
p = &BIND_EXPR_BODY (*p);
break;
case CLEANUP_POINT_EXPR:
case TRY_FINALLY_EXPR:
case TRY_CATCH_EXPR:
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
p = &TREE_OPERAND (*p, 0);
break;
case STATEMENT_LIST:
{
tree_stmt_iterator i = tsi_last (*p);
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
}
break;
case COMPOUND_EXPR:
/* Advance to the last statement. Set all container types to
void. */
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
{
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
}
break;
case TRANSACTION_EXPR:
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
p = &TRANSACTION_EXPR_BODY (*p);
break;
default:
/* Assume that any tree upon which voidify_wrapper_expr is
directly called is a wrapper, and that its body is op0. */
if (p == &wrapper)
{
TREE_SIDE_EFFECTS (*p) = 1;
TREE_TYPE (*p) = void_type_node;
p = &TREE_OPERAND (*p, 0);
break;
}
goto out;
out:
if (p == NULL || IS_EMPTY_STMT (*p))
temp = NULL_TREE;
else if (temp)
/* The wrapper is on the RHS of an assignment that we're pushing
down. */
gcc_assert (TREE_CODE (temp) == INIT_EXPR
|| TREE_CODE (temp) == MODIFY_EXPR);
TREE_OPERAND (temp, 1) = *p;
*p = temp;
temp = create_tmp_var (type, "retval");
*p = build2 (INIT_EXPR, type, temp, *p);
}
return temp;
}
return NULL_TREE;
}
/* Prepare calls to builtins to SAVE and RESTORE the stack as well as
a temporary through which they communicate. */
build_stack_save_restore (gcall **save, gcall **restore)
tree tmp_var;
Michael Meissner
committed
*save = gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_SAVE), 0);
tmp_var = create_tmp_var (ptr_type_node, "saved_stack");
gimple_call_set_lhs (*save, tmp_var);
Michael Meissner
committed
= gimple_build_call (builtin_decl_implicit (BUILT_IN_STACK_RESTORE),
/* Generate IFN_ASAN_MARK call that poisons shadow of a for DECL variable. */
static tree
build_asan_poison_call_expr (tree decl)
{
/* Do not poison variables that have size equal to zero. */
tree unit_size = DECL_SIZE_UNIT (decl);
if (zerop (unit_size))
return NULL_TREE;
tree base = build_fold_addr_expr (decl);
return build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_ASAN_MARK,
void_type_node, 3,
build_int_cst (integer_type_node,
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
base, unit_size);
}
/* Generate IFN_ASAN_MARK call that would poison or unpoison, depending
on POISON flag, shadow memory of a DECL variable. The call will be
put on location identified by IT iterator, where BEFORE flag drives
position where the stmt will be put. */
static void
asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it,
bool before)
{
tree unit_size = DECL_SIZE_UNIT (decl);
tree base = build_fold_addr_expr (decl);
/* Do not poison variables that have size equal to zero. */
if (zerop (unit_size))
return;
/* It's necessary to have all stack variables aligned to ASAN granularity
bytes. */
gcc_assert (!hwasan_sanitize_p () || hwasan_sanitize_stack_p ());
unsigned shadow_granularity
= hwasan_sanitize_p () ? HWASAN_TAG_GRANULE_SIZE : ASAN_SHADOW_GRANULARITY;
if (DECL_ALIGN_UNIT (decl) <= shadow_granularity)
SET_DECL_ALIGN (decl, BITS_PER_UNIT * shadow_granularity);
HOST_WIDE_INT flags = poison ? ASAN_MARK_POISON : ASAN_MARK_UNPOISON;
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
gimple *g
= gimple_build_call_internal (IFN_ASAN_MARK, 3,
build_int_cst (integer_type_node, flags),
base, unit_size);
if (before)
gsi_insert_before (it, g, GSI_NEW_STMT);
else
gsi_insert_after (it, g, GSI_NEW_STMT);
}
/* Generate IFN_ASAN_MARK internal call that depending on POISON flag
either poisons or unpoisons a DECL. Created statement is appended
to SEQ_P gimple sequence. */
static void
asan_poison_variable (tree decl, bool poison, gimple_seq *seq_p)
{
gimple_stmt_iterator it = gsi_last (*seq_p);
bool before = false;
if (gsi_end_p (it))
before = true;
asan_poison_variable (decl, poison, &it, before);
}
/* Sort pair of VAR_DECLs A and B by DECL_UID. */
static int
sort_by_decl_uid (const void *a, const void *b)
{
const tree *t1 = (const tree *)a;
const tree *t2 = (const tree *)b;
int uid1 = DECL_UID (*t1);
int uid2 = DECL_UID (*t2);
if (uid1 < uid2)
return -1;
else if (uid1 > uid2)
return 1;
else
return 0;
}
/* Generate IFN_ASAN_MARK internal call for all VARIABLES
depending on POISON flag. Created statement is appended
to SEQ_P gimple sequence. */
static void
asan_poison_variables (hash_set<tree> *variables, bool poison, gimple_seq *seq_p)
{
unsigned c = variables->elements ();
if (c == 0)
return;
auto_vec<tree> sorted_variables (c);
for (hash_set<tree>::iterator it = variables->begin ();
it != variables->end (); ++it)
sorted_variables.safe_push (*it);
sorted_variables.qsort (sort_by_decl_uid);
unsigned i;
tree var;
FOR_EACH_VEC_ELT (sorted_variables, i, var)
{
asan_poison_variable (var, poison, seq_p);
/* Add use_after_scope_memory attribute for the variable in order
to prevent re-written into SSA. */
if (!lookup_attribute (ASAN_USE_AFTER_SCOPE_ATTRIBUTE,
DECL_ATTRIBUTES (var)))
DECL_ATTRIBUTES (var)
= tree_cons (get_identifier (ASAN_USE_AFTER_SCOPE_ATTRIBUTE),
integer_one_node,
DECL_ATTRIBUTES (var));
}
/* Gimplify a BIND_EXPR. Just voidify and recurse. */
static enum gimplify_status
gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p)
{
tree bind_expr = *expr_p;
Eric Botcazou
committed
bool old_keep_stack = gimplify_ctxp->keep_stack;
bool old_save_stack = gimplify_ctxp->save_stack;
tree t;
gimple_seq body, cleanup;
location_t start_locus = 0, end_locus = 0;
tree ret_clauses = NULL;
tree temp = voidify_wrapper_expr (bind_expr, NULL);
/* Mark variables seen in this bind expr. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t))
Richard Henderson
committed
{
Jakub Jelinek
committed
if (VAR_P (t))
{
struct gimplify_omp_ctx *ctx = gimplify_omp_ctxp;
/* Mark variable as local. */
if (ctx && ctx->region_type != ORT_NONE && !DECL_EXTERNAL (t))
if (! DECL_SEEN_IN_BIND_EXPR_P (t)
|| splay_tree_lookup (ctx->variables,
(splay_tree_key) t) == NULL)
{
Jakub Jelinek
committed
int flag = GOVD_LOCAL;
if (ctx->region_type == ORT_SIMD
&& TREE_ADDRESSABLE (t)
&& !TREE_STATIC (t))
Jakub Jelinek
committed
{
if (TREE_CODE (DECL_SIZE_UNIT (t)) != INTEGER_CST)
ctx->add_safelen1 = true;
else
flag = GOVD_PRIVATE;
}
omp_add_variable (ctx, t, flag | GOVD_SEEN);
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
}
/* Static locals inside of target construct or offloaded
routines need to be "omp declare target". */
if (TREE_STATIC (t))
for (; ctx; ctx = ctx->outer_context)
if ((ctx->region_type & ORT_TARGET) != 0)
{
if (!lookup_attribute ("omp declare target",
DECL_ATTRIBUTES (t)))
{
tree id = get_identifier ("omp declare target");
DECL_ATTRIBUTES (t)
= tree_cons (id, NULL_TREE, DECL_ATTRIBUTES (t));
varpool_node *node = varpool_node::get (t);
if (node)
{
node->offloadable = 1;
if (ENABLE_OFFLOADING && !DECL_EXTERNAL (t))
{
g->have_offload = true;
if (!in_lto_p)
vec_safe_push (offload_vars, t);
}
}
}
break;
}
DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
if (DECL_HARD_REGISTER (t) && !is_global_var (t) && cfun)
cfun->has_local_explicit_reg_vars = true;
Richard Henderson
committed
}
bind_stmt = gimple_build_bind (BIND_EXPR_VARS (bind_expr), NULL,
Eric Botcazou
committed
BIND_EXPR_BLOCK (bind_expr));
gimple_push_bind_expr (bind_stmt);
Eric Botcazou
committed
gimplify_ctxp->keep_stack = false;
gimplify_ctxp->save_stack = false;
/* Gimplify the body into the GIMPLE_BIND tuple's body. */
body = NULL;
gimplify_stmt (&BIND_EXPR_BODY (bind_expr), &body);
gimple_bind_set_body (bind_stmt, body);
/* Source location wise, the cleanup code (stack_restore and clobbers)
belongs to the end of the block, so propagate what we have. The
stack_save operation belongs to the beginning of block, which we can
infer from the bind_expr directly if the block has no explicit
assignment. */
if (BIND_EXPR_BLOCK (bind_expr))
{
end_locus = BLOCK_SOURCE_END_LOCATION (BIND_EXPR_BLOCK (bind_expr));
start_locus = BLOCK_SOURCE_LOCATION (BIND_EXPR_BLOCK (bind_expr));
}
if (start_locus == 0)
start_locus = EXPR_LOCATION (bind_expr);
cleanup = NULL;
stack_save = NULL;
Eric Botcazou
committed
/* If the code both contains VLAs and calls alloca, then we cannot reclaim
the stack space allocated to the VLAs. */
if (gimplify_ctxp->save_stack && !gimplify_ctxp->keep_stack)
gcall *stack_restore;
/* Save stack on entry and restore it on exit. Add a try_finally
build_stack_save_restore (&stack_save, &stack_restore);
gimple_set_location (stack_save, start_locus);
gimple_set_location (stack_restore, end_locus);
gimplify_seq_add_stmt (&cleanup, stack_restore);
}
/* Add clobbers for all variables that go out of scope. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = DECL_CHAIN (t))
{
Jakub Jelinek
committed
if (VAR_P (t)
&& !is_global_var (t)
&& DECL_CONTEXT (t) == current_function_decl)
if (!DECL_HARD_REGISTER (t)
&& !TREE_THIS_VOLATILE (t)
&& !DECL_HAS_VALUE_EXPR_P (t)
/* Only care for variables that have to be in memory. Others
will be rewritten into SSA names, hence moved to the
top-level. */
&& !is_gimple_reg (t)
&& flag_stack_reuse != SR_NONE)
{
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);
gimplify_seq_add_stmt (&cleanup, clobber_stmt);
}
if (flag_openacc && oacc_declare_returns != NULL)
{
tree key = t;
if (DECL_HAS_VALUE_EXPR_P (key))
{
key = DECL_VALUE_EXPR (key);
if (TREE_CODE (key) == INDIRECT_REF)
key = TREE_OPERAND (key, 0);
}
tree *c = oacc_declare_returns->get (key);
if (c != NULL)
{
if (ret_clauses)
OMP_CLAUSE_CHAIN (*c) = ret_clauses;
if (oacc_declare_returns->is_empty ())
{
delete oacc_declare_returns;
oacc_declare_returns = NULL;
}
}
}
if (asan_poisoned_variables != NULL
&& asan_poisoned_variables->contains (t))
{
asan_poisoned_variables->remove (t);
asan_poison_variable (t, true, &cleanup);
}
if (gimplify_ctxp->live_switch_vars != NULL
&& gimplify_ctxp->live_switch_vars->contains (t))
gimplify_ctxp->live_switch_vars->remove (t);
}
if (ret_clauses)
{
gomp_target *stmt;
gimple_stmt_iterator si = gsi_start (cleanup);
stmt = gimple_build_omp_target (NULL, GF_OMP_TARGET_KIND_OACC_DECLARE,
ret_clauses);
gsi_insert_seq_before_without_update (&si, stmt, GSI_NEW_STMT);
}
if (cleanup)
{
gimple_seq new_body;
new_body = NULL;
gs = gimple_build_try (gimple_bind_body (bind_stmt), cleanup,
GIMPLE_TRY_FINALLY);
if (stack_save)
gimplify_seq_add_stmt (&new_body, stack_save);
gimplify_seq_add_stmt (&new_body, gs);
gimple_bind_set_body (bind_stmt, new_body);
Eric Botcazou
committed
/* keep_stack propagates all the way up to the outermost BIND_EXPR. */
if (!gimplify_ctxp->keep_stack)
gimplify_ctxp->keep_stack = old_keep_stack;
gimplify_ctxp->save_stack = old_save_stack;
Eric Botcazou
committed
gimple_pop_bind_expr ();
gimplify_seq_add_stmt (pre_p, bind_stmt);
if (temp)
{
*expr_p = temp;
return GS_OK;
}
*expr_p = NULL_TREE;
return GS_ALL_DONE;
/* Maybe add early return predict statement to PRE_P sequence. */
static void
maybe_add_early_return_predict_stmt (gimple_seq *pre_p)
{
/* If we are not in a conditional context, add PREDICT statement. */
if (gimple_conditional_context ())
{
gimple *predict = gimple_build_predict (PRED_TREE_EARLY_RETURN,
NOT_TAKEN);
gimplify_seq_add_stmt (pre_p, predict);
}
}
/* Gimplify a RETURN_EXPR. If the expression to be returned is not a
GIMPLE value, it is assigned to a new temporary and the statement is
re-written to return the temporary.
PRE_P points to the sequence where side effects that must happen before
STMT should be stored. */
static enum gimplify_status
gimplify_return_expr (tree stmt, gimple_seq *pre_p)
tree ret_expr = TREE_OPERAND (stmt, 0);
Richard Henderson
committed
tree result_decl, result;
if (ret_expr == error_mark_node)
return GS_ERROR;
if (!ret_expr
|| TREE_CODE (ret_expr) == RESULT_DECL)
maybe_add_early_return_predict_stmt (pre_p);
greturn *ret = gimple_build_return (ret_expr);
copy_warning (ret, stmt);
gimplify_seq_add_stmt (pre_p, ret);
return GS_ALL_DONE;
}
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
Richard Henderson
committed
result_decl = NULL_TREE;
else if (TREE_CODE (ret_expr) == COMPOUND_EXPR)
{
/* Used in C++ for handling EH cleanup of the return value if a local
cleanup throws. Assume the front-end knows what it's doing. */
result_decl = DECL_RESULT (current_function_decl);
/* But crash if we end up trying to modify ret_expr below. */
ret_expr = NULL_TREE;
}
result_decl = TREE_OPERAND (ret_expr, 0);
/* See through a return by reference. */
if (TREE_CODE (result_decl) == INDIRECT_REF)
result_decl = TREE_OPERAND (result_decl, 0);
gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR
|| TREE_CODE (ret_expr) == INIT_EXPR)
&& TREE_CODE (result_decl) == RESULT_DECL);
Richard Henderson
committed
/* If aggregate_value_p is true, then we can return the bare RESULT_DECL.
Recall that aggregate_value_p is FALSE for any aggregate type that is
returned in registers. If we're returning values in registers, then
we don't want to extend the lifetime of the RESULT_DECL, particularly
across another call. In addition, for those aggregates for which
hard_function_value generates a PARALLEL, we'll die during normal
Richard Henderson
committed
expansion of structure assignments; there's special code in expand_return
to handle this case that does not exist in expand_expr. */
Eric Botcazou
committed
if (!result_decl)
result = NULL_TREE;
else if (aggregate_value_p (result_decl, TREE_TYPE (current_function_decl)))
{
if (!poly_int_tree_p (DECL_SIZE (result_decl)))
Eric Botcazou
committed
{
if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (result_decl)))
gimplify_type_sizes (TREE_TYPE (result_decl), pre_p);
/* Note that we don't use gimplify_vla_decl because the RESULT_DECL
should be effectively allocated by the caller, i.e. all calls to
this function must be subject to the Return Slot Optimization. */
gimplify_one_sizepos (&DECL_SIZE (result_decl), pre_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (result_decl), pre_p);
}
result = result_decl;
}
Richard Henderson
committed
else if (gimplify_ctxp->return_temp)
result = gimplify_ctxp->return_temp;
else
{
Jakub Jelinek
committed
result = create_tmp_reg (TREE_TYPE (result_decl));
Richard Henderson
committed
/* ??? With complex control flow (usually involving abnormal edges),
we can wind up warning about an uninitialized value for this. Due
to how this variable is constructed and initialized, this is never
true. Give up and never warn. */
suppress_warning (result, OPT_Wuninitialized);
Richard Henderson
committed
Richard Henderson
committed
gimplify_ctxp->return_temp = result;
}
/* Smash the lhs of the MODIFY_EXPR to the temporary we plan to use.
Richard Henderson
committed
Then gimplify the whole thing. */
if (result != result_decl)
TREE_OPERAND (ret_expr, 0) = result;
gimplify_and_add (TREE_OPERAND (stmt, 0), pre_p);
maybe_add_early_return_predict_stmt (pre_p);
ret = gimple_build_return (result);
copy_warning (ret, stmt);
gimplify_seq_add_stmt (pre_p, ret);
return GS_ALL_DONE;
}
/* Gimplify a variable-length array DECL. */
Jakub Jelinek
committed
static void
gimplify_vla_decl (tree decl, gimple_seq *seq_p)
Jakub Jelinek
committed
{
/* This is a variable-sized decl. Simplify its size and mark it
Jakub Jelinek
committed
tree t, addr, ptr_type;
gimplify_one_sizepos (&DECL_SIZE (decl), seq_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), seq_p);
Jakub Jelinek
committed
/* Don't mess with a DECL_VALUE_EXPR set by the front-end. */
if (DECL_HAS_VALUE_EXPR_P (decl))
return;
Jakub Jelinek
committed
/* All occurrences of this decl in final gimplified code will be
replaced by indirection. Setting DECL_VALUE_EXPR does two
things: First, it lets the rest of the gimplifier know what
replacement to use. Second, it lets the debug info know
where to find the value. */
ptr_type = build_pointer_type (TREE_TYPE (decl));
addr = create_tmp_var (ptr_type, get_name (decl));
DECL_IGNORED_P (addr) = 0;
t = build_fold_indirect_ref (addr);
TREE_THIS_NOTRAP (t) = 1;
Jakub Jelinek
committed
SET_DECL_VALUE_EXPR (decl, t);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
t = build_alloca_call_expr (DECL_SIZE_UNIT (decl), DECL_ALIGN (decl),
max_int_size_in_bytes (TREE_TYPE (decl)));
/* The call has been built for a variable-sized object. */
CALL_ALLOCA_FOR_VAR_P (t) = 1;
Jakub Jelinek
committed
t = fold_convert (ptr_type, t);
t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
Jakub Jelinek
committed
gimplify_and_add (t, seq_p);
/* Record the dynamic allocation associated with DECL if requested. */
if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
record_dynamic_alloc (decl);
Jakub Jelinek
committed
}
Andrew MacLeod
committed
/* A helper function to be called via walk_tree. Mark all labels under *TP
as being forced. To be called for DECL_INITIAL of static variables. */
static tree
force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
if (TYPE_P (*tp))
*walk_subtrees = 0;
if (TREE_CODE (*tp) == LABEL_DECL)
{
FORCED_LABEL (*tp) = 1;
cfun->has_forced_label_in_static = 1;
}
Andrew MacLeod
committed
return NULL_TREE;
}
/* Generate an initialization to automatic variable DECL based on INIT_TYPE.
Build a call to internal const function DEFERRED_INIT:
1st argument: SIZE of the DECL;
2nd argument: INIT_TYPE;
3rd argument: NAME of the DECL;
as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, NAME of the DECL). */
static void
gimple_add_init_for_auto_var (tree decl,
enum auto_init_type init_type,
gimple_seq *seq_p)
{
gcc_assert (auto_var_p (decl));
gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
location_t loc = EXPR_LOCATION (decl);
tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
tree init_type_node
= build_int_cst (integer_type_node, (int) init_type);
tree decl_name = NULL_TREE;
if (DECL_NAME (decl))
decl_name = build_string_literal (DECL_NAME (decl));
else
{
char *decl_name_anonymous = xasprintf ("D.%u", DECL_UID (decl));
decl_name = build_string_literal (decl_name_anonymous);
free (decl_name_anonymous);
}
tree call = build_call_expr_internal_loc (loc, IFN_DEFERRED_INIT,
TREE_TYPE (decl), 3,
decl_size, init_type_node,
decl_name);
gimplify_assign (decl, call, seq_p);
}
/* Generate padding initialization for automatic vairable DECL.
C guarantees that brace-init with fewer initializers than members
aggregate will initialize the rest of the aggregate as-if it were
static initialization. In turn static initialization guarantees
that padding is initialized to zero. So, we always initialize paddings
to zeroes regardless INIT_TYPE.
To do the padding initialization, we insert a call to
__builtin_clear_padding (&decl, 0, for_auto_init = true).
Note, we add an additional dummy argument for __builtin_clear_padding,
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
'for_auto_init' to distinguish whether this call is for automatic
variable initialization or not.
*/
static void
gimple_add_padding_init_for_auto_var (tree decl, bool is_vla,
gimple_seq *seq_p)
{
tree addr_of_decl = NULL_TREE;
tree fn = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING);
if (is_vla)
{
/* The temporary address variable for this vla should be
created in gimplify_vla_decl. */
gcc_assert (DECL_HAS_VALUE_EXPR_P (decl));
gcc_assert (TREE_CODE (DECL_VALUE_EXPR (decl)) == INDIRECT_REF);
addr_of_decl = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
}
else
{
mark_addressable (decl);
addr_of_decl = build_fold_addr_expr (decl);
}
gimple *call = gimple_build_call (fn, 2, addr_of_decl,
build_one_cst (TREE_TYPE (addr_of_decl)));
gimplify_seq_add_stmt (seq_p, call);
}
/* Return true if the DECL need to be automaticly initialized by the
compiler. */
static bool
is_var_need_auto_init (tree decl)
{
if (auto_var_p (decl)
&& (TREE_CODE (decl) != VAR_DECL
|| !DECL_HARD_REGISTER (decl))
&& (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
&& (!lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl)))
&& !OPAQUE_TYPE_P (TREE_TYPE (decl))
&& !is_empty_type (TREE_TYPE (decl)))
return true;
return false;
}
/* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
and initialization explicit. */
static enum gimplify_status
gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
{
tree stmt = *stmt_p;
tree decl = DECL_EXPR_DECL (stmt);
*stmt_p = NULL_TREE;
if (TREE_TYPE (decl) == error_mark_node)
return GS_ERROR;
if ((TREE_CODE (decl) == TYPE_DECL
Jakub Jelinek
committed
|| VAR_P (decl))
&& !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
Jakub Jelinek
committed
{
gimplify_type_sizes (TREE_TYPE (decl), seq_p);
if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
gimplify_type_sizes (TREE_TYPE (TREE_TYPE (decl)), seq_p);
}
/* ??? DECL_ORIGINAL_TYPE is streamed for LTO so it needs to be gimplified
in case its size expressions contain problematic nodes like CALL_EXPR. */
if (TREE_CODE (decl) == TYPE_DECL
&& DECL_ORIGINAL_TYPE (decl)
&& !TYPE_SIZES_GIMPLIFIED (DECL_ORIGINAL_TYPE (decl)))
Jakub Jelinek
committed
{
gimplify_type_sizes (DECL_ORIGINAL_TYPE (decl), seq_p);
if (TREE_CODE (DECL_ORIGINAL_TYPE (decl)) == REFERENCE_TYPE)
gimplify_type_sizes (TREE_TYPE (DECL_ORIGINAL_TYPE (decl)), seq_p);
}
Jakub Jelinek
committed
if (VAR_P (decl) && !DECL_EXTERNAL (decl))
{
tree init = DECL_INITIAL (decl);
/* Check whether a decl has FE created VALUE_EXPR here BEFORE
gimplify_vla_decl creates VALUE_EXPR for a vla decl.
If the decl has VALUE_EXPR that was created by FE (usually
C++FE), it's a proxy varaible, and FE already initialized
the VALUE_EXPR of it, we should not initialize it anymore. */
bool decl_had_value_expr_p = DECL_HAS_VALUE_EXPR_P (decl);
poly_uint64 size;
if (!poly_int_tree_p (DECL_SIZE_UNIT (decl), &size)
|| (!TREE_STATIC (decl)
&& flag_stack_check == GENERIC_STACK_CHECK
&& maybe_gt (size,
(unsigned HOST_WIDE_INT) STACK_CHECK_MAX_VAR_SIZE)))
{
gimplify_vla_decl (decl, seq_p);
is_vla = true;
}
if (asan_poisoned_variables
&& !is_vla
&& TREE_ADDRESSABLE (decl)
&& !TREE_STATIC (decl)
&& !DECL_HAS_VALUE_EXPR_P (decl)
Martin Liska
committed
&& DECL_ALIGN (decl) <= MAX_SUPPORTED_STACK_ALIGNMENT
Jakub Jelinek
committed
&& dbg_cnt (asan_use_after_scope)
&& !gimplify_omp_ctxp
/* GNAT introduces temporaries to hold return values of calls in
initializers of variables defined in other units, so the
declaration of the variable is discarded completely. We do not
want to issue poison calls for such dropped variables. */
&& (DECL_SEEN_IN_BIND_EXPR_P (decl)
|| (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)))
{
asan_poisoned_variables->add (decl);
asan_poison_variable (decl, false, seq_p);
if (!DECL_ARTIFICIAL (decl) && gimplify_ctxp->live_switch_vars)
gimplify_ctxp->live_switch_vars->add (decl);
}
Jason Merrill
committed
/* Some front ends do not explicitly declare all anonymous
artificial variables. We compensate here by declaring the
variables, though it would be better if the front ends would
explicitly declare them. */
if (!DECL_SEEN_IN_BIND_EXPR_P (decl)
&& DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE)
gimple_add_tmp_var (decl);
if (init && init != error_mark_node)
{
if (!TREE_STATIC (decl))
{
DECL_INITIAL (decl) = NULL_TREE;
init = build2 (INIT_EXPR, void_type_node, decl, init);
gimplify_and_add (init, seq_p);
ggc_free (init);
/* Clear TREE_READONLY if we really have an initialization. */
if (!DECL_INITIAL (decl)
&& !omp_privatize_by_reference (decl))
TREE_READONLY (decl) = 0;
}
else
/* We must still examine initializers for static variables
as they may contain a label address. */
walk_tree (&init, force_labels_r, NULL, NULL);
}
/* When there is no explicit initializer, if the user requested,
We should insert an artifical initializer for this automatic
variable. */
else if (is_var_need_auto_init (decl)
&& !decl_had_value_expr_p)
{
gimple_add_init_for_auto_var (decl,
flag_auto_var_init,
seq_p);
/* The expanding of a call to the above .DEFERRED_INIT will apply
block initialization to the whole space covered by this variable.
As a result, all the paddings will be initialized to zeroes
for zero initialization and 0xFE byte-repeatable patterns for
pattern initialization.
In order to make the paddings as zeroes for pattern init, We
should add a call to __builtin_clear_padding to clear the
paddings to zero in compatiple with CLANG.
We cannot insert this call if the variable is a gimple register
since __builtin_clear_padding will take the address of the
variable. As a result, if a long double/_Complex long double
variable will spilled into stack later, its padding is 0XFE. */
if (flag_auto_var_init == AUTO_INIT_PATTERN
&& !is_gimple_reg (decl)
&& clear_padding_type_may_have_padding_p (TREE_TYPE (decl)))
gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p);
}
}
return GS_ALL_DONE;
}
/* Gimplify a LOOP_EXPR. Normally this just involves gimplifying the body
and replacing the LOOP_EXPR with goto, but if the loop contains an
EXIT_EXPR, we need to append a label for it to jump to. */
static enum gimplify_status
gimplify_loop_expr (tree *expr_p, gimple_seq *pre_p)
{
tree saved_label = gimplify_ctxp->exit_label;
tree start_label = create_artificial_label (UNKNOWN_LOCATION);
gimplify_seq_add_stmt (pre_p, gimple_build_label (start_label));
gimplify_ctxp->exit_label = NULL_TREE;
gimplify_and_add (LOOP_EXPR_BODY (*expr_p), pre_p);
gimplify_seq_add_stmt (pre_p, gimple_build_goto (start_label));
if (gimplify_ctxp->exit_label)
gimplify_seq_add_stmt (pre_p,
gimple_build_label (gimplify_ctxp->exit_label));