/* Tree lowering pass. This pass converts the GENERIC functions-as-trees
tree representation into the GIMPLE form.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
tree lab = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
DECL_ARTIFICIAL (lab) = 1;
+ DECL_IGNORED_P (lab) = 1;
DECL_CONTEXT (lab) = current_function_decl;
return lab;
}
of the emitted code: see mx_register_decls(). */
tree t, args, addr, ptr_type;
- gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
+ /* ??? We really shouldn't need to gimplify the type of the variable
+ since it already should have been done. But leave this here
+ for now to avoid disrupting too many things at once. */
+ if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
+ gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
+
gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
VARRAY_GENERIC_PTR_NOGC_INIT (stack, 10, "stack");
/* We can handle anything that get_inner_reference can deal with. */
- for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
- VARRAY_PUSH_GENERIC_PTR_NOGC (stack, *p);
+ for (p = expr_p; ; p = &TREE_OPERAND (*p, 0))
+ {
+ /* Fold INDIRECT_REFs now to turn them into ARRAY_REFs. */
+ if (TREE_CODE (*p) == INDIRECT_REF)
+ *p = fold_indirect_ref (*p);
+ if (!handled_component_p (*p))
+ break;
+ VARRAY_PUSH_GENERIC_PTR_NOGC (stack, *p);
+ }
gcc_assert (VARRAY_ACTIVE_SIZE (stack));
return GS_OK;
}
- if (DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
+ if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
{
tree arglist = TREE_OPERAND (*expr_p, 1);
tree true_label, false_label, end_label, t;
tree *true_label_p;
tree *false_label_p;
- bool emit_end, emit_false;
+ bool emit_end, emit_false, jump_over_else;
bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
then_ = shortcut_cond_expr (expr);
+ then_se = then_ && TREE_SIDE_EFFECTS (then_);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
}
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
else_ = shortcut_cond_expr (expr);
+ else_se = else_ && TREE_SIDE_EFFECTS (else_);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
}
emit_end = (end_label == NULL_TREE);
emit_false = (false_label == NULL_TREE);
+ /* We only emit the jump over the else clause if we have to--if the
+ then clause may fall through. Otherwise we can wind up with a
+ useless jump and a useless label at the end of gimplified code,
+ which will cause us to think that this conditional as a whole
+ falls through even if it doesn't. If we then inline a function
+ which ends with such a condition, that can cause us to issue an
+ inappropriate warning about control reaching the end of a
+ non-void function. */
+ jump_over_else = block_may_fallthru (then_);
+
pred = shortcut_cond_r (pred, true_label_p, false_label_p);
expr = NULL;
append_to_statement_list (then_, &expr);
if (else_se)
{
- t = build_and_jump (&end_label);
- append_to_statement_list (t, &expr);
+ if (jump_over_else)
+ {
+ t = build_and_jump (&end_label);
+ append_to_statement_list (t, &expr);
+ }
if (emit_false)
{
t = build1 (LABEL_EXPR, void_type_node, false_label);
TARGET is the tree for T1 above.
PRE_P points to the list where side effects that must happen before
- *EXPR_P should be stored. */
+ *EXPR_P should be stored.
+
+ POST_P points to the list where side effects that must happen after
+ *EXPR_P should be stored. */
static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target)
{
tree expr = *expr_p;
tree tmp, tmp2, type;
{
if (target)
{
- ret = gimplify_expr (&target, pre_p, NULL,
+ ret = gimplify_expr (&target, pre_p, post_p,
is_gimple_min_lval, fb_lvalue);
if (ret != GS_ERROR)
ret = GS_OK;
categorize_ctor_elements (ctor, &num_nonzero_elements,
&num_nonconstant_elements,
- &num_ctor_elements);
+ &num_ctor_elements, &cleared);
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
if (num_nonconstant_elements == 0
+ && num_nonzero_elements > 1
&& TREE_READONLY (object)
&& TREE_CODE (object) == VAR_DECL)
{
num_type_elements = count_type_elements (TREE_TYPE (ctor));
/* If there are "lots" of zeros, then block clear the object first. */
- cleared = false;
if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
&& num_nonzero_elements < num_type_elements/4)
cleared = true;
case VECTOR_TYPE:
/* Go ahead and simplify constant constructors to VECTOR_CST. */
if (TREE_CONSTANT (ctor))
- TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
- else
{
- /* Vector types use CONSTRUCTOR all the way through gimple
- compilation as a general initializer. */
- for (; elt_list; elt_list = TREE_CHAIN (elt_list))
+ tree tem;
+
+ /* Even when ctor is constant, it might contain non-*_CST
+ elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
+ belong into VECTOR_CST nodes. */
+ for (tem = elt_list; tem; tem = TREE_CHAIN (tem))
+ if (! CONSTANT_CLASS_P (TREE_VALUE (tem)))
+ break;
+
+ if (! tem)
{
- enum gimplify_status tret;
- tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
- is_gimple_val, fb_rvalue);
- if (tret == GS_ERROR)
- ret = GS_ERROR;
+ TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
+ break;
}
}
+
+ /* Vector types use CONSTRUCTOR all the way through gimple
+ compilation as a general initializer. */
+ for (; elt_list; elt_list = TREE_CHAIN (elt_list))
+ {
+ enum gimplify_status tret;
+ tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ if (tret == GS_ERROR)
+ ret = GS_ERROR;
+ }
break;
default:
while (ret != GS_UNHANDLED)
switch (TREE_CODE (*from_p))
{
+ case INDIRECT_REF:
+ {
+ /* If we have code like
+
+ *(const A*)(A*)&x
+
+ where the type of "x" is a (possibly cv-qualified variant
+ of "A"), treat the entire expression as identical to "x".
+ This kind of code arises in C++ when an object is bound
+ to a const reference, and if "x" is a TARGET_EXPR we want
+ to take advantage of the optimization below. */
+ tree t = fold_indirect_ref (*from_p);
+ if (t != *from_p)
+ {
+ *from_p = t;
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+ }
+
case TARGET_EXPR:
{
/* If we are initializing something from a TARGET_EXPR, strip the
if (!is_gimple_reg_type (TREE_TYPE (*from_p)))
{
*expr_p = *from_p;
- return gimplify_cond_expr (expr_p, pre_p, *to_p);
+ return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p);
}
else
ret = GS_UNHANDLED;
bool allows_mem, allows_reg, is_inout;
enum gimplify_status ret, tret;
- ASM_STRING (expr)
- = resolve_asm_operand_names (ASM_STRING (expr), ASM_OUTPUTS (expr),
- ASM_INPUTS (expr));
-
ret = GS_ALL_DONE;
for (i = 0, link = ASM_OUTPUTS (expr); link; ++i, link = TREE_CHAIN (link))
{
ret = GS_OK;
if (TREE_CODE (init) == BIND_EXPR)
gimplify_bind_expr (&init, temp, pre_p);
- if (init != temp)
+ if (init != temp)
{
init = build (MODIFY_EXPR, void_type_node, temp, init);
ret = gimplify_expr (&init, pre_p, post_p, is_gimple_stmt,
break;
case COND_EXPR:
- ret = gimplify_cond_expr (expr_p, pre_p, NULL_TREE);
+ ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE);
break;
case CALL_EXPR:
recalculate_side_effects (*expr_p);
break;
+ case INDIRECT_REF:
+ *expr_p = fold_indirect_ref (*expr_p);
+ if (*expr_p != save_expr)
+ break;
+ /* else fall through. */
case ALIGN_INDIRECT_REF:
case MISALIGNED_INDIRECT_REF:
- case INDIRECT_REF:
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_reg, fb_rvalue);
recalculate_side_effects (*expr_p);
void
gimplify_type_sizes (tree type, tree *list_p)
{
- tree field;
+ tree field, t;
+
+ /* Note that we do not check for TYPE_SIZES_GIMPLIFIED already set because
+ that's not supposed to happen on types where gimplification does anything.
+ We should assert that it isn't set, but we can indeed be called multiple
+ times on pointers. Unfortunately, this includes fat pointers which we
+ can't easily test for. We could pass TYPE down to gimplify_one_sizepos
+ and test there, but it doesn't seem worth it. */
+
+ /* We first do the main variant, then copy into any other variants. */
+ type = TYPE_MAIN_VARIANT (type);
switch (TREE_CODE (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);
+ TYPE_SIZES_GIMPLIFIED (t) = 1;
+ }
break;
case ARRAY_TYPE:
- /* These anonymous types don't have declarations, so handle them here. */
- gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
+ /* These types may not have declarations, so handle them here. */
+ if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (type)))
+ gimplify_type_sizes (TREE_TYPE (type), list_p);
+
+ if (!TYPE_SIZES_GIMPLIFIED (TYPE_DOMAIN (type)))
+ gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
break;
case RECORD_TYPE:
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;
+ }
+
+ TYPE_SIZES_GIMPLIFIED (type) = 1;
}
-/* Subroutine of the above to gimplify one size or position, *EXPR_P.
+/* 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
|| CONTAINS_PLACEHOLDER_P (*expr_p))
return;
+ *expr_p = unshare_expr (*expr_p);
gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
}
\f