aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r--gcc/gimplify.c197
1 files changed, 135 insertions, 62 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 3dd48a8d09e..0639fd05bb5 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -27,7 +27,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "tm.h"
#include "tree.h"
#include "rtl.h"
-#include "errors.h"
#include "varray.h"
#include "tree-gimple.h"
#include "tree-inline.h"
@@ -45,6 +44,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "output.h"
#include "expr.h"
#include "ggc.h"
+#include "toplev.h"
#include "target.h"
static struct gimplify_ctx
@@ -54,7 +54,7 @@ static struct gimplify_ctx
tree conditional_cleanups;
tree exit_label;
tree return_temp;
- varray_type case_labels;
+ VEC(tree,heap) *case_labels;
/* The formal temporary table. Should this be persistent? */
htab_t temp_htab;
int conditions;
@@ -1008,10 +1008,12 @@ gimplify_decl_expr (tree *stmt_p)
if (TREE_TYPE (decl) == error_mark_node)
return GS_ERROR;
- else if (TREE_CODE (decl) == TYPE_DECL)
+ if ((TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
- else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
{
tree init = DECL_INITIAL (decl);
@@ -1022,12 +1024,6 @@ gimplify_decl_expr (tree *stmt_p)
of the emitted code: see mx_register_decls(). */
tree t, args, addr, ptr_type;
- /* ??? 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);
@@ -1167,7 +1163,7 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
if (SWITCH_BODY (switch_expr))
{
- varray_type labels, saved_labels;
+ VEC(tree,heap) *labels, *saved_labels;
tree label_vec, default_case = NULL_TREE;
size_t i, len;
@@ -1176,23 +1172,23 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
gcc_assert (!SWITCH_LABELS (switch_expr));
saved_labels = gimplify_ctxp->case_labels;
- VARRAY_TREE_INIT (gimplify_ctxp->case_labels, 8, "case_labels");
+ gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
gimplify_to_stmt_list (&SWITCH_BODY (switch_expr));
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
- len = VARRAY_ACTIVE_SIZE (labels);
+ len = VEC_length (tree, labels);
for (i = 0; i < len; ++i)
{
- tree t = VARRAY_TREE (labels, i);
+ tree t = VEC_index (tree, labels, i);
if (!CASE_LOW (t))
{
/* The default case must be the last label in the list. */
default_case = t;
- VARRAY_TREE (labels, i) = VARRAY_TREE (labels, len - 1);
+ VEC_replace (tree, labels, i, VEC_index (tree, labels, len - 1));
len--;
break;
}
@@ -1216,9 +1212,11 @@ gimplify_switch_expr (tree *expr_p, tree *pre_p)
*expr_p = SWITCH_BODY (switch_expr);
for (i = 0; i < len; ++i)
- TREE_VEC_ELT (label_vec, i) = VARRAY_TREE (labels, i);
+ TREE_VEC_ELT (label_vec, i) = VEC_index (tree, labels, i);
TREE_VEC_ELT (label_vec, len) = default_case;
+ VEC_free (tree, heap, labels);
+
sort_case_labels (label_vec);
SWITCH_BODY (switch_expr) = NULL;
@@ -1235,7 +1233,7 @@ gimplify_case_label_expr (tree *expr_p)
tree expr = *expr_p;
gcc_assert (gimplify_ctxp->case_labels);
- VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
+ VEC_safe_push (tree, heap, gimplify_ctxp->case_labels, expr);
*expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
return GS_ALL_DONE;
}
@@ -2530,6 +2528,17 @@ gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
pre_p);
}
+/* Return true if FDECL is accessing a field that is zero sized. */
+
+static bool
+zero_sized_field_decl (tree fdecl)
+{
+ if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl)
+ && integer_zerop (DECL_SIZE (fdecl)))
+ return true;
+ return false;
+}
+
/* 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
@@ -2562,6 +2571,9 @@ gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared)
so we don't have to figure out what's missing ourselves. */
gcc_assert (purpose);
+ if (zero_sized_field_decl (purpose))
+ continue;
+
/* If we have a RANGE_EXPR, we have to build a loop to assign the
whole range. */
if (TREE_CODE (purpose) == RANGE_EXPR)
@@ -2678,10 +2690,35 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
break;
}
+ /* If there are "lots" of initialized elements, even discounting
+ 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_type_elements = count_type_elements (TREE_TYPE (ctor));
+
+ /* If there are "lots" of zeros, then block clear the object first. */
+ 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
+ in the initializer, we should simply set them to zero. Except
+ 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 if (num_ctor_elements < num_type_elements)
+ cleared = true;
+
/* If there are "lots" of initialized elements, and all of them
are valid address constants, then the entire initializer can
- be dropped to memory, and then memcpy'd out. */
- if (num_nonconstant_elements == 0)
+ be dropped to memory, and then memcpy'd out. Don't do this
+ for sparse arrays, though, as it's more efficient to follow
+ the standard CONSTRUCTOR behavior of memset followed by
+ individual element initialization. */
+ if (num_nonconstant_elements == 0 && !cleared)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
unsigned int align;
@@ -2727,28 +2764,6 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
}
}
- /* If there are "lots" of initialized elements, even discounting
- 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_type_elements = count_type_elements (TREE_TYPE (ctor));
-
- /* If there are "lots" of zeros, then block clear the object first. */
- 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
- in the initializer, we should simply set them to zero. Except
- 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 if (num_ctor_elements < num_type_elements)
- cleared = true;
-
if (cleared)
{
/* Zap the CONSTRUCTOR element list, which simplifies this case.
@@ -2871,6 +2886,62 @@ gimplify_init_constructor (tree *expr_p, tree *pre_p,
return GS_ALL_DONE;
}
+/* Given a pointer value OP0, return a simplified version of an
+ indirection through OP0, or NULL_TREE if no simplification is
+ possible. This may only be applied to a rhs of an expression.
+ Note that the resulting type may be different from the type pointed
+ to in the sense that it is still compatible from the langhooks
+ point of view. */
+
+static tree
+fold_indirect_ref_rhs (tree t)
+{
+ tree type = TREE_TYPE (TREE_TYPE (t));
+ tree sub = t;
+ tree subtype;
+
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+ /* *&p => p */
+ if (lang_hooks.types_compatible_p (type, optype))
+ return op;
+ /* *(foo *)&fooarray => fooarray[0] */
+ else if (TREE_CODE (optype) == ARRAY_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
+ }
+ }
+
+ /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+ {
+ tree type_domain;
+ tree min_val = size_zero_node;
+ sub = fold_indirect_ref_rhs (sub);
+ if (! sub)
+ sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), sub);
+ type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
+ }
+
+ return NULL_TREE;
+}
+
/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
based on the code of the RHS. We loop for as long as something changes. */
@@ -2894,8 +2965,8 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
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)
+ tree t = fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
+ if (t)
{
*from_p = t;
ret = GS_OK;
@@ -3042,7 +3113,7 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
{
/* If we've somehow already got an SSA_NAME on the LHS, then
- we're probably modifying it twice. Not good. */
+ we're probably modified it twice. Not good. */
gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
*to_p = make_ssa_name (*to_p, *expr_p);
}
@@ -4390,21 +4461,21 @@ gimplify_type_sizes (tree type, tree *list_p)
{
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. */
+ if (type == NULL)
+ return;
/* We first do the main variant, then copy into any other variants. */
type = TYPE_MAIN_VARIANT (type);
+ /* Avoid infinite recursion. */
+ if (TYPE_SIZES_GIMPLIFIED (type)
+ || type == error_mark_node)
+ return;
+
+ TYPE_SIZES_GIMPLIFIED (type) = 1;
+
switch (TREE_CODE (type))
{
- case ERROR_MARK:
- return;
-
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
@@ -4417,17 +4488,13 @@ gimplify_type_sizes (tree type, tree *list_p)
{
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 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);
+ gimplify_type_sizes (TREE_TYPE (type), list_p);
+ gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
break;
case RECORD_TYPE:
@@ -4435,7 +4502,15 @@ gimplify_type_sizes (tree type, tree *list_p)
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_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
+ gimplify_type_sizes (TREE_TYPE (field), list_p);
+ }
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ gimplify_type_sizes (TREE_TYPE (type), list_p);
break;
default:
@@ -4451,8 +4526,6 @@ gimplify_type_sizes (tree type, tree *list_p)
TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
TYPE_SIZES_GIMPLIFIED (t) = 1;
}
-
- TYPE_SIZES_GIMPLIFIED (type) = 1;
}
/* A subroutine of gimplify_type_sizes to make sure that *EXPR_P,