/* Forward declarations. */
static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
+#ifdef ENABLE_CHECKING
+static bool cpt_same_type (tree a, tree b);
+#endif
/* Return a hash value for a formal temporary table entry. */
/* Only allow them to compare equal if they also hash equal; otherwise
results are nondeterminate, and we fail bootstrap comparison. */
- if (gimple_tree_hash (p1) != gimple_tree_hash (p2))
- abort ();
+ gcc_assert (gimple_tree_hash (p1) == gimple_tree_hash (p2));
return 1;
}
void
push_gimplify_context (void)
{
- if (gimplify_ctxp)
- abort ();
+ gcc_assert (!gimplify_ctxp);
gimplify_ctxp
= (struct gimplify_ctx *) xcalloc (1, sizeof (struct gimplify_ctx));
if (optimize)
{
tree t;
- if (!gimplify_ctxp || gimplify_ctxp->current_bind_expr)
- abort ();
+ gcc_assert (gimplify_ctxp && !gimplify_ctxp->current_bind_expr);
for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
DECL_GIMPLE_FORMAL_TEMP_P (t) = 0;
static void
gimple_push_condition (void)
{
+#ifdef ENABLE_CHECKING
+ if (gimplify_ctxp->conditions == 0)
+ gcc_assert (!gimplify_ctxp->conditional_cleanups);
+#endif
++(gimplify_ctxp->conditions);
}
{
int conds = --(gimplify_ctxp->conditions);
+ gcc_assert (conds >= 0);
if (conds == 0)
{
append_to_statement_list (gimplify_ctxp->conditional_cleanups, pre_p);
gimplify_ctxp->conditional_cleanups = NULL_TREE;
}
- else if (conds < 0)
- abort ();
}
-/* A subroutine of append_to_statement_list{,_force}. */
+/* A subroutine of append_to_statement_list{,_force}. T is not NULL. */
static void
-append_to_statement_list_1 (tree t, tree *list_p, bool side_effects)
+append_to_statement_list_1 (tree t, tree *list_p)
{
tree list = *list_p;
tree_stmt_iterator i;
- if (!side_effects)
- return;
-
if (!list)
{
if (t && TREE_CODE (t) == STATEMENT_LIST)
void
append_to_statement_list (tree t, tree *list_p)
{
- append_to_statement_list_1 (t, list_p, t ? TREE_SIDE_EFFECTS (t) : false);
+ if (t && TREE_SIDE_EFFECTS (t))
+ append_to_statement_list_1 (t, list_p);
}
/* Similar, but the statement is always added, regardless of side effects. */
void
append_to_statement_list_force (tree t, tree *list_p)
{
- append_to_statement_list_1 (t, list_p, t != NULL);
+ if (t != NULL_TREE)
+ append_to_statement_list_1 (t, list_p);
}
/* Both gimplify the statement T and append it to LIST_P. */
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;
}
new_type = build_type_variant (type, 0, 0);
TYPE_ATTRIBUTES (new_type) = TYPE_ATTRIBUTES (type);
- tmp_var = build_decl (VAR_DECL, create_tmp_var_name (prefix), type);
+ tmp_var = build_decl (VAR_DECL, prefix ? create_tmp_var_name (prefix) : NULL,
+ type);
/* The variable was declared by the compiler. */
DECL_ARTIFICIAL (tmp_var) = 1;
{
tree tmp_var;
-#if defined ENABLE_CHECKING
/* We don't allow types that are addressable (meaning we can't make copies),
incomplete, or of variable size. */
- if (TREE_ADDRESSABLE (type)
- || !COMPLETE_TYPE_P (type)
- || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
- abort ();
-#endif
+ gcc_assert (!TREE_ADDRESSABLE (type)
+ && COMPLETE_TYPE_P (type)
+ && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST);
tmp_var = create_tmp_var_raw (type, prefix);
gimple_add_tmp_var (tmp_var);
while (TREE_CODE (scope) == COMPOUND_EXPR)
scope = TREE_OPERAND (scope, 0);
- if (TREE_CODE (scope) != BIND_EXPR)
- abort ();
+ gcc_assert (TREE_CODE (scope) == BIND_EXPR);
temps = nreverse (last);
TREE_CHAIN (last) = BIND_EXPR_VARS (scope);
void
gimple_add_tmp_var (tree tmp)
{
- if (TREE_CHAIN (tmp) || DECL_SEEN_IN_BIND_EXPR_P (tmp))
- abort ();
+ gcc_assert (!TREE_CHAIN (tmp) && !DECL_SEEN_IN_BIND_EXPR_P (tmp));
DECL_CONTEXT (tmp) = current_function_decl;
DECL_SEEN_IN_BIND_EXPR_P (tmp) = 1;
static void
annotate_one_with_locus (tree t, location_t locus)
{
- if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (t)))
- && ! EXPR_HAS_LOCATION (t)
- && should_carry_locus_p (t))
+ if (EXPR_P (t) && ! EXPR_HAS_LOCATION (t) && should_carry_locus_p (t))
SET_EXPR_LOCATION (t, locus);
}
{
tree t = tsi_stmt (i);
-#ifdef ENABLE_CHECKING
- /* Assuming we've already been gimplified, we shouldn't
- see nested chaining constructs anymore. */
- if (TREE_CODE (t) == STATEMENT_LIST
- || TREE_CODE (t) == COMPOUND_EXPR)
- abort ();
-#endif
+ /* Assuming we've already been gimplified, we shouldn't
+ see nested chaining constructs anymore. */
+ gcc_assert (TREE_CODE (t) != STATEMENT_LIST
+ && TREE_CODE (t) != COMPOUND_EXPR);
annotate_one_with_locus (t, locus);
}
{
enum tree_code code = TREE_CODE (*tp);
/* Don't unshare types, decls, constants and SAVE_EXPR nodes. */
- if (TREE_CODE_CLASS (code) == 't'
- || TREE_CODE_CLASS (code) == 'd'
- || TREE_CODE_CLASS (code) == 'c'
+ if (TREE_CODE_CLASS (code) == tcc_type
+ || TREE_CODE_CLASS (code) == tcc_declaration
+ || TREE_CODE_CLASS (code) == tcc_constant
|| code == SAVE_EXPR || code == TARGET_EXPR
/* We can't do anything sensible with a BLOCK used as an expression,
but we also can't abort when we see it because of non-expression
uses. So just avert our eyes and cross our fingers. Silly Java. */
|| code == BLOCK)
*walk_subtrees = 0;
- else if (code == BIND_EXPR)
- abort ();
else
- copy_tree_r (tp, walk_subtrees, data);
+ {
+ gcc_assert (code != BIND_EXPR);
+ copy_tree_r (tp, walk_subtrees, data);
+ }
return NULL_TREE;
}
types and the bounds of types. Mark them as visited so we properly
unmark their subtrees on the unmark pass. If we've already seen them,
don't look down further. */
- if (TREE_CODE_CLASS (code) == 't'
- || TREE_CODE_CLASS (code) == 'd'
- || TREE_CODE_CLASS (code) == 'c')
+ if (TREE_CODE_CLASS (code) == tcc_type
+ || TREE_CODE_CLASS (code) == tcc_declaration
+ || TREE_CODE_CLASS (code) == tcc_constant)
{
if (TREE_VISITED (t))
*walk_subtrees = 0;
return expr;
}
-/* A terser interface for building a representation of a exception
+/* A terser interface for building a representation of an exception
specification. */
tree
p = tsi_end_p (i) ? NULL : tsi_stmt_ptr (i);
}
else
- {
+ {
for (; TREE_CODE (*p) == COMPOUND_EXPR; p = &TREE_OPERAND (*p, 1))
{
TREE_SIDE_EFFECTS (*p) = 1;
if (TREE_CODE (result_decl) == INDIRECT_REF)
/* See through a return by reference. */
result_decl = TREE_OPERAND (result_decl, 0);
-#ifdef ENABLE_CHECKING
- if ((TREE_CODE (ret_expr) != MODIFY_EXPR
- && TREE_CODE (ret_expr) != INIT_EXPR)
- || TREE_CODE (result_decl) != RESULT_DECL)
- abort ();
-#endif
+
+ gcc_assert ((TREE_CODE (ret_expr) == MODIFY_EXPR
+ || TREE_CODE (ret_expr) == INIT_EXPR)
+ && TREE_CODE (result_decl) == RESULT_DECL);
}
/* 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
+ across another call. In addition, for those aggregates for which
hard_function_value generates a PARALLEL, we'll abort during normal
expansion of structure assignments; there's special code in expand_return
to handle this case that does not exist in expand_expr. */
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);
- /* All occurences of this decl in final gimplified code will be
+ /* 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
+ 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));
/* If someone can be bothered to fill in the labels, they can
be bothered to null out the body too. */
- if (SWITCH_LABELS (switch_expr))
- abort ();
+ gcc_assert (!SWITCH_LABELS (switch_expr));
saved_labels = gimplify_ctxp->case_labels;
VARRAY_TREE_INIT (gimplify_ctxp->case_labels, 8, "case_labels");
SWITCH_BODY (switch_expr) = NULL;
}
- else if (!SWITCH_LABELS (switch_expr))
- abort ();
+ else
+ gcc_assert (SWITCH_LABELS (switch_expr));
return ret;
}
gimplify_case_label_expr (tree *expr_p)
{
tree expr = *expr_p;
- if (gimplify_ctxp->case_labels)
- VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
- else
- abort ();
+
+ gcc_assert (gimplify_ctxp->case_labels);
+ VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
*expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
return GS_ALL_DONE;
}
-/* Gimplify a LABELED_BLOCK_EXPR into a LABEL_EXPR following
- a (possibly empty) body. */
-
-static enum gimplify_status
-gimplify_labeled_block_expr (tree *expr_p)
-{
- tree body = LABELED_BLOCK_BODY (*expr_p);
- tree label = LABELED_BLOCK_LABEL (*expr_p);
- tree t;
-
- DECL_CONTEXT (label) = current_function_decl;
- t = build (LABEL_EXPR, void_type_node, label);
- if (body != NULL_TREE)
- t = build (COMPOUND_EXPR, void_type_node, body, t);
- *expr_p = t;
-
- return GS_OK;
-}
-
-/* Gimplify a EXIT_BLOCK_EXPR into a GOTO_EXPR. */
-
-static enum gimplify_status
-gimplify_exit_block_expr (tree *expr_p)
-{
- tree labeled_block = TREE_OPERAND (*expr_p, 0);
- tree label;
-
- /* First operand must be a LABELED_BLOCK_EXPR, which should
- already be lowered (or partially lowered) when we get here. */
-#if defined ENABLE_CHECKING
- if (TREE_CODE (labeled_block) != LABELED_BLOCK_EXPR)
- abort ();
-#endif
-
- label = LABELED_BLOCK_LABEL (labeled_block);
- *expr_p = build1 (GOTO_EXPR, void_type_node, label);
-
- return GS_OK;
-}
-
/* Build a GOTO to the LABEL_DECL pointed to by LABEL_P, building it first
if necessary. */
tree expr = *expr_p;
tree type;
- if (TREE_CODE (expr) != COMPONENT_REF)
- abort ();
+ gcc_assert (TREE_CODE (expr) == COMPONENT_REF);
if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
}
/* If a NOP conversion is changing a pointer to array of foo to a pointer
- to foo, embed that change in the ADDR_EXPR by converting
+ to foo, embed that change in the ADDR_EXPR by converting
T array[U];
(T *)&array
==>
return;
/* The lower bound and element sizes must be constant. */
- if (TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
+ if (!TYPE_SIZE_UNIT (dctype)
+ || TREE_CODE (TYPE_SIZE_UNIT (dctype)) != INTEGER_CST
|| !TYPE_DOMAIN (datype) || !TYPE_MIN_VALUE (TYPE_DOMAIN (datype))
|| TREE_CODE (TYPE_MIN_VALUE (TYPE_DOMAIN (datype))) != INTEGER_CST)
return;
static enum gimplify_status
gimplify_conversion (tree *expr_p)
-{
- /* If we still have a conversion at the toplevel, then strip
- away all but the outermost conversion. */
- if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
- {
- STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
+{
+ gcc_assert (TREE_CODE (*expr_p) == NOP_EXPR
+ || TREE_CODE (*expr_p) == CONVERT_EXPR);
+
+ /* Then strip away all but the outermost conversion. */
+ STRIP_SIGN_NOPS (TREE_OPERAND (*expr_p, 0));
- /* And remove the outermost conversion if it's useless. */
- if (tree_ssa_useless_type_conversion (*expr_p))
- *expr_p = TREE_OPERAND (*expr_p, 0);
- }
+ /* And remove the outermost conversion if it's useless. */
+ if (tree_ssa_useless_type_conversion (*expr_p))
+ *expr_p = TREE_OPERAND (*expr_p, 0);
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
int i;
/* Create a stack of the subexpressions so later we can walk them in
- order from inner to outer.
+ order from inner to outer.
This array is very memory consuming. Don't even think of making
it VARRAY_TREE. */
VARRAY_GENERIC_PTR_NOGC_INIT (stack, 10, "stack");
- /* We can either handle REALPART_EXPR, IMAGEPART_EXPR anything that
- handled_components can deal with. */
- for (p = expr_p;
- (handled_component_p (*p)
- || TREE_CODE (*p) == REALPART_EXPR || TREE_CODE (*p) == IMAGPART_EXPR);
- p = &TREE_OPERAND (*p, 0))
+ /* 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);
-#if defined ENABLE_CHECKING
- if (VARRAY_ACTIVE_SIZE (stack) == 0)
- abort ();
-#endif
+ gcc_assert (VARRAY_ACTIVE_SIZE (stack));
/* Now STACK is a stack of pointers to all the refs we've walked through
and P points to the innermost expression.
code = TREE_CODE (*expr_p);
-#if defined ENABLE_CHECKING
- if (code != POSTINCREMENT_EXPR
- && code != POSTDECREMENT_EXPR
- && code != PREINCREMENT_EXPR
- && code != PREDECREMENT_EXPR)
- abort ();
-#endif
+ gcc_assert (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR
+ || code == PREINCREMENT_EXPR || code == PREDECREMENT_EXPR);
/* Prefix or postfix? */
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
tree arglist;
enum gimplify_status ret;
-#if defined ENABLE_CHECKING
- if (TREE_CODE (*expr_p) != CALL_EXPR)
- abort ();
-#endif
+ gcc_assert (TREE_CODE (*expr_p) == CALL_EXPR);
- /* For reliable diagnostics during inlining, it is necessary that
+ /* For reliable diagnostics during inlining, it is necessary that
every call_expr be annotated with file and line. */
if (! EXPR_HAS_LOCATION (*expr_p))
SET_EXPR_LOCATION (*expr_p, input_location);
decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
- tree new = simplify_builtin (*expr_p, !want_value);
+ tree new = fold_builtin (*expr_p, !want_value);
if (new && new != *expr_p)
{
}
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
- /* Avoid gimplifying the second argument to va_start, which needs
- to be the plain PARM_DECL. */
- return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
+ {
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+
+ if (!arglist || !TREE_CHAIN (arglist))
+ {
+ error ("too few arguments to function %<va_start%>");
+ *expr_p = build_empty_stmt ();
+ return GS_OK;
+ }
+
+ if (fold_builtin_next_arg (TREE_CHAIN (arglist)))
+ {
+ *expr_p = build_empty_stmt ();
+ return GS_OK;
+ }
+ /* Avoid gimplifying the second argument to va_start, which needs
+ to be the plain PARM_DECL. */
+ return gimplify_arg (&TREE_VALUE (TREE_OPERAND (*expr_p, 1)), pre_p);
+ }
}
/* There is a sequence point before the call, so any side effects in
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
{
- tree new = simplify_builtin (*expr_p, !want_value);
+ tree new = fold_builtin (*expr_p, !want_value);
if (new && new != *expr_p)
{
/* These expressions always produce boolean results. */
TREE_TYPE (expr) = boolean_type_node;
return expr;
-
+
default:
/* Other expressions that get here must have boolean values, but
might need to be converted to the appropriate mode. */
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;
&& alias_sets_conflict_p (data->lhs_alias_set, get_alias_set (t)))
return t;
- if (DECL_P (t) || TYPE_P (t))
+ if (IS_TYPE_OR_DECL_P (t))
*walk_subtrees = 0;
return NULL;
}
/* Gimplify the constructor element to something appropriate for the rhs
of a MODIFY_EXPR. Given that we know the lhs is an aggregate, we know
- the gimplifier will consider this a store to memory. Doing this
+ the gimplifier will consider this a store to memory. Doing this
gimplification now means that we won't have to deal with complicated
language-specific trees, nor trees like SAVE_EXPR that can induce
- exponential search behaviour. */
+ exponential search behavior. */
one = gimplify_expr (expr_p, pre_p, post_p, is_gimple_mem_rhs, fb_rvalue);
if (one == GS_ERROR)
{
*expr_p = get_formal_tmp_var (*expr_p, pre_p);
}
+/* A subroutine of gimplify_init_ctor_eval. Create a loop for
+ a RANGE_EXPR in a CONSTRUCTOR for an array.
+
+ var = lower;
+ loop_entry:
+ object[var] = value;
+ if (var == upper)
+ goto loop_exit;
+ var = var + 1;
+ goto loop_entry;
+ loop_exit:
+
+ We increment var _after_ the loop exit check because we might otherwise
+ fail if upper == TYPE_MAX_VALUE (type for upper).
+
+ Note that we never have to deal with SAVE_EXPRs here, because this has
+ already been taken care of for us, in gimplify_init_ctor_preeval(). */
+
+static void gimplify_init_ctor_eval (tree, tree, tree *, bool);
+
+static void
+gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
+ tree value, tree array_elt_type,
+ tree *pre_p, bool cleared)
+{
+ tree loop_entry_label, loop_exit_label;
+ tree var, var_type, cref;
+
+ loop_entry_label = create_artificial_label ();
+ loop_exit_label = create_artificial_label ();
+
+ /* Create and initialize the index variable. */
+ var_type = TREE_TYPE (upper);
+ var = create_tmp_var (var_type, NULL);
+ append_to_statement_list (build2 (MODIFY_EXPR, var_type, var, lower), pre_p);
+
+ /* Add the loop entry label. */
+ append_to_statement_list (build1 (LABEL_EXPR,
+ void_type_node,
+ loop_entry_label),
+ pre_p);
+
+ /* Build the reference. */
+ cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
+ var, NULL_TREE, NULL_TREE);
+
+ /* If we are a constructor, just call gimplify_init_ctor_eval to do
+ the store. Otherwise just assign value to the reference. */
+
+ if (TREE_CODE (value) == CONSTRUCTOR)
+ /* NB we might have to call ourself recursively through
+ gimplify_init_ctor_eval if the value is a constructor. */
+ gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
+ pre_p, cleared);
+ else
+ append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (cref),
+ cref, value),
+ pre_p);
+
+ /* We exit the loop when the index var is equal to the upper bound. */
+ gimplify_and_add (build3 (COND_EXPR, void_type_node,
+ build2 (EQ_EXPR, boolean_type_node,
+ var, upper),
+ build1 (GOTO_EXPR,
+ void_type_node,
+ loop_exit_label),
+ NULL_TREE),
+ pre_p);
+
+ /* Otherwise, increment the index var... */
+ append_to_statement_list (build2 (MODIFY_EXPR, var_type, var,
+ build2 (PLUS_EXPR, var_type, var,
+ fold_convert (var_type,
+ integer_one_node))),
+ pre_p);
+
+ /* ...and jump back to the loop entry. */
+ append_to_statement_list (build1 (GOTO_EXPR,
+ void_type_node,
+ loop_entry_label),
+ pre_p);
+
+ /* Add the loop exit label. */
+ append_to_statement_list (build1 (LABEL_EXPR,
+ void_type_node,
+ loop_exit_label),
+ pre_p);
+}
+
/* A subroutine of gimplify_init_constructor. Generate individual
MODIFY_EXPRs for a CONSTRUCTOR. OBJECT is the LHS against which the
assignments should happen. LIST is the CONSTRUCTOR_ELTS of the
if (cleared && initializer_zerop (value))
continue;
- if (array_elt_type)
+ /* ??? Here's to hoping the front end fills in all of the indices,
+ so we don't have to figure out what's missing ourselves. */
+ gcc_assert (purpose);
+
+ /* If we have a RANGE_EXPR, we have to build a loop to assign the
+ whole range. */
+ if (TREE_CODE (purpose) == RANGE_EXPR)
{
- /* ??? Here's to hoping the front end fills in all of the indicies,
- so we don't have to figure out what's missing ourselves. */
- if (!purpose)
- abort ();
- /* ??? Need to handle this. */
- if (TREE_CODE (purpose) == RANGE_EXPR)
- abort ();
+ tree lower = TREE_OPERAND (purpose, 0);
+ tree upper = TREE_OPERAND (purpose, 1);
+
+ /* If the lower bound is equal to upper, just treat it as if
+ upper was the index. */
+ if (simple_cst_equal (lower, upper))
+ purpose = upper;
+ else
+ {
+ gimplify_init_ctor_eval_range (object, lower, upper, value,
+ array_elt_type, pre_p, cleared);
+ continue;
+ }
+ }
+ if (array_elt_type)
+ {
cref = build (ARRAY_REF, array_elt_type, unshare_expr (object),
purpose, NULL_TREE, NULL_TREE);
}
case ARRAY_TYPE:
{
struct gimplify_init_ctor_preeval_data preeval_data;
- HOST_WIDE_INT num_elements, num_nonzero_elements;
- HOST_WIDE_INT num_nonconstant_elements;
+ HOST_WIDE_INT num_type_elements, num_ctor_elements;
+ HOST_WIDE_INT num_nonzero_elements, num_nonconstant_elements;
bool cleared;
/* Aggregate types must lower constructors to initialization of
break;
categorize_ctor_elements (ctor, &num_nonzero_elements,
- &num_nonconstant_elements);
+ &num_nonconstant_elements,
+ &num_ctor_elements);
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
}
/* If there are "lots" of initialized elements, even discounting
- those that are not address constants (and thus *must* be
+ those that are not address constants (and thus *must* be
computed at runtime), then partition the constructor into
constant and non-constant parts. Block copy the constant
parts in, then generate code for the non-constant parts. */
/* TODO. There's code in cp/typeck.c to do this. */
- num_elements = count_type_elements (TREE_TYPE (ctor));
+ 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_elements - num_nonzero_elements > CLEAR_RATIO
- && num_nonzero_elements < num_elements/4)
+ if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
+ && num_nonzero_elements < num_type_elements/4)
cleared = true;
/* ??? This bit ought not be needed. For any element not present
we'd need to *find* the elements that are not present, and that
requires trickery to avoid quadratic compile-time behavior in
large cases or excessive memory use in small cases. */
- else
- {
- HOST_WIDE_INT len = list_length (elt_list);
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- tree nelts = array_type_nelts (type);
- if (!host_integerp (nelts, 1)
- || tree_low_cst (nelts, 1) + 1 != len)
- cleared = true;
- }
- else if (len != fields_length (type))
- cleared = true;
- }
+ else if (num_ctor_elements < num_type_elements)
+ cleared = true;
if (cleared)
{
append_to_statement_list (*expr_p, pre_p);
}
- preeval_data.lhs_base_decl = get_base_address (object);
- if (!DECL_P (preeval_data.lhs_base_decl))
- preeval_data.lhs_base_decl = NULL;
- preeval_data.lhs_alias_set = get_alias_set (object);
-
- gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
- pre_p, post_p, &preeval_data);
- gimplify_init_ctor_eval (object, elt_list, pre_p, cleared);
+ /* If we have not block cleared the object, or if there are nonzero
+ elements in the constructor, add assignments to the individual
+ scalar fields of the object. */
+ if (!cleared || num_nonzero_elements > 0)
+ {
+ preeval_data.lhs_base_decl = get_base_address (object);
+ if (!DECL_P (preeval_data.lhs_base_decl))
+ preeval_data.lhs_base_decl = NULL;
+ preeval_data.lhs_alias_set = get_alias_set (object);
+
+ gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
+ pre_p, post_p, &preeval_data);
+ gimplify_init_ctor_eval (object, elt_list, pre_p, cleared);
+ }
*expr_p = NULL_TREE;
}
if (elt_list)
{
i = TREE_VALUE (elt_list);
- if (TREE_CHAIN (elt_list))
- abort ();
+ gcc_assert (!TREE_CHAIN (elt_list));
}
}
if (r == NULL || i == NULL)
default:
/* So how did we get a CONSTRUCTOR for a scalar type? */
- abort ();
+ gcc_unreachable ();
}
if (ret == GS_ERROR)
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 pointer;
+
+ pointer = TREE_OPERAND (*from_p, 0);
+ STRIP_NOPS (pointer);
+ if (TREE_CODE (pointer) == ADDR_EXPR
+ && (lang_hooks.types_compatible_p
+ (TREE_TYPE (TREE_OPERAND (pointer, 0)),
+ TREE_TYPE (*from_p))))
+ {
+ *from_p = TREE_OPERAND (pointer, 0);
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+ }
+
case TARGET_EXPR:
{
/* If we are initializing something from a TARGET_EXPR, strip the
case COND_EXPR:
/* If we're assigning to a non-register type, push the assignment
down into the branches. This is mandatory for ADDRESSABLE types,
- since we cannot generate temporaries for such, but it saves a
+ since we cannot generate temporaries for such, but it saves a
copy in other cases as well. */
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;
tree *to_p = &TREE_OPERAND (*expr_p, 0);
enum gimplify_status ret = GS_UNHANDLED;
-#if defined ENABLE_CHECKING
- if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
- abort ();
-#endif
+ gcc_assert (TREE_CODE (*expr_p) == MODIFY_EXPR
+ || TREE_CODE (*expr_p) == INIT_EXPR);
/* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful. */
if (TREE_CODE (*expr_p) == INIT_EXPR)
{
/* If we've somehow already got an SSA_NAME on the LHS, then
we're probably modifying it twice. Not good. */
- if (TREE_CODE (*to_p) == SSA_NAME)
- abort ();
+ gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
*to_p = make_ssa_name (*to_p, *expr_p);
}
PRE_P points to the list where the side effects for all the
expressions in the sequence will be emitted.
-
+
WANT_VALUE is true when the result of the last COMPOUND_EXPR is used. */
/* ??? Should rearrange to share the pre-queue with all the indirect
- invocations of gimplify_expr. Would probably save on creations
+ invocations of gimplify_expr. Would probably save on creations
of statement_list nodes. */
static enum gimplify_status
enum gimplify_status ret = GS_ALL_DONE;
tree val;
-#if defined ENABLE_CHECKING
- if (TREE_CODE (*expr_p) != SAVE_EXPR)
- abort ();
-#endif
-
+ gcc_assert (TREE_CODE (*expr_p) == SAVE_EXPR);
val = TREE_OPERAND (*expr_p, 0);
/* If the SAVE_EXPR has not been resolved, then evaluate it once. */
switch (TREE_CODE (op0))
{
case INDIRECT_REF:
+ case MISALIGNED_INDIRECT_REF:
+ do_indirect_ref:
/* Check if we are dealing with an expression of the form '&*ptr'.
While the front end folds away '&*ptr' into 'ptr', these
expressions may be generated internally by the compiler (e.g.,
builtins like __builtin_va_end). */
- *expr_p = TREE_OPERAND (op0, 0);
- ret = GS_OK;
+ /* Caution: the silent array decomposition semantics we allow for
+ ADDR_EXPR means we can't always discard the pair. */
+ {
+ tree op00 = TREE_OPERAND (op0, 0);
+ tree t_expr = TREE_TYPE (expr);
+ tree t_op00 = TREE_TYPE (op00);
+
+ if (!lang_hooks.types_compatible_p (t_expr, t_op00))
+ {
+#ifdef ENABLE_CHECKING
+ tree t_op0 = TREE_TYPE (op0);
+ gcc_assert (TREE_CODE (t_op0) == ARRAY_TYPE
+ && POINTER_TYPE_P (t_expr)
+ && cpt_same_type (TREE_TYPE (t_op0),
+ TREE_TYPE (t_expr))
+ && POINTER_TYPE_P (t_op00)
+ && cpt_same_type (t_op0, TREE_TYPE (t_op00)));
+#endif
+ op00 = fold_convert (TREE_TYPE (expr), op00);
+ }
+ *expr_p = op00;
+ ret = GS_OK;
+ }
break;
case VIEW_CONVERT_EXPR:
??? The interactions of VIEW_CONVERT_EXPR and aliasing is not at
all clear. The impact of this transformation is even less clear. */
+
+ /* If the operand is a useless conversion, look through it. Doing so
+ guarantees that the ADDR_EXPR and its operand will remain of the
+ same type. */
+ if (tree_ssa_useless_type_conversion (TREE_OPERAND (op0, 0)))
+ op0 = TREE_OPERAND (op0, 0);
+
*expr_p = fold_convert (TREE_TYPE (expr),
build_fold_addr_expr (TREE_OPERAND (op0, 0)));
ret = GS_OK;
is_gimple_addressable, fb_either);
if (ret != GS_ERROR)
{
- /* The above may have made an INDIRECT_REF (e.g, Ada's NULL_EXPR),
- so check for it here. It's not worth checking for the other
- cases above. */
- if (TREE_CODE (TREE_OPERAND (expr, 0)) == INDIRECT_REF)
- {
- *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
- break;
- }
+ op0 = TREE_OPERAND (expr, 0);
+
+ /* For various reasons, the gimplification of the expression
+ may have made a new INDIRECT_REF. */
+ if (TREE_CODE (op0) == INDIRECT_REF)
+ goto do_indirect_ref;
/* Make sure TREE_INVARIANT, TREE_CONSTANT, and TREE_SIDE_EFFECTS
is set properly. */
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))
{
+ size_t constraint_len;
oconstraints[i] = constraint
= TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (link)));
+ constraint_len = strlen (constraint);
+ if (constraint_len == 0)
+ continue;
parse_output_constraint (&constraint, i, 0, 0,
&allows_mem, &allows_reg, &is_inout);
operands. */
tree input;
char buf[10];
- size_t constraint_len = strlen (constraint);
/* Turn the in/out constraint into an output constraint. */
char *p = xstrdup (constraint);
else
{
tret = gimplify_expr (&TREE_VALUE (link), pre_p, post_p,
- is_gimple_val, fb_rvalue);
+ is_gimple_asm_val, fb_rvalue);
if (tret == GS_ERROR)
ret = tret;
}
TREE_OPERAND (targ, 3) = init;
TARGET_EXPR_INITIAL (targ) = NULL_TREE;
}
- else if (!DECL_SEEN_IN_BIND_EXPR_P (temp))
+ else
/* We should have expanded this before. */
- abort ();
+ gcc_assert (DECL_SEEN_IN_BIND_EXPR_P (temp));
*expr_p = temp;
return GS_OK;
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:
break;
case TREE_LIST:
- abort ();
+ gcc_unreachable ();
case COMPOUND_EXPR:
ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
recalculate_side_effects (*expr_p);
break;
+ 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);
case CONST_DECL:
/* If we require an lvalue, such as for ADDR_EXPR, retain the
- CONST_DECL node. Otherwise the decl is replacable by its
+ CONST_DECL node. Otherwise the decl is replaceable by its
value. */
/* ??? Should be == fb_lvalue, but ADDR_EXPR passes fb_either. */
if (fallback & fb_lvalue)
ret = gimplify_switch_expr (expr_p, pre_p);
break;
- case LABELED_BLOCK_EXPR:
- ret = gimplify_labeled_block_expr (expr_p);
- break;
-
- case EXIT_BLOCK_EXPR:
- ret = gimplify_exit_block_expr (expr_p);
- break;
-
case EXIT_EXPR:
ret = gimplify_exit_expr (expr_p);
break;
case LABEL_EXPR:
ret = GS_ALL_DONE;
-#ifdef ENABLE_CHECKING
- if (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) != current_function_decl)
- abort ();
-#endif
+ gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p))
+ == current_function_decl);
break;
case CASE_LABEL_EXPR:
*expr_p = NULL_TREE;
}
-
+
ret = GS_ALL_DONE;
break;
case NON_LVALUE_EXPR:
/* This should have been stripped above. */
- abort ();
- break;
+ gcc_unreachable ();
case ASM_EXPR:
ret = gimplify_asm_expr (expr_p, pre_p, post_p);
case WITH_SIZE_EXPR:
{
enum gimplify_status r0, r1;
- r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
post_p == &internal_post ? NULL : post_p,
gimple_test_f, fallback);
r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
/* ??? If this is a local variable, and it has not been seen in any
outer BIND_EXPR, then it's probably the result of a duplicate
declaration, for which we've already issued an error. It would
- be really nice if the front end wouldn't leak these at all.
+ be really nice if the front end wouldn't leak these at all.
Currently the only known culprit is C++ destructors, as seen
in g++.old-deja/g++.jason/binding.C. */
tmp = *expr_p;
&& decl_function_context (tmp) == current_function_decl
&& !DECL_SEEN_IN_BIND_EXPR_P (tmp))
{
-#ifdef ENABLE_CHECKING
- if (!errorcount && !sorrycount)
- abort ();
-#endif
+ gcc_assert (errorcount || sorrycount);
ret = GS_ERROR;
break;
}
+ /* FALLTHRU */
+
+ case PARM_DECL:
+ tmp = *expr_p;
/* If this is a local variable sized decl, it must be accessed
indirectly. Perform that substitution. */
break;
default:
- /* If this is a comparison of objects of aggregate type, handle
- it specially (by converting to a call to memcmp). It would be
- nice to only have to do this for variable-sized objects, but
- then we'd have to allow the same nest of reference nodes we
- allow for MODIFY_EXPR and that's too complex. */
- if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
- && (AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1)))))
- ret = gimplify_variable_sized_compare (expr_p);
-
- /* If *EXPR_P does not need to be special-cased, handle it
- according to its class. */
- else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
- ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
- post_p, is_gimple_val, fb_rvalue);
- else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '<'
- || TREE_CODE (*expr_p) == TRUTH_AND_EXPR
- || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
- || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR)
+ switch (TREE_CODE_CLASS (TREE_CODE (*expr_p)))
{
- enum gimplify_status r0, r1;
+ case tcc_comparison:
+ /* If this is a comparison of objects of aggregate type,
+ handle it specially (by converting to a call to
+ memcmp). It would be nice to only have to do this
+ for variable-sized objects, but then we'd have to
+ allow the same nest of reference nodes we allow for
+ MODIFY_EXPR and that's too complex. */
+ if (!AGGREGATE_TYPE_P (TREE_TYPE (TREE_OPERAND (*expr_p, 1))))
+ goto expr_2;
+ ret = gimplify_variable_sized_compare (expr_p);
+ break;
- r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
- post_p, is_gimple_val, fb_rvalue);
- r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
- post_p, is_gimple_val, fb_rvalue);
+ /* If *EXPR_P does not need to be special-cased, handle it
+ according to its class. */
+ case tcc_unary:
+ ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ break;
- ret = MIN (r0, r1);
- }
- else if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'd'
- || TREE_CODE_CLASS (TREE_CODE (*expr_p)) == 'c')
- {
+ case tcc_binary:
+ expr_2:
+ {
+ enum gimplify_status r0, r1;
+
+ r0 = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+ r1 = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p,
+ post_p, is_gimple_val, fb_rvalue);
+
+ ret = MIN (r0, r1);
+ break;
+ }
+
+ case tcc_declaration:
+ case tcc_constant:
ret = GS_ALL_DONE;
- break;
+ goto dont_recalculate;
+
+ default:
+ gcc_assert (TREE_CODE (*expr_p) == TRUTH_AND_EXPR
+ || TREE_CODE (*expr_p) == TRUTH_OR_EXPR
+ || TREE_CODE (*expr_p) == TRUTH_XOR_EXPR);
+ goto expr_2;
}
- else
- /* Fail if we don't know how to handle this tree code. */
- abort ();
recalculate_side_effects (*expr_p);
+ dont_recalculate:
break;
}
goto out;
}
-#ifdef ENABLE_CHECKING
/* This was only valid as a return value from the langhook, which
we handled. Make sure it doesn't escape from any other context. */
- if (ret == GS_UNHANDLED)
- abort ();
-#endif
+ gcc_assert (ret != GS_UNHANDLED);
if (fallback == fb_none && *expr_p && !is_gimple_stmt (*expr_p))
{
has side effects. Recurse through the operands to find it. */
enum tree_code code = TREE_CODE (*expr_p);
- if (code == COMPONENT_REF
- || code == REALPART_EXPR || code == IMAGPART_EXPR)
- gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
- gimple_test_f, fallback);
- else if (code == ARRAY_REF || code == ARRAY_RANGE_REF)
+ switch (code)
{
+ case COMPONENT_REF:
+ case REALPART_EXPR: case IMAGPART_EXPR:
+ gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ gimple_test_f, fallback);
+ break;
+
+ case ARRAY_REF: case ARRAY_RANGE_REF:
gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
gimple_test_f, fallback);
gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
- gimple_test_f, fallback);
+ gimple_test_f, fallback);
+ break;
+
+ default:
+ /* Anything else with side-effects must be converted to
+ a valid statement before we get here. */
+ gcc_unreachable ();
}
- else
- /* Anything else with side-effects
- must be converted to a valid statement before we get here. */
- abort ();
*expr_p = NULL;
}
}
else if ((fallback & fb_rvalue) && is_gimple_formal_tmp_rhs (*expr_p))
{
-#if defined ENABLE_CHECKING
- if (VOID_TYPE_P (TREE_TYPE (*expr_p)))
- abort ();
-#endif
+ gcc_assert (!VOID_TYPE_P (TREE_TYPE (*expr_p)));
/* An rvalue will do. Assign the gimplified expression into a new
temporary TMP and replace the original expression with TMP. */
if (TREE_CODE (*expr_p) != SSA_NAME)
DECL_GIMPLE_FORMAL_TEMP_P (*expr_p) = 1;
}
- else if (fallback & fb_mayfail)
+ else
{
- /* If this is an asm statement, and the user asked for the impossible,
- don't abort. Fail and let gimplify_asm_expr issue an error. */
+#ifdef ENABLE_CHECKING
+ if (!(fallback & fb_mayfail))
+ {
+ fprintf (stderr, "gimplification failed:\n");
+ print_generic_expr (stderr, *expr_p, 0);
+ debug_tree (*expr_p);
+ internal_error ("gimplification failed");
+ }
+#endif
+ gcc_assert (fallback & fb_mayfail);
+ /* If this is an asm statement, and the user asked for the
+ impossible, don't abort. Fail and let gimplify_asm_expr
+ issue an error. */
ret = GS_ERROR;
goto out;
}
- else
- {
- fprintf (stderr, "gimplification failed:\n");
- print_generic_expr (stderr, *expr_p, 0);
- debug_tree (*expr_p);
- abort ();
- }
-#if defined ENABLE_CHECKING
/* Make sure the temporary matches our predicate. */
- if (!(*gimple_test_f) (*expr_p))
- abort ();
-#endif
+ gcc_assert ((*gimple_test_f) (*expr_p));
if (internal_post)
{
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 gimplifcation 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
otype = TREE_TYPE (t);
ptype = TREE_TYPE (TREE_OPERAND (t, 0));
dtype = TREE_TYPE (ptype);
- if (!cpt_same_type (otype, dtype))
- abort ();
+ gcc_assert (cpt_same_type (otype, dtype));
break;
case ADDR_EXPR:
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. */
- if (TREE_CODE (otype) == ARRAY_TYPE
- && POINTER_TYPE_P (ptype)
- && cpt_same_type (TREE_TYPE (otype), dtype))
- break;
- abort ();
+ gcc_assert (TREE_CODE (otype) == ARRAY_TYPE
+ && POINTER_TYPE_P (ptype)
+ && cpt_same_type (TREE_TYPE (otype), dtype));
+ break;
}
break;
function decl containing BODY. */
void
-gimplify_body (tree *body_p, tree fndecl)
+gimplify_body (tree *body_p, tree fndecl, bool do_parms)
{
location_t saved_location = input_location;
- tree body;
+ tree body, parm_stmts;
timevar_push (TV_TREE_GIMPLIFY);
push_gimplify_context ();
/* Make sure input_location isn't set to something wierd. */
input_location = DECL_SOURCE_LOCATION (fndecl);
+ /* 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;
- /* Unshare again, in case gimplification was sloppy. */
- unshare_all_trees (body);
-
if (!body)
body = alloc_stmt_list ();
else if (TREE_CODE (body) == STATEMENT_LIST)
append_to_statement_list_force (body, &BIND_EXPR_BODY (b));
body = b;
}
+
+ /* 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);
oldfn = current_function_decl;
current_function_decl = fndecl;
+ cfun = DECL_STRUCT_FUNCTION (fndecl);
+ if (cfun == NULL)
+ allocate_struct_function (fndecl);
- gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl);
+ 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
}
current_function_decl = oldfn;
+ cfun = oldfn ? DECL_STRUCT_FUNCTION (oldfn) : NULL;
}
\f
ret = gimplify_expr (&expr, stmts, NULL,
gimple_test_f, fb_rvalue);
- if (ret == GS_ERROR)
- abort ();
+ gcc_assert (ret != GS_ERROR);
for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
add_referenced_tmp_var (t);