Newer
Older
/* We first do the main variant, then copy into any other variants. */
/* Avoid infinite recursion. */
if (TYPE_SIZES_GIMPLIFIED (type))
return;
TYPE_SIZES_GIMPLIFIED (type) = 1;
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
case REAL_TYPE:
gimplify_one_sizepos (&TYPE_MIN_VALUE (type), list_p);
gimplify_one_sizepos (&TYPE_MAX_VALUE (type), list_p);
for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
{
TYPE_MIN_VALUE (t) = TYPE_MIN_VALUE (type);
TYPE_MAX_VALUE (t) = TYPE_MAX_VALUE (type);
}
break;
case ARRAY_TYPE:
/* These types may not have declarations, so handle them here. */
gimplify_type_sizes (TREE_TYPE (type), list_p);
gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
break;
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
{
gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
gimplify_type_sizes (TREE_TYPE (field), list_p);
}
break;
case POINTER_TYPE:
case REFERENCE_TYPE:
/* We used to recurse on the pointed-to type here, which turned out to
be incorrect because its definition might refer to variables not
yet initialized at this point if a forward declaration is involved.
It was actually useful for anonymous pointed-to types to ensure
that the sizes evaluation dominates every possible later use of the
values. Restricting to such types here would be safe since there
is no possible forward declaration around, but would introduce an
undesirable middle-end semantic to anonymity. We then defer to
front-ends the responsibility of ensuring that the sizes are
evaluated both early and late enough, e.g. by attaching artificial
type declarations to the tree. */
break;
default:
break;
}
gimplify_one_sizepos (&TYPE_SIZE (type), list_p);
gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), list_p);
for (t = TYPE_NEXT_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
TYPE_SIZE (t) = TYPE_SIZE (type);
TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
TYPE_SIZES_GIMPLIFIED (t) = 1;
}
}
/* A subroutine of gimplify_type_sizes to make sure that *EXPR_P,
a size or position, has had all of its SAVE_EXPRs evaluated.
We add any required statements to STMT_P. */
void
gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
{
Richard Henderson
committed
tree type, expr = *expr_p;
/* We don't do anything if the value isn't there, is constant, or contains
A PLACEHOLDER_EXPR. We also don't want to do anything if it's already
a VAR_DECL. If it's a VAR_DECL from another function, the gimplifier
will want to replace it with a new variable, but that will cause problems
if this type is from outside the function. It's OK to have that here. */
Richard Henderson
committed
if (expr == NULL_TREE || TREE_CONSTANT (expr)
|| TREE_CODE (expr) == VAR_DECL
|| CONTAINS_PLACEHOLDER_P (expr))
return;
Richard Henderson
committed
type = TREE_TYPE (expr);
*expr_p = unshare_expr (expr);
gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
Richard Henderson
committed
expr = *expr_p;
/* Verify that we've an exact type match with the original expression.
In particular, we do not wish to drop a "sizetype" in favour of a
type of similar dimensions. We don't want to pollute the generic
type-stripping code with this knowledge because it doesn't matter
for the bulk of GENERIC/GIMPLE. It only matters that TYPE_SIZE_UNIT
and friends retain their "sizetype-ness". */
Richard Henderson
committed
if (TREE_TYPE (expr) != type
&& TREE_CODE (type) == INTEGER_TYPE
&& TYPE_IS_SIZETYPE (type))
Richard Henderson
committed
{
tree tmp;
*expr_p = create_tmp_var (type, NULL);
tmp = build1 (NOP_EXPR, type, expr);
tmp = build2 (MODIFY_EXPR, type, *expr_p, tmp);
Richard Henderson
committed
if (EXPR_HAS_LOCATION (expr))
SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr));
else
SET_EXPR_LOCATION (tmp, input_location);
gimplify_and_add (tmp, stmt_p);
}
}
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
6146
6147
6148
6149
6150
6151
6152
6153
6154
6155
6156
6157
6158
6159
6160
6161
6162
6163
6164
6165
6166
6167
6168
6169
6170
6171
6172
#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;
6340
6341
6342
6343
6344
6345
6346
6347
6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
/* 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;
}