Newer
Older
Richard Henderson
committed
gimplify_and_add (tmp, stmt_p);
}
}
6005
6006
6007
6008
6009
6010
6011
6012
6013
6014
6015
6016
6017
6018
6019
6020
6021
6022
6023
6024
6025
6026
6027
6028
6029
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
6053
6054
#ifdef ENABLE_CHECKING
/* Compare types A and B for a "close enough" match. */
static bool
cpt_same_type (tree a, tree b)
{
if (lang_hooks.types_compatible_p (a, b))
return true;
/* ??? The C++ FE decomposes METHOD_TYPES to FUNCTION_TYPES and doesn't
link them together. This routine is intended to catch type errors
that will affect the optimizers, and the optimizers don't add new
dereferences of function pointers, so ignore it. */
if ((TREE_CODE (a) == FUNCTION_TYPE || TREE_CODE (a) == METHOD_TYPE)
&& (TREE_CODE (b) == FUNCTION_TYPE || TREE_CODE (b) == METHOD_TYPE))
return true;
/* ??? The C FE pushes type qualifiers after the fact into the type of
the element from the type of the array. See build_unary_op's handling
of ADDR_EXPR. This seems wrong -- if we were going to do this, we
should have done it when creating the variable in the first place.
Alternately, why aren't the two array types made variants? */
if (TREE_CODE (a) == ARRAY_TYPE && TREE_CODE (b) == ARRAY_TYPE)
return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
/* And because of those, we have to recurse down through pointers. */
if (POINTER_TYPE_P (a) && POINTER_TYPE_P (b))
return cpt_same_type (TREE_TYPE (a), TREE_TYPE (b));
return false;
}
/* Check for some cases of the front end missing cast expressions.
The type of a dereference should correspond to the pointer type;
similarly the type of an address should match its object. */
static tree
check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
tree t = *tp;
tree ptype, otype, dtype;
switch (TREE_CODE (t))
{
case INDIRECT_REF:
case ARRAY_REF:
otype = TREE_TYPE (t);
ptype = TREE_TYPE (TREE_OPERAND (t, 0));
dtype = TREE_TYPE (ptype);
gcc_assert (cpt_same_type (otype, dtype));
break;
case ADDR_EXPR:
ptype = TREE_TYPE (t);
otype = TREE_TYPE (TREE_OPERAND (t, 0));
dtype = TREE_TYPE (ptype);
if (!cpt_same_type (otype, dtype))
{
/* &array is allowed to produce a pointer to the element, rather than
a pointer to the array type. We must allow this in order to
properly represent assigning the address of an array in C into
pointer to the element type. */
gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
&& POINTER_TYPE_P (ptype)
&& cpt_same_type (TREE_TYPE (otype), dtype));
break;
}
break;
default:
return NULL_TREE;
}
return NULL_TREE;
}
#endif
/* Gimplify the body of statements pointed to by BODY_P. FNDECL is the
function decl containing BODY. */
void
Richard Henderson
committed
gimplify_body (tree *body_p, tree fndecl, bool do_parms)
{
location_t saved_location = input_location;
Richard Henderson
committed
tree body, parm_stmts;
timevar_push (TV_TREE_GIMPLIFY);
push_gimplify_context ();
/* Unshare most shared trees in the body and in that of any nested functions.
It would seem we don't have to do this for nested functions because
they are supposed to be output and then the outer function gimplified
first, but the g++ front end doesn't always do it that way. */
unshare_body (body_p, fndecl);
unvisit_body (body_p, fndecl);
/* Make sure input_location isn't set to something wierd. */
input_location = DECL_SOURCE_LOCATION (fndecl);
Richard Henderson
committed
/* Resolve callee-copies. This has to be done before processing
the body so that DECL_VALUE_EXPR gets processed correctly. */
parm_stmts = do_parms ? gimplify_parameters () : NULL;
/* Gimplify the function's body. */
gimplify_stmt (body_p);
body = *body_p;
if (!body)
body = alloc_stmt_list ();
else if (TREE_CODE (body) == STATEMENT_LIST)
{
tree t = expr_only (*body_p);
if (t)
body = t;
}
/* If there isn't an outer BIND_EXPR, add one. */
if (TREE_CODE (body) != BIND_EXPR)
{
tree b = build3 (BIND_EXPR, void_type_node, NULL_TREE,
NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (b) = 1;
Jason Merrill
committed
append_to_statement_list_force (body, &BIND_EXPR_BODY (b));
Richard Henderson
committed
/* If we had callee-copies statements, insert them at the beginning
of the function. */
if (parm_stmts)
{
append_to_statement_list_force (BIND_EXPR_BODY (body), &parm_stmts);
BIND_EXPR_BODY (body) = parm_stmts;
}
/* Unshare again, in case gimplification was sloppy. */
unshare_all_trees (body);
*body_p = body;
pop_gimplify_context (body);
#ifdef ENABLE_CHECKING
walk_tree (body_p, check_pointer_types_r, NULL, NULL);
#endif
timevar_pop (TV_TREE_GIMPLIFY);
input_location = saved_location;
}
/* Entry point to the gimplification pass. FNDECL is the FUNCTION_DECL
node for the function we want to gimplify. */
void
gimplify_function_tree (tree fndecl)
{
Richard Henderson
committed
tree oldfn, parm, ret;
oldfn = current_function_decl;
current_function_decl = fndecl;
Richard Henderson
committed
cfun = DECL_STRUCT_FUNCTION (fndecl);
if (cfun == NULL)
allocate_struct_function (fndecl);
Richard Henderson
committed
for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
{
/* Preliminarily mark non-addressed complex variables as eligible
for promotion to gimple registers. We'll transform their uses
as we find them. */
if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
&& !TREE_THIS_VOLATILE (parm)
&& !needs_to_live_in_memory (parm))
DECL_COMPLEX_GIMPLE_REG_P (parm) = 1;
}
ret = DECL_RESULT (fndecl);
if (TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
&& !needs_to_live_in_memory (ret))
DECL_COMPLEX_GIMPLE_REG_P (ret) = 1;
Richard Henderson
committed
gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true);
/* 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))
{
tree tf, x, bind;
tf = build2 (TRY_FINALLY_EXPR, void_type_node, NULL, NULL);
TREE_SIDE_EFFECTS (tf) = 1;
x = DECL_SAVED_TREE (fndecl);
append_to_statement_list (x, &TREE_OPERAND (tf, 0));
x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_EXIT];
x = build_function_call_expr (x, NULL);
append_to_statement_list (x, &TREE_OPERAND (tf, 1));
bind = build3 (BIND_EXPR, void_type_node, NULL, NULL, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
x = implicit_built_in_decls[BUILT_IN_PROFILE_FUNC_ENTER];
x = build_function_call_expr (x, NULL);
append_to_statement_list (x, &BIND_EXPR_BODY (bind));
append_to_statement_list (tf, &BIND_EXPR_BODY (bind));
DECL_SAVED_TREE (fndecl) = bind;
}
current_function_decl = oldfn;
Richard Henderson
committed
cfun = oldfn ? DECL_STRUCT_FUNCTION (oldfn) : NULL;
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
/* Expands 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. */
tree
force_gimple_operand (tree expr, tree *stmts, bool simple, tree var)
{
tree t;
enum gimplify_status ret;
gimple_predicate gimple_test_f;
*stmts = NULL_TREE;
if (is_gimple_val (expr))
return expr;
gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
push_gimplify_context ();
Zdenek Dvorak
committed
gimplify_ctxp->into_ssa = in_ssa_p;
expr = build2 (MODIFY_EXPR, TREE_TYPE (var), var, expr);
ret = gimplify_expr (&expr, stmts, NULL,
gimple_test_f, fb_rvalue);
gcc_assert (ret != GS_ERROR);
Zdenek Dvorak
committed
if (referenced_vars)
{
for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
add_referenced_var (t);
Zdenek Dvorak
committed
}
pop_gimplify_context (NULL);
return expr;
}
Zdenek Dvorak
committed
/* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR. If
some statements are produced, emits them before BSI. */
tree
force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
bool simple_p, tree var)
{
tree stmts;
expr = force_gimple_operand (expr, &stmts, simple_p, var);
if (stmts)
bsi_insert_before (bsi, stmts, BSI_SAME_STMT);
return expr;
}