aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r--gcc/gimplify.c771
1 files changed, 576 insertions, 195 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index f6e4a04..3649272 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1,6 +1,5 @@
/* 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.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
@@ -36,6 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "langhooks.h"
#include "langhooks-def.h"
#include "tree-flow.h"
+#include "cgraph.h"
#include "timevar.h"
#include "except.h"
#include "hashtab.h"
@@ -71,6 +71,73 @@ typedef struct gimple_temp_hash_elt
tree temp; /* Value */
} elt_t;
+/* Forward declarations. */
+static hashval_t gimple_tree_hash (const void *);
+static int gimple_tree_eq (const void *, const void *);
+static bool gimple_conditional_context (void);
+static void gimple_push_condition (void);
+static void gimple_pop_condition (tree *);
+static void append_to_statement_list_1 (tree, tree *, bool);
+static inline void remove_suffix (char *, int);
+static inline tree create_tmp_from_val (tree);
+static tree lookup_tmp_var (tree, bool);
+static tree internal_get_tmp_var (tree, tree *, tree *, bool);
+static bool should_carry_locus_p (tree);
+static tree mostly_copy_tree_r (tree *, int *, void *);
+static tree mark_decls_volatile_r (tree *, int *, void *);
+static tree copy_if_shared_r (tree *, int *, void *);
+static tree unmark_visited_r (tree *, int *, void *);
+static void unshare_body (tree *, tree);
+static void unvisit_body (tree *, tree);
+static void build_stack_save_restore (tree *, tree *);
+static enum gimplify_status gimplify_bind_expr (tree *, tree, tree *);
+static enum gimplify_status gimplify_return_expr (tree, tree *);
+static enum gimplify_status gimplify_loop_expr (tree *, tree *);
+static int compare_case_labels (const void *, const void *);
+static enum gimplify_status gimplify_switch_expr (tree *, tree *);
+static enum gimplify_status gimplify_case_label_expr (tree *);
+static enum gimplify_status gimplify_labeled_block_expr (tree *);
+static enum gimplify_status gimplify_exit_block_expr (tree *);
+static enum gimplify_status gimplify_exit_expr (tree *);
+static enum gimplify_status gimplify_init_constructor (tree *, tree *, tree *,
+ bool);
+static void canonicalize_component_ref (tree *);
+static void canonicalize_addr_expr (tree *);
+static enum gimplify_status gimplify_conversion (tree *);
+static enum gimplify_status gimplify_minimax_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_array_ref_to_plus (tree *, tree *,
+ tree *);
+static tree build_addr_expr_with_type (tree, tree);
+static tree build_addr_expr (tree);
+static enum gimplify_status gimplify_compound_lval (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_self_mod_expr (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_call_expr (tree *, tree *,
+ bool (*) (tree));
+static tree shortcut_cond_r (tree, tree *, tree *);
+static tree shortcut_cond_expr (tree);
+static tree gimple_boolify (tree);
+static enum gimplify_status gimplify_cond_expr (tree *, tree *, tree);
+static enum gimplify_status gimplify_modify_expr (tree *, tree *, tree *,
+ bool);
+static enum gimplify_status gimplify_modify_expr_rhs (tree *, tree *, tree *,
+ tree *, tree *, bool);
+static enum gimplify_status gimplify_variable_sized_compare (tree *);
+static enum gimplify_status gimplify_boolean_expr (tree *);
+static enum gimplify_status gimplify_compound_expr (tree *, tree *, bool);
+static enum gimplify_status gimplify_statement_list (tree *);
+static enum gimplify_status gimplify_save_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_addr_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_asm_expr (tree *, tree *, tree *);
+static enum gimplify_status gimplify_cleanup_point_expr (tree *, tree *);
+static void gimple_push_cleanup (tree, tree, tree *);
+static enum gimplify_status gimplify_target_expr (tree *, tree *, tree *);
+#ifdef ENABLE_CHECKING
+static bool cpt_same_type (tree, tree);
+static tree check_pointer_types_r (tree *, int *, void *);
+#endif
+
/* Return a hash value for a formal temporary table entry. */
static hashval_t
@@ -355,15 +422,11 @@ create_tmp_var (tree type, const char *prefix)
tree tmp_var;
#if defined ENABLE_CHECKING
- /* If the type is an array or a type which must be created by the
- frontend, something is wrong. */
- if (TREE_CODE (type) == ARRAY_TYPE || TREE_ADDRESSABLE (type))
- abort ();
- if (!COMPLETE_TYPE_P (type))
- abort ();
- /* Variable sized types require lots of machinery to create; the
- optimizers shouldn't be doing anything of the sort. */
- if (TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST)
+ /* 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
@@ -653,11 +716,19 @@ copy_if_shared_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
tree t = *tp;
enum tree_code code = TREE_CODE (t);
- /* Skip types, decls, and constants. */
+ /* Skip types, decls, and constants. But we do want to look at their
+ 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')
- *walk_subtrees = 0;
+ {
+ if (TREE_VISITED (t))
+ *walk_subtrees = 0;
+ else
+ TREE_VISITED (t) = 1;
+ }
/* Special-case BIND_EXPR. We should never be copying these, therefore
we can omit examining BIND_EXPR_VARS. Which also avoids problems with
@@ -715,6 +786,31 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
return NULL_TREE;
}
+/* Unshare all the trees in BODY_P, a pointer to the body of FNDECL, and the
+ bodies of any nested functions. */
+
+static void
+unshare_body (tree *body_p, tree fndecl)
+{
+ struct cgraph_node *cgn = cgraph_node (fndecl);
+
+ walk_tree (body_p, copy_if_shared_r, NULL, NULL);
+ for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ unshare_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
+/* Likewise, but mark all trees as not visited. */
+
+static void
+unvisit_body (tree *body_p, tree fndecl)
+{
+ struct cgraph_node *cgn = cgraph_node (fndecl);
+
+ walk_tree (body_p, unmark_visited_r, NULL, NULL);
+ for (cgn = cgn->nested; cgn; cgn = cgn->next_nested)
+ unvisit_body (&DECL_SAVED_TREE (cgn->decl), cgn->decl);
+}
+
/* Unshare T and all the trees reached from T via TREE_CHAIN. */
void
@@ -1192,7 +1288,7 @@ build_and_jump (tree *label_p)
{
if (label_p == NULL)
/* If there's nowhere to jump, just fall through. */
- return build_empty_stmt ();
+ return alloc_stmt_list ();
if (*label_p == NULL_TREE)
{
@@ -1214,7 +1310,7 @@ gimplify_exit_expr (tree *expr_p)
tree expr;
expr = build_and_jump (&gimplify_ctxp->exit_label);
- expr = build (COND_EXPR, void_type_node, cond, expr, build_empty_stmt ());
+ expr = build (COND_EXPR, void_type_node, cond, expr, alloc_stmt_list ());
*expr_p = expr;
return GS_OK;
@@ -1243,7 +1339,7 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
- tree *post_p, int want_value)
+ tree *post_p, bool want_value)
{
tree object = TREE_OPERAND (*expr_p, 0);
tree ctor = TREE_OPERAND (*expr_p, 1);
@@ -1279,7 +1375,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
return GS_OK;
}
else
- return GS_ALL_DONE;
+ return GS_UNHANDLED;
}
categorize_ctor_elements (ctor, &num_nonzero_elements,
@@ -1307,7 +1403,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
TU-local symbol, we must invoke the lhd version now. */
lhd_set_decl_assembler_name (object);
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
break;
}
@@ -1416,13 +1512,11 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
if (TREE_CODE (purpose) == RANGE_EXPR)
abort ();
- cref = build (ARRAY_REF, t, object, purpose);
+ cref = build (ARRAY_REF, t, object, purpose, NULL_TREE, NULL_TREE);
}
else
- {
- cref = build (COMPONENT_REF, TREE_TYPE (purpose),
- object, purpose);
- }
+ cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
+ purpose, NULL_TREE);
init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
/* Each member initialization is a full-expression. */
@@ -1430,7 +1524,7 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
append_to_statement_list (init, pre_p);
}
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
break;
@@ -1552,18 +1646,17 @@ canonicalize_component_ref (tree *expr_p)
}
/* If a NOP conversion is changing a pointer to array of foo to a pointer
- to foo, embed that change in the ADDR_EXPR. Lest we perturb the type
- system too badly, we must take extra steps to ensure that the ADDR_EXPR
- and the addressed object continue to agree on types. */
-/* ??? We might could do better if we recognize
- T array[N][M];
- (T *)&array
+ to foo, embed that change in the ADDR_EXPR by converting
+ T array[U];
+ (T *)&array
==>
- &array[0][0];
-*/
+ &array[L]
+ where L is the lower bound. Only do this for constant lower bound since
+ we have no place to put any statements made during gimplification of
+ the lower bound. */
static void
-canonicalize_addr_expr (tree* expr_p)
+canonicalize_addr_expr (tree *expr_p)
{
tree expr = *expr_p;
tree ctype = TREE_TYPE (expr);
@@ -1592,8 +1685,20 @@ canonicalize_addr_expr (tree* expr_p)
if (!lang_hooks.types_compatible_p (otype, datype))
return;
+ /* The lower bound and element sizes must be constant. */
+ if (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;
+
/* All checks succeeded. Build a new node to merge the cast. */
- *expr_p = build1 (ADDR_EXPR, ctype, obj_expr);
+ *expr_p = build4 (ARRAY_REF, dctype, obj_expr,
+ TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+ TYPE_MIN_VALUE (TYPE_DOMAIN (datype)),
+ size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (dctype),
+ size_int (TYPE_ALIGN (dctype)
+ / BITS_PER_UNIT)));
+ *expr_p = build1 (ADDR_EXPR, ctype, *expr_p);
}
/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions
@@ -1666,7 +1771,7 @@ gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
return GS_OK;
}
-/* Subroutine of gimplify_compound_lval and gimplify_array_ref.
+/* Subroutine of gimplify_compound_lval.
Converts an ARRAY_REF to the equivalent *(&array + offset) form. */
static enum gimplify_status
@@ -1675,25 +1780,21 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
tree array = TREE_OPERAND (*expr_p, 0);
tree arrtype = TREE_TYPE (array);
tree elttype = TREE_TYPE (arrtype);
- tree size = size_in_bytes (elttype);
+ tree size = array_ref_element_size (*expr_p);
tree ptrtype = build_pointer_type (elttype);
enum tree_code add_code = PLUS_EXPR;
tree idx = TREE_OPERAND (*expr_p, 1);
- tree minidx, offset, addr, result;
+ tree minidx = unshare_expr (array_ref_low_bound (*expr_p));
+ tree offset, addr, result;
enum gimplify_status ret;
/* If the array domain does not start at zero, apply the offset. */
- minidx = TYPE_DOMAIN (arrtype);
- if (minidx)
+ if (!integer_zerop (minidx))
{
- minidx = TYPE_MIN_VALUE (minidx);
- if (minidx && !integer_zerop (minidx))
- {
- idx = convert (TREE_TYPE (minidx), idx);
- idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
- }
+ idx = convert (TREE_TYPE (minidx), idx);
+ idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
}
-
+
/* If the index is negative -- a technically invalid situation now
that we've biased the index back to zero -- then casting it to
unsigned has ill effects. In particular, -1*4U/4U != -1.
@@ -1707,7 +1808,7 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
}
/* Pointer arithmetic must be done in sizetype. */
- idx = convert (sizetype, idx);
+ idx = fold_convert (sizetype, idx);
/* Convert the index to a byte offset. */
offset = size_binop (MULT_EXPR, size, idx);
@@ -1723,6 +1824,44 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
return GS_OK;
}
+/* Build an expression for the address of T. Folds away INDIRECT_REF to
+ avoid confusing the gimplify process. */
+
+static tree
+build_addr_expr_with_type (tree t, tree ptrtype)
+{
+ if (TREE_CODE (t) == INDIRECT_REF)
+ {
+ t = TREE_OPERAND (t, 0);
+ if (TREE_TYPE (t) != ptrtype)
+ t = build1 (NOP_EXPR, ptrtype, t);
+ }
+ else
+ {
+ tree base = t;
+
+ if (TREE_CODE (base) == REALPART_EXPR
+ || TREE_CODE (base) == IMAGPART_EXPR)
+ base = TREE_OPERAND (base, 0);
+ else
+ while (handled_component_p (base))
+ base = TREE_OPERAND (base, 0);
+
+ if (DECL_P (base))
+ TREE_ADDRESSABLE (base) = 1;
+
+ t = build1 (ADDR_EXPR, ptrtype, t);
+ }
+
+ return t;
+}
+
+static tree
+build_addr_expr (tree t)
+{
+ return build_addr_expr_with_type (t, build_pointer_type (TREE_TYPE (t)));
+}
+
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
node pointed by EXPR_P.
@@ -1747,63 +1886,49 @@ gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
static enum gimplify_status
gimplify_compound_lval (tree *expr_p, tree *pre_p,
- tree *post_p, int want_lvalue)
+ tree *post_p, bool want_lvalue)
{
tree *p;
- enum tree_code code;
varray_type stack;
- enum gimplify_status ret;
+ enum gimplify_status ret = GS_OK, tret;
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != ARRAY_REF
+ && TREE_CODE (*expr_p) != ARRAY_RANGE_REF
&& TREE_CODE (*expr_p) != COMPONENT_REF
+ && TREE_CODE (*expr_p) != BIT_FIELD_REF
&& TREE_CODE (*expr_p) != REALPART_EXPR
&& TREE_CODE (*expr_p) != IMAGPART_EXPR)
abort ();
#endif
- code = ERROR_MARK; /* [GIMPLE] Avoid uninitialized use warning. */
-
/* Create a stack of the subexpressions so later we can walk them in
order from inner to outer. */
VARRAY_TREE_INIT (stack, 10, "stack");
- for (p = expr_p;
- TREE_CODE (*p) == ARRAY_REF
- || TREE_CODE (*p) == COMPONENT_REF
- || TREE_CODE (*p) == REALPART_EXPR
- || TREE_CODE (*p) == IMAGPART_EXPR;
- p = &TREE_OPERAND (*p, 0))
- {
- code = TREE_CODE (*p);
- if (code == ARRAY_REF)
- {
- tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*p, 0)));
- if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
- /* If the size of the array elements is not constant,
- computing the offset is non-trivial, so expose it. */
- break;
- }
+ /* We can either handle one REALPART_EXPR or IMAGEPART_EXPR or
+ nest of handled components. */
+ if (TREE_CODE (*expr_p) == REALPART_EXPR
+ || TREE_CODE (*expr_p) == IMAGPART_EXPR)
+ p = &TREE_OPERAND (*expr_p, 0);
+ else
+ for (p = expr_p; handled_component_p (*p); p = &TREE_OPERAND (*p, 0))
VARRAY_PUSH_TREE (stack, *p);
- }
-
- /* Now 'p' points to the first bit that isn't a ref, 'code' is the
- TREE_CODE of the last bit that was, and 'stack' is a stack of pointers
- to all the refs we've walked through.
- Gimplify the base, and then process each of the outer nodes from left
- to right. */
- ret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
- code != ARRAY_REF ? fb_either : fb_lvalue);
+ /* Now STACK is a stack of pointers to all the refs we've walked through
+ and P points to the innermost expression.
+ Process each of the outer nodes from left to right, then gimplify the
+ base. We need to do it in this order so that PLACEHOLDER_EXPRs
+ can be resolved. */
for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
{
tree t = VARRAY_TOP_TREE (stack);
- if (TREE_CODE (t) == ARRAY_REF)
+
+ if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
- /* Gimplify the dimension. */
- enum gimplify_status tret;
- /* Temporary fix for gcc.c-torture/execute/20040313-1.c.
+ /* Gimplify the dimension.
+ Temporary fix for gcc.c-torture/execute/20040313-1.c.
Gimplify non-constant array indices into a temporary
variable.
FIXME - The real fix is to gimplify post-modify
@@ -1815,14 +1940,82 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
{
tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
- if (tret == GS_ERROR)
- ret = GS_ERROR;
+ ret = MIN (ret, tret);
+ }
+
+ /* Gimplify the low bound and element type size and put them into
+ the ARRAY_REF. If these values are set, they have already been
+ gimplified. */
+ if (!TREE_OPERAND (t, 2))
+ {
+ TREE_OPERAND (t, 2) = unshare_expr (array_ref_low_bound (t));
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_tmp_var, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+ }
+
+ if (!TREE_OPERAND (t, 3))
+ {
+ tree elmt_type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (t, 0)));
+ tree elmt_size = unshare_expr (array_ref_element_size (t));
+ tree factor = size_int (TYPE_ALIGN (elmt_type) / BITS_PER_UNIT);
+
+ /* Divide the element size by the alignment of the element
+ type (above). */
+ elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
+
+ TREE_OPERAND (t, 3) = elmt_size;
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 3)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
+ is_gimple_tmp_var, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
}
}
+ else if (TREE_CODE (t) == COMPONENT_REF)
+ {
+ /* Set the field offset into T and gimplify it. */
+ if (!TREE_OPERAND (t, 2))
+ {
+ tree offset = unshare_expr (component_ref_field_offset (t));
+ tree field = TREE_OPERAND (t, 1);
+ tree factor
+ = size_int (DECL_OFFSET_ALIGN (field) / BITS_PER_UNIT);
+
+ /* Divide the offset by its alignment. */
+ offset = size_binop (EXACT_DIV_EXPR, offset, factor);
+
+ TREE_OPERAND (t, 2) = offset;
+ if (!is_gimple_min_invariant (TREE_OPERAND (t, 2)))
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_tmp_var, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+ }
+ }
+ else if (TREE_CODE (t) == BIT_FIELD_REF)
+ {
+ tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
+ tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
+ }
+
recalculate_side_effects (t);
VARRAY_POP (stack);
}
+ tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
+ want_lvalue ? fb_lvalue : fb_rvalue);
+ ret = MIN (ret, tret);
+
/* If the outermost expression is a COMPONENT_REF, canonicalize its type. */
if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
{
@@ -1833,33 +2026,6 @@ gimplify_compound_lval (tree *expr_p, tree *pre_p,
return ret;
}
-/* Re-write the ARRAY_REF node pointed by EXPR_P.
-
- PRE_P points to the list where side effects that must happen before
- *EXPR_P should be stored.
-
- POST_P points to the list where side effects that must happen after
- *EXPR_P should be stored.
-
- FIXME: ARRAY_REF currently doesn't accept a pointer as the array
- argument, so this gimplification uses an INDIRECT_REF of ARRAY_TYPE.
- ARRAY_REF should be extended. */
-
-static enum gimplify_status
-gimplify_array_ref (tree *expr_p, tree *pre_p,
- tree *post_p, int want_lvalue)
-{
- tree elttype = TREE_TYPE (TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
- if (!TREE_CONSTANT (TYPE_SIZE_UNIT (elttype)))
- /* If the size of the array elements is not constant,
- computing the offset is non-trivial, so expose it. */
- return gimplify_array_ref_to_plus (expr_p, pre_p, post_p);
- else
- /* Handle array and member refs together for now. When alias analysis
- improves, we may want to go back to handling them separately. */
- return gimplify_compound_lval (expr_p, pre_p, post_p, want_lvalue);
-}
-
/* Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
PRE_P points to the list where side effects that must happen before
@@ -1873,7 +2039,7 @@ gimplify_array_ref (tree *expr_p, tree *pre_p,
static enum gimplify_status
gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
- int want_value)
+ bool want_value)
{
enum tree_code code;
tree lhs, lvalue, rhs, t1;
@@ -2166,7 +2332,7 @@ shortcut_cond_expr (tree expr)
then_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, then_,
- build_empty_stmt ());
+ alloc_stmt_list ());
}
}
if (!TREE_SIDE_EFFECTS (then_))
@@ -2181,7 +2347,7 @@ shortcut_cond_expr (tree expr)
else_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred,
- build_empty_stmt (), else_);
+ alloc_stmt_list (), else_);
}
}
@@ -2207,14 +2373,14 @@ shortcut_cond_expr (tree expr)
&& TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
{
true_label = GOTO_DESTINATION (then_);
- then_ = build_empty_stmt ();
+ then_ = alloc_stmt_list ();
}
if (TREE_CODE (else_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
{
false_label = GOTO_DESTINATION (else_);
- else_ = build_empty_stmt ();
+ else_ = alloc_stmt_list ();
}
/* If we aren't hijacking a label for the 'then' branch, it falls through. */
@@ -2329,6 +2495,8 @@ gimple_boolify (tree expr)
The second form is used when *EXPR_P is of type void.
+ 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. */
@@ -2456,7 +2624,7 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
{
tree *from_p = &TREE_OPERAND (*expr_p, 1);
tree *to_p = &TREE_OPERAND (*expr_p, 0);
- enum gimplify_status ret;
+ enum gimplify_status ret = GS_UNHANDLED;
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != MODIFY_EXPR && TREE_CODE (*expr_p) != INIT_EXPR)
@@ -2467,40 +2635,51 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
if (TREE_CODE (*expr_p) == INIT_EXPR)
TREE_SET_CODE (*expr_p, MODIFY_EXPR);
- ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
- if (ret == GS_ERROR)
+ /* See if any simplifications can be done based on what the RHS is. */
+ ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+ want_value);
+ if (ret != GS_UNHANDLED)
return ret;
- /* If we are initializing something from a TARGET_EXPR, strip the
- TARGET_EXPR and initialize it directly, if possible. This can't
- be done if the initializer is void, since that implies that the
- temporary is set in some non-trivial way. */
- /* What about code that pulls out the temp and uses it elsewhere? I
- think that such code never uses the TARGET_EXPR as an initializer. If
- I'm wrong, we'll abort because the temp won't have any RTL. In that
- case, I guess we'll need to replace references somehow. */
- if (TREE_CODE (*from_p) == TARGET_EXPR)
+ /* If the value being copied is of variable width, expose the length
+ if the copy by converting the whole thing to a memcpy. Note that
+ we need to do this before gimplifying any of the operands
+ so that we can resolve any PLACEHOLDER_EXPRs in the size. */
+ if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST)
{
- tree init = TARGET_EXPR_INITIAL (*from_p);
- if (!VOID_TYPE_P (TREE_TYPE (init)))
- *from_p = init;
+ tree args, t, dest;
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *to_p);
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, *from_p);
+ t = unshare_expr (t);
+ args = tree_cons (NULL, t, NULL);
+ t = build_fold_addr_expr (*from_p);
+ args = tree_cons (NULL, t, args);
+ dest = build_fold_addr_expr (*to_p);
+ args = tree_cons (NULL, dest, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ t = build_function_call_expr (t, args);
+ if (want_value)
+ {
+ t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
+ t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
+ }
+ *expr_p = t;
+ return GS_OK;
}
- /* If we're assigning from a ?: expression with ADDRESSABLE type, push
- the assignment down into the branches, since we can't generate a
- temporary of such a type. */
- if (TREE_CODE (*from_p) == COND_EXPR
- && TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
- {
- *expr_p = *from_p;
- return gimplify_cond_expr (expr_p, pre_p, *to_p);
- }
+ ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
+ if (ret == GS_ERROR)
+ return ret;
ret = gimplify_expr (from_p, pre_p, post_p, is_gimple_rhs, fb_rvalue);
if (ret == GS_ERROR)
return ret;
- ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+ /* Now see if the above changed *from_p to something we handle specially. */
+ ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
+ want_value);
if (ret != GS_UNHANDLED)
return ret;
@@ -2530,35 +2709,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
&& !is_gimple_reg (*to_p)))
gimplify_expr (from_p, pre_p, post_p, is_gimple_val, fb_rvalue);
- /* If the value being copied is of variable width, expose the length
- if the copy by converting the whole thing to a memcpy. */
- /* ??? Except that we can't manage this with VA_ARG_EXPR. Yes, this
- does leave us with an edge condition that doesn't work. The only
- way out is to rearrange how VA_ARG_EXPR works. */
- if (TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (*to_p))) != INTEGER_CST
- && TREE_CODE (*from_p) != VA_ARG_EXPR)
- {
- tree args, t, dest;
-
- t = TYPE_SIZE_UNIT (TREE_TYPE (*to_p));
- t = unshare_expr (t);
- args = tree_cons (NULL, t, NULL);
- t = build_fold_addr_expr (*from_p);
- args = tree_cons (NULL, t, args);
- dest = build_fold_addr_expr (*to_p);
- args = tree_cons (NULL, dest, args);
- t = implicit_built_in_decls[BUILT_IN_MEMCPY];
- t = build_function_call_expr (t, args);
- if (want_value)
- {
- t = build1 (NOP_EXPR, TREE_TYPE (dest), t);
- t = build1 (INDIRECT_REF, TREE_TYPE (*to_p), t);
- }
- *expr_p = t;
-
- return GS_OK;
- }
-
ret = want_value ? GS_OK : GS_ALL_DONE;
}
@@ -2571,6 +2721,101 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
return ret;
}
+/* Subroutine of above to do simplications of MODIFY_EXPRs based on
+ the code of the RHS. We loop for as long as we can do something. */
+
+static enum gimplify_status
+gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
+ tree *post_p, bool want_value)
+{
+ enum gimplify_status ret = GS_OK;
+
+ while (ret != GS_UNHANDLED)
+ switch (TREE_CODE (*from_p))
+ {
+ case TARGET_EXPR:
+ {
+ /* If we are initializing something from a TARGET_EXPR, strip the
+ TARGET_EXPR and initialize it directly, if possible. This can't
+ be done if the initializer is void, since that implies that the
+ temporary is set in some non-trivial way.
+
+ ??? What about code that pulls out the temp and uses it
+ elsewhere? I think that such code never uses the TARGET_EXPR as
+ an initializer. If I'm wrong, we'll abort because the temp won't
+ have any RTL. In that case, I guess we'll need to replace
+ references somehow. */
+ tree init = TARGET_EXPR_INITIAL (*from_p);
+
+ if (!VOID_TYPE_P (TREE_TYPE (init)))
+ {
+ *from_p = init;
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ }
+ break;
+
+ case COMPOUND_EXPR:
+ /* Remove any COMPOUND_EXPR in the RHS so the following cases will be
+ caught. */
+ gimplify_compound_expr (from_p, pre_p, true);
+ ret = GS_OK;
+ break;
+
+ case CONSTRUCTOR:
+ /* If we're initializing from a CONSTRUCTOR, break this into
+ individual MODIFY_EXPRs. */
+ return gimplify_init_constructor (expr_p, pre_p, post_p, want_value);
+
+ case COND_EXPR:
+ /* If we're assigning from a ?: expression with ADDRESSABLE type, push
+ the assignment down into the branches, since we can't generate a
+ temporary of such a type. */
+ if (TREE_ADDRESSABLE (TREE_TYPE (*from_p)))
+ {
+ *expr_p = *from_p;
+ return gimplify_cond_expr (expr_p, pre_p, *to_p);
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+
+ default:
+ ret = GS_UNHANDLED;
+ break;
+ }
+
+ return ret;
+}
+
+/* Gimplify a comparison between two variable-sized objects. Do this
+ with a call to BUILT_IN_MEMCMP. */
+
+static enum gimplify_status
+gimplify_variable_sized_compare (tree *expr_p)
+{
+ tree op0 = TREE_OPERAND (*expr_p, 0);
+ tree op1 = TREE_OPERAND (*expr_p, 1);
+ tree args, t, dest;
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (op0));
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, op0);
+ t = unshare_expr (t);
+ args = tree_cons (NULL, t, NULL);
+ t = build_addr_expr (op1);
+ args = tree_cons (NULL, t, args);
+ dest = build_addr_expr (op0);
+ args = tree_cons (NULL, dest, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMCMP];
+ t = build_function_call_expr (t, args);
+ *expr_p
+ = build (TREE_CODE (*expr_p), TREE_TYPE (*expr_p), t, integer_zero_node);
+
+ return GS_OK;
+}
+
/* Gimplify TRUTH_ANDIF_EXPR and TRUTH_ORIF_EXPR expressions. EXPR_P
points to the expression to gimplify.
@@ -2696,7 +2941,7 @@ gimplify_save_expr (tree *expr_p, tree *pre_p, tree *post_p)
tree body = TREE_OPERAND (*expr_p, 0);
ret = gimplify_expr (& body, pre_p, post_p, is_gimple_stmt, fb_none);
append_to_statement_list (body, pre_p);
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
else
*expr_p = TREE_OPERAND (*expr_p, 0)
@@ -2742,9 +2987,15 @@ gimplify_addr_expr (tree *expr_p, tree *pre_p, tree *post_p)
pre_p, post_p);
/* This added an INDIRECT_REF. Fold it away. */
- op0 = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+ *expr_p = TREE_OPERAND (TREE_OPERAND (expr, 0), 0);
+ break;
- *expr_p = op0;
+ case VIEW_CONVERT_EXPR:
+ /* Take the address of our operand and then convert it to the type of
+ this ADDR_EXPR. */
+ *expr_p = fold_convert (TREE_TYPE (expr),
+ build_addr_expr (TREE_OPERAND (op0, 0)));
+ ret = GS_OK;
break;
default:
@@ -2993,7 +3244,7 @@ gimple_push_cleanup (tree var, tree cleanup, tree *pre_p)
tree ftrue = build (MODIFY_EXPR, void_type_node, flag,
boolean_true_node);
cleanup = build (COND_EXPR, void_type_node, flag, cleanup,
- build_empty_stmt ());
+ alloc_stmt_list ());
wce = build (WITH_CLEANUP_EXPR, void_type_node, NULL_TREE,
cleanup, NULL_TREE);
append_to_statement_list (ffalse, &gimplify_ctxp->conditional_cleanups);
@@ -3208,10 +3459,9 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
break;
case ARRAY_REF:
- ret = gimplify_array_ref (expr_p, pre_p, post_p,
- fallback & fb_lvalue);
- break;
-
+ case ARRAY_RANGE_REF:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
case COMPONENT_REF:
ret = gimplify_compound_lval (expr_p, pre_p, post_p,
fallback & fb_lvalue);
@@ -3232,12 +3482,6 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
ret = gimplify_compound_expr (expr_p, pre_p, fallback != fb_none);
break;
- case REALPART_EXPR:
- case IMAGPART_EXPR:
- ret = gimplify_compound_lval (expr_p, pre_p, post_p,
- fallback & fb_lvalue);
- break;
-
case MODIFY_EXPR:
case INIT_EXPR:
ret = gimplify_modify_expr (expr_p, pre_p, post_p,
@@ -3265,6 +3509,34 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
ret = gimplify_va_arg_expr (expr_p, pre_p, post_p);
break;
+ case VIEW_CONVERT_EXPR:
+ if (VOID_TYPE_P (TREE_TYPE (*expr_p))
+ || fallback == fb_none)
+ {
+ /* Just strip a conversion to void (or in void context) and
+ try again. */
+ *expr_p = TREE_OPERAND (*expr_p, 0);
+ break;
+ }
+
+ /* If both types are BLKmode or if one type is of variable size,
+ convert this into a pointer punning operation. This avoids
+ copies of large data or making a variable-size temporary. */
+ if ((TYPE_MODE (TREE_TYPE (*expr_p)) == BLKmode
+ && TYPE_MODE (TREE_TYPE (TREE_OPERAND (*expr_p, 0))) == BLKmode)
+ || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE (*expr_p)))
+ || !TREE_CONSTANT (TYPE_SIZE (TREE_TYPE
+ (TREE_OPERAND (*expr_p,0)))))
+ {
+ tree restype = TREE_TYPE (*expr_p);
+ *expr_p = build1 (INDIRECT_REF, TREE_TYPE (*expr_p),
+ fold_convert (build_pointer_type (restype),
+ build_addr_expr
+ (TREE_OPERAND (*expr_p, 0))));
+ break;
+ }
+ goto unary;
+
case CONVERT_EXPR:
case NOP_EXPR:
if (IS_EMPTY_STMT (*expr_p))
@@ -3293,6 +3565,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
case FIX_CEIL_EXPR:
case FIX_FLOOR_EXPR:
case FIX_ROUND_EXPR:
+ unary:
/* unary_expr: ... | '(' cast ')' val | ... */
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
is_gimple_val, fb_rvalue);
@@ -3484,9 +3757,18 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
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. */
- if (TREE_CODE_CLASS (TREE_CODE (*expr_p)) == '1')
+ 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'
@@ -3529,7 +3811,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
if (ret == GS_ERROR)
{
if (is_statement)
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
goto out;
}
@@ -3541,17 +3823,37 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
#endif
if (!*expr_p)
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
if (fallback == fb_none && !is_gimple_stmt (*expr_p))
{
/* We aren't looking for a value, and we don't have a valid
statement. If it doesn't have side-effects, throw it away. */
if (!TREE_SIDE_EFFECTS (*expr_p))
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
else if (!TREE_THIS_VOLATILE (*expr_p))
- /* We only handle volatiles here; anything else with side-effects
- must be converted to a valid statement before we get here. */
- abort ();
+ {
+ /* This is probably a _REF that contains something nested that
+ 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)
+ {
+ 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);
+ }
+ else
+ /* Anything else with side-effects
+ must be converted to a valid statement before we get here. */
+ abort ();
+
+ *expr_p = alloc_stmt_list ();
+ }
else if (COMPLETE_TYPE_P (TREE_TYPE (*expr_p)))
{
/* Historically, the compiler has treated a bare
@@ -3562,7 +3864,7 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
else
/* We can't do anything useful with a volatile reference to
incomplete type, so just throw it away. */
- *expr_p = build_empty_stmt ();
+ *expr_p = alloc_stmt_list ();
}
/* If we are gimplifying at the statement level, we're done. Tack
@@ -3660,6 +3962,78 @@ gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p,
return ret;
}
+/* Look through TYPE for variable-sized objects and gimplify each such
+ size that we find. Return a STATEMENT_LIST containing the result. */
+
+tree
+gimplify_type_sizes (tree type)
+{
+ tree stmts = NULL_TREE;
+ tree field;
+
+ switch (TREE_CODE (type))
+ {
+ case ERROR_MARK:
+ return alloc_stmt_list ();
+
+ case INTEGER_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case CHAR_TYPE:
+ case REAL_TYPE:
+ gimplify_one_sizepos (&TYPE_MIN_VALUE (type), &stmts);
+ gimplify_one_sizepos (&TYPE_MAX_VALUE (type), &stmts);
+ break;
+
+ case ARRAY_TYPE:
+ /* These anonymous types don't have declarations, so handle them here. */
+ append_to_statement_list (gimplify_type_sizes (TYPE_DOMAIN (type)),
+ &stmts);
+ 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), &stmts);
+ break;
+
+ default:
+ break;
+ }
+
+ gimplify_one_sizepos (&TYPE_SIZE (type), &stmts);
+ gimplify_one_sizepos (&TYPE_SIZE_UNIT (type), &stmts);
+
+ if (!stmts)
+ stmts = alloc_stmt_list ();
+
+ return stmts;
+}
+
+/* Subroutine of the above to gimplify one size or position, *EXPR_P.
+ We add any required statements to STMT_P. */
+
+void
+gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
+{
+ tree pre = NULL_TREE, post = NULL_TREE;
+
+ /* We don't do anything if the value isn't there, is constant, or contains
+ A PLACEHOLDER_EXPR. */
+ if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
+ || CONTAINS_PLACEHOLDER_P (*expr_p))
+ return;
+
+ gimplify_expr (expr_p, &pre, &post, is_gimple_val, fb_rvalue);
+
+ if (pre)
+ append_to_statement_list (pre, stmt_p);
+ if (post)
+ append_to_statement_list (post, stmt_p);
+}
+
#ifdef ENABLE_CHECKING
/* Compare types A and B for a "close enough" match. */
@@ -3720,8 +4094,10 @@ check_pointer_types_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
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. */
+ /* &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. */
if (TREE_CODE (otype) == ARRAY_TYPE
&& POINTER_TYPE_P (ptype)
&& cpt_same_type (TREE_TYPE (otype), dtype))
@@ -3751,8 +4127,12 @@ gimplify_body (tree *body_p, tree fndecl)
timevar_push (TV_TREE_GIMPLIFY);
push_gimplify_context ();
- /* Unshare most shared trees in the body. */
- unshare_all_trees (*body_p);
+ /* 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);
@@ -3764,13 +4144,14 @@ gimplify_body (tree *body_p, tree fndecl)
/* Unshare again, in case gimplification was sloppy. */
unshare_all_trees (body);
- /* If there isn't an outer BIND_EXPR, add one. */
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 = build (BIND_EXPR, void_type_node, NULL_TREE,