Newer
Older
Richard Henderson
committed
/* Gimplify the function's body. */
seq = NULL;
gimplify_stmt (&DECL_SAVED_TREE (fndecl), &seq);
outer_bind = gimple_seq_first_stmt (seq);
if (!outer_bind)
outer_bind = gimple_build_nop ();
gimplify_seq_add_stmt (&seq, outer_bind);
/* The body must contain exactly one statement, a GIMPLE_BIND. If this is
not the case, wrap everything in a GIMPLE_BIND to make it so. */
if (gimple_code (outer_bind) == GIMPLE_BIND
&& gimple_seq_first (seq) == gimple_seq_last (seq))
;
else
outer_bind = gimple_build_bind (NULL_TREE, seq, NULL);
DECL_SAVED_TREE (fndecl) = NULL_TREE;
Richard Henderson
committed
/* If we had callee-copies statements, insert them at the beginning
Richard Guenther
committed
of the function and clear DECL_VALUE_EXPR_P on the parameters. */
if (!gimple_seq_empty_p (parm_stmts))
Richard Henderson
committed
{
Richard Guenther
committed
tree parm;
gimplify_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind));
gimple_bind_set_body (outer_bind, parm_stmts);
Richard Guenther
committed
for (parm = DECL_ARGUMENTS (current_function_decl);
Richard Guenther
committed
if (DECL_HAS_VALUE_EXPR_P (parm))
{
DECL_HAS_VALUE_EXPR_P (parm) = 0;
DECL_IGNORED_P (parm) = 0;
}
Richard Henderson
committed
}
if (nonlocal_vlas)
{
pointer_set_destroy (nonlocal_vlas);
nonlocal_vlas = NULL;
}
pop_gimplify_context (outer_bind);
verify_gimple_in_seq (gimple_bind_body (outer_bind));
timevar_pop (TV_TREE_GIMPLIFY);
input_location = saved_location;
return outer_bind;
Joseph Myers
committed
8058
8059
8060
8061
8062
8063
8064
8065
8066
8067
8068
8069
8070
8071
8072
8073
8074
8075
8076
8077
8078
8079
8080
8081
8082
8083
8084
8085
8086
8087
8088
8089
8090
8091
8092
8093
8094
8095
8096
8097
typedef char *char_p; /* For DEF_VEC_P. */
DEF_VEC_P(char_p);
DEF_VEC_ALLOC_P(char_p,heap);
/* Return whether we should exclude FNDECL from instrumentation. */
static bool
flag_instrument_functions_exclude_p (tree fndecl)
{
VEC(char_p,heap) *vec;
vec = (VEC(char_p,heap) *) flag_instrument_functions_exclude_functions;
if (VEC_length (char_p, vec) > 0)
{
const char *name;
int i;
char *s;
name = lang_hooks.decl_printable_name (fndecl, 0);
FOR_EACH_VEC_ELT (char_p, vec, i, s)
if (strstr (name, s) != NULL)
return true;
}
vec = (VEC(char_p,heap) *) flag_instrument_functions_exclude_files;
if (VEC_length (char_p, vec) > 0)
{
const char *name;
int i;
char *s;
name = DECL_SOURCE_FILE (fndecl);
FOR_EACH_VEC_ELT (char_p, vec, i, s)
if (strstr (name, s) != NULL)
return true;
}
return false;
}
/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL
node for the function we want to gimplify.
Return the sequence of GIMPLE statements corresponding to the body
of FNDECL. */
void
gimplify_function_tree (tree fndecl)
{
Richard Henderson
committed
tree oldfn, parm, ret;
gimple_seq seq;
gimple bind;
gcc_assert (!gimple_body (fndecl));
oldfn = current_function_decl;
current_function_decl = fndecl;
if (DECL_STRUCT_FUNCTION (fndecl))
push_cfun (DECL_STRUCT_FUNCTION (fndecl));
else
push_struct_function (fndecl);
for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = DECL_CHAIN (parm))
Richard Henderson
committed
{
/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
as we find them. */
Andrew Pinski
committed
if ((TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (parm)) == VECTOR_TYPE)
Richard Henderson
committed
&& !TREE_THIS_VOLATILE (parm)
&& !needs_to_live_in_memory (parm))
Andrew Pinski
committed
DECL_GIMPLE_REG_P (parm) = 1;
Richard Henderson
committed
}
ret = DECL_RESULT (fndecl);
Andrew Pinski
committed
if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
|| TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
Richard Henderson
committed
&& !needs_to_live_in_memory (ret))
Andrew Pinski
committed
DECL_GIMPLE_REG_P (ret) = 1;
Richard Henderson
committed
bind = gimplify_body (fndecl, true);
/* The tree body of the function is no longer needed, replace it
with the new GIMPLE body. */
seq = gimple_seq_alloc ();
gimple_seq_add_stmt (&seq, bind);
gimple_set_body (fndecl, seq);
/* If we're instrumenting function entry/exit, then prepend the call to
the entry hook and wrap the whole function in a TRY_FINALLY_EXPR to
catch the exit hook. */
/* ??? Add some way to ignore exceptions for this TFE. */
if (flag_instrument_function_entry_exit
&& !DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (fndecl)
&& !flag_instrument_functions_exclude_p (fndecl))
tree x;
gimple new_bind;
gimple tf;
gimple_seq cleanup = NULL, body = NULL;
tree tmp_var;
gimple call;
Michael Meissner
committed
x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
Paul Wögerer
committed
call = gimple_build_call (x, 1, integer_zero_node);
tmp_var = create_tmp_var (ptr_type_node, "return_addr");
gimple_call_set_lhs (call, tmp_var);
gimplify_seq_add_stmt (&cleanup, call);
Michael Meissner
committed
x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_EXIT);
call = gimple_build_call (x, 2,
build_fold_addr_expr (current_function_decl),
tmp_var);
gimplify_seq_add_stmt (&cleanup, call);
tf = gimple_build_try (seq, cleanup, GIMPLE_TRY_FINALLY);
Michael Meissner
committed
x = builtin_decl_implicit (BUILT_IN_RETURN_ADDRESS);
Paul Wögerer
committed
call = gimple_build_call (x, 1, integer_zero_node);
tmp_var = create_tmp_var (ptr_type_node, "return_addr");
gimple_call_set_lhs (call, tmp_var);
gimplify_seq_add_stmt (&body, call);
Michael Meissner
committed
x = builtin_decl_implicit (BUILT_IN_PROFILE_FUNC_ENTER);
call = gimple_build_call (x, 2,
build_fold_addr_expr (current_function_decl),
tmp_var);
gimplify_seq_add_stmt (&body, call);
gimplify_seq_add_stmt (&body, tf);
new_bind = gimple_build_bind (NULL, body, gimple_bind_block (bind));
/* Clear the block for BIND, since it is no longer directly inside
the function, but within a try block. */
gimple_bind_set_block (bind, NULL);
/* Replace the current function body with the body
wrapped in the try/finally TF. */
seq = gimple_seq_alloc ();
gimple_seq_add_stmt (&seq, new_bind);
gimple_set_body (fndecl, seq);
DECL_SAVED_TREE (fndecl) = NULL_TREE;
cfun->curr_properties = PROP_gimple_any;
current_function_decl = oldfn;
8202
8203
8204
8205
8206
8207
8208
8209
8210
8211
8212
8213
8214
8215
8216
8217
8218
8219
8220
8221
8222
8223
8224
8225
8226
8227
/* Some transformations like inlining may invalidate the GIMPLE form
for operands. This function traverses all the operands in STMT and
gimplifies anything that is not a valid gimple operand. Any new
GIMPLE statements are inserted before *GSI_P. */
void
gimple_regimplify_operands (gimple stmt, gimple_stmt_iterator *gsi_p)
{
size_t i, num_ops;
tree orig_lhs = NULL_TREE, lhs, t;
gimple_seq pre = NULL;
gimple post_stmt = NULL;
struct gimplify_ctx gctx;
push_gimplify_context (&gctx);
gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
switch (gimple_code (stmt))
{
case GIMPLE_COND:
gimplify_expr (gimple_cond_lhs_ptr (stmt), &pre, NULL,
is_gimple_val, fb_rvalue);
gimplify_expr (gimple_cond_rhs_ptr (stmt), &pre, NULL,
is_gimple_val, fb_rvalue);
break;
case GIMPLE_SWITCH:
gimplify_expr (gimple_switch_index_ptr (stmt), &pre, NULL,
is_gimple_val, fb_rvalue);
break;
8232
8233
8234
8235
8236
8237
8238
8239
8240
8241
8242
8243
8244
8245
8246
8247
8248
8249
8250
8251
8252
8253
8254
8255
8256
8257
8258
8259
8260
8261
8262
8263
8264
8265
8266
8267
8268
8269
8270
8271
8272
8273
8274
8275
8276
8277
8278
8279
8280
8281
8282
8283
8284
8285
8286
8287
8288
8289
8290
8291
8292
8293
8294
8295
8296
8297
8298
8299
8300
8301
8302
8303
8304
8305
case GIMPLE_OMP_ATOMIC_LOAD:
gimplify_expr (gimple_omp_atomic_load_rhs_ptr (stmt), &pre, NULL,
is_gimple_val, fb_rvalue);
break;
case GIMPLE_ASM:
{
size_t i, noutputs = gimple_asm_noutputs (stmt);
const char *constraint, **oconstraints;
bool allows_mem, allows_reg, is_inout;
oconstraints
= (const char **) alloca ((noutputs) * sizeof (const char *));
for (i = 0; i < noutputs; i++)
{
tree op = gimple_asm_output_op (stmt, i);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
oconstraints[i] = constraint;
parse_output_constraint (&constraint, i, 0, 0, &allows_mem,
&allows_reg, &is_inout);
gimplify_expr (&TREE_VALUE (op), &pre, NULL,
is_inout ? is_gimple_min_lval : is_gimple_lvalue,
fb_lvalue | fb_mayfail);
}
for (i = 0; i < gimple_asm_ninputs (stmt); i++)
{
tree op = gimple_asm_input_op (stmt, i);
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (op)));
parse_input_constraint (&constraint, 0, 0, noutputs, 0,
oconstraints, &allows_mem, &allows_reg);
if (TREE_ADDRESSABLE (TREE_TYPE (TREE_VALUE (op))) && allows_mem)
allows_reg = 0;
if (!allows_reg && allows_mem)
gimplify_expr (&TREE_VALUE (op), &pre, NULL,
is_gimple_lvalue, fb_lvalue | fb_mayfail);
else
gimplify_expr (&TREE_VALUE (op), &pre, NULL,
is_gimple_asm_val, fb_rvalue);
}
}
break;
default:
/* NOTE: We start gimplifying operands from last to first to
make sure that side-effects on the RHS of calls, assignments
and ASMs are executed before the LHS. The ordering is not
important for other statements. */
num_ops = gimple_num_ops (stmt);
orig_lhs = gimple_get_lhs (stmt);
for (i = num_ops; i > 0; i--)
{
tree op = gimple_op (stmt, i - 1);
if (op == NULL_TREE)
continue;
if (i == 1 && (is_gimple_call (stmt) || is_gimple_assign (stmt)))
gimplify_expr (&op, &pre, NULL, is_gimple_lvalue, fb_lvalue);
else if (i == 2
&& is_gimple_assign (stmt)
&& num_ops == 2
&& get_gimple_rhs_class (gimple_expr_code (stmt))
== GIMPLE_SINGLE_RHS)
gimplify_expr (&op, &pre, NULL,
rhs_predicate_for (gimple_assign_lhs (stmt)),
fb_rvalue);
else if (i == 2 && is_gimple_call (stmt))
{
if (TREE_CODE (op) == FUNCTION_DECL)
continue;
gimplify_expr (&op, &pre, NULL, is_gimple_call_addr, fb_rvalue);
}
else
gimplify_expr (&op, &pre, NULL, is_gimple_val, fb_rvalue);
gimple_set_op (stmt, i - 1, op);
}
lhs = gimple_get_lhs (stmt);
/* If the LHS changed it in a way that requires a simple RHS,
create temporary. */
if (lhs && !is_gimple_reg (lhs))
8309
8310
8311
8312
8313
8314
8315
8316
8317
8318
8319
8320
8321
8322
8323
8324
8325
8326
8327
8328
8329
8330
8331
8332
8333
8334
8335
8336
8337
8338
8339
8340
8341
8342
8343
8344
8345
8346
8347
8348
8349
8350
8351
8352
8353
8354
{
bool need_temp = false;
if (is_gimple_assign (stmt)
&& num_ops == 2
&& get_gimple_rhs_class (gimple_expr_code (stmt))
== GIMPLE_SINGLE_RHS)
gimplify_expr (gimple_assign_rhs1_ptr (stmt), &pre, NULL,
rhs_predicate_for (gimple_assign_lhs (stmt)),
fb_rvalue);
else if (is_gimple_reg (lhs))
{
if (is_gimple_reg_type (TREE_TYPE (lhs)))
{
if (is_gimple_call (stmt))
{
i = gimple_call_flags (stmt);
if ((i & ECF_LOOPING_CONST_OR_PURE)
|| !(i & (ECF_CONST | ECF_PURE)))
need_temp = true;
}
if (stmt_can_throw_internal (stmt))
need_temp = true;
}
}
else
{
if (is_gimple_reg_type (TREE_TYPE (lhs)))
need_temp = true;
else if (TYPE_MODE (TREE_TYPE (lhs)) != BLKmode)
{
if (is_gimple_call (stmt))
{
tree fndecl = gimple_call_fndecl (stmt);
if (!aggregate_value_p (TREE_TYPE (lhs), fndecl)
&& !(fndecl && DECL_RESULT (fndecl)
&& DECL_BY_REFERENCE (DECL_RESULT (fndecl))))
need_temp = true;
}
else
need_temp = true;
}
}
if (need_temp)
{
tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL);
if (TREE_CODE (orig_lhs) == SSA_NAME)
orig_lhs = SSA_NAME_VAR (orig_lhs);
if (gimple_in_ssa_p (cfun))
temp = make_ssa_name (temp, NULL);
gimple_set_lhs (stmt, temp);
post_stmt = gimple_build_assign (lhs, temp);
if (TREE_CODE (lhs) == SSA_NAME)
SSA_NAME_DEF_STMT (lhs) = post_stmt;
}
}
break;
}
Jakub Jelinek
committed
if (gimple_referenced_vars (cfun))
for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
add_referenced_var (t);
if (!gimple_seq_empty_p (pre))
{
if (gimple_in_ssa_p (cfun))
{
gimple_stmt_iterator i;
for (i = gsi_start (pre); !gsi_end_p (i); gsi_next (&i))
mark_symbols_for_renaming (gsi_stmt (i));
}
gsi_insert_seq_before (gsi_p, pre, GSI_SAME_STMT);
}
if (post_stmt)
gsi_insert_after (gsi_p, post_stmt, GSI_NEW_STMT);
pop_gimplify_context (NULL);
}
/* Expand EXPR to list of gimple statements STMTS. GIMPLE_TEST_F specifies
the predicate that will hold for the result. If VAR is not NULL, make the
base variable of the final destination be VAR if suitable. */
tree
force_gimple_operand_1 (tree expr, gimple_seq *stmts,
gimple_predicate gimple_test_f, tree var)
{
tree t;
enum gimplify_status ret;
struct gimplify_ctx gctx;
*stmts = NULL;
Richard Guenther
committed
/* gimple_test_f might be more strict than is_gimple_val, make
sure we pass both. Just checking gimple_test_f doesn't work
because most gimple predicates do not work recursively. */
if (is_gimple_val (expr)
&& (*gimple_test_f) (expr))
push_gimplify_context (&gctx);
gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
expr = build2 (MODIFY_EXPR, TREE_TYPE (var), var, expr);
if (TREE_CODE (expr) != MODIFY_EXPR
&& TREE_TYPE (expr) == void_type_node)
{
gimplify_and_add (expr, stmts);
expr = NULL_TREE;
}
else
{
ret = gimplify_expr (&expr, stmts, NULL, gimple_test_f, fb_rvalue);
gcc_assert (ret != GS_ERROR);
}
if (gimple_referenced_vars (cfun))
for (t = gimplify_ctxp->temps; t ; t = DECL_CHAIN (t))
add_referenced_var (t);
pop_gimplify_context (NULL);
return expr;
}
/* Expand EXPR to list of gimple statements STMTS. If SIMPLE is true,
force the result to be either ssa_name or an invariant, otherwise
just force it to be a rhs expression. If VAR is not NULL, make the
base variable of the final destination be VAR if suitable. */
Zdenek Dvorak
committed
tree
force_gimple_operand (tree expr, gimple_seq *stmts, bool simple, tree var)
{
return force_gimple_operand_1 (expr, stmts,
simple ? is_gimple_val : is_gimple_reg_rhs,
var);
}
/* Invoke force_gimple_operand_1 for EXPR with parameters GIMPLE_TEST_F
and VAR. If some statements are produced, emits them at GSI.
If BEFORE is true. the statements are appended before GSI, otherwise
they are appended after it. M specifies the way GSI moves after
insertion (GSI_SAME_STMT or GSI_CONTINUE_LINKING are the usual values). */
tree
force_gimple_operand_gsi_1 (gimple_stmt_iterator *gsi, tree expr,
gimple_predicate gimple_test_f,
tree var, bool before,
enum gsi_iterator_update m)
Zdenek Dvorak
committed
{
gimple_seq stmts;
Zdenek Dvorak
committed
expr = force_gimple_operand_1 (expr, &stmts, gimple_test_f, var);
if (!gimple_seq_empty_p (stmts))
Zdenek Dvorak
committed
{
Eric Botcazou
committed
if (gimple_in_ssa_p (cfun))
{
gimple_stmt_iterator i;
Eric Botcazou
committed
for (i = gsi_start (stmts); !gsi_end_p (i); gsi_next (&i))
mark_symbols_for_renaming (gsi_stmt (i));
Eric Botcazou
committed
}
Zdenek Dvorak
committed
if (before)
gsi_insert_seq_before (gsi, stmts, m);
Zdenek Dvorak
committed
else
gsi_insert_seq_after (gsi, stmts, m);
Zdenek Dvorak
committed
}
Zdenek Dvorak
committed
return expr;
}
/* Invoke force_gimple_operand_1 for EXPR with parameter VAR.
If SIMPLE is true, force the result to be either ssa_name or an invariant,
otherwise just force it to be a rhs expression. If some statements are
produced, emits them at GSI. If BEFORE is true, the statements are
appended before GSI, otherwise they are appended after it. M specifies
the way GSI moves after insertion (GSI_SAME_STMT or GSI_CONTINUE_LINKING
are the usual values). */
tree
force_gimple_operand_gsi (gimple_stmt_iterator *gsi, tree expr,
bool simple_p, tree var, bool before,
enum gsi_iterator_update m)
{
return force_gimple_operand_gsi_1 (gsi, expr,
simple_p
? is_gimple_val : is_gimple_reg_rhs,
var, before, m);
}