Commit 26d44ae2 by Richard Henderson Committed by Richard Henderson

gimplify.c (gimplify_modify_expr_rhs): Move immediately before gimplify_modify_expr.

        * gimplify.c (gimplify_modify_expr_rhs): Move immediately before
        gimplify_modify_expr.
        (gimplify_init_constructor): Likewise.  Gimplify the null
        CONSTRUCTOR assignment.
        (gimplify_modify_expr_to_memcpy): New.
        (gimplify_modify_expr_to_memset): New.
        (gimplify_modify_expr): Use them.

From-SVN: r83888
parent 9d75385f
2004-06-29 Richard Henderson <rth@redhat.com>
* gimplify.c (gimplify_modify_expr_rhs): Move immediately before
gimplify_modify_expr.
(gimplify_init_constructor): Likewise. Gimplify the null
CONSTRUCTOR assignment.
(gimplify_modify_expr_to_memcpy): New.
(gimplify_modify_expr_to_memset): New.
(gimplify_modify_expr): Use them.
2004-06-29 Roman Zippel <zippel@linux-m68k.org>
* web.c (union_defs): use all defs of an instruction to create a
......
......@@ -1323,1270 +1323,1412 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
return NULL_TREE;
}
/* Break out elements of a constructor used as an initializer into separate
MODIFY_EXPRs.
/* *EXPR_P is a COMPONENT_REF being used as an rvalue. If its type is
different from its canonical type, wrap the whole thing inside a
NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
type.
Note that we still need to clear any elements that don't have explicit
initializers, so if not all elements are initialized we keep the
original MODIFY_EXPR, we just remove all of the constructor elements. */
The canonical type of a COMPONENT_REF is the type of the field being
referenced--unless the field is a bit-field which can be read directly
in a smaller mode, in which case the canonical type is the
sign-appropriate type corresponding to that mode. */
static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
tree *post_p, bool want_value)
static void
canonicalize_component_ref (tree *expr_p)
{
tree object = TREE_OPERAND (*expr_p, 0);
tree ctor = TREE_OPERAND (*expr_p, 1);
tree type = TREE_TYPE (ctor);
enum gimplify_status ret;
tree elt_list;
tree expr = *expr_p;
tree type;
if (TREE_CODE (ctor) != CONSTRUCTOR)
return GS_UNHANDLED;
if (TREE_CODE (expr) != COMPONENT_REF)
abort ();
elt_list = CONSTRUCTOR_ELTS (ctor);
if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
else
type = TREE_TYPE (TREE_OPERAND (expr, 1));
ret = GS_ALL_DONE;
switch (TREE_CODE (type))
{
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
case ARRAY_TYPE:
if (TREE_TYPE (expr) != type)
{
HOST_WIDE_INT i, num_elements, num_nonzero_elements;
HOST_WIDE_INT num_nonconstant_elements;
bool cleared;
tree old_type = TREE_TYPE (expr);
/* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node
with no elements indicates zero-initialization of the whole. */
if (elt_list == NULL)
{
if (want_value)
{
*expr_p = object;
return GS_OK;
}
else
return GS_UNHANDLED;
}
/* Set the type of the COMPONENT_REF to the underlying type. */
TREE_TYPE (expr) = type;
categorize_ctor_elements (ctor, &num_nonzero_elements,
&num_nonconstant_elements);
num_elements = count_type_elements (TREE_TYPE (ctor));
/* And wrap the whole thing inside a NOP_EXPR. */
expr = build1 (NOP_EXPR, old_type, expr);
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
if (num_nonconstant_elements == 0
&& TREE_READONLY (object)
&& TREE_CODE (object) == VAR_DECL)
{
DECL_INITIAL (object) = ctor;
TREE_STATIC (object) = 1;
if (!DECL_NAME (object))
DECL_NAME (object) = create_tmp_var_name ("C");
walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
*expr_p = expr;
}
}
/* ??? C++ doesn't automatically append a .<number> to the
assembler name, and even when it does, it looks a FE private
data structures to figure out what that number should be,
which are not set for this variable. I suppose this is
important for local statics for inline functions, which aren't
"local" in the object file sense. So in order to get a unique
TU-local symbol, we must invoke the lhd version now. */
lhd_set_decl_assembler_name (object);
/* 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
T array[U];
(T *)&array
==>
&array[L]
where L is the lower bound. For simplicity, only do this for constant
lower bound. */
*expr_p = NULL_TREE;
break;
}
static void
canonicalize_addr_expr (tree *expr_p)
{
tree expr = *expr_p;
tree ctype = TREE_TYPE (expr);
tree addr_expr = TREE_OPERAND (expr, 0);
tree atype = TREE_TYPE (addr_expr);
tree dctype, datype, ddatype, otype, obj_expr;
/* 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)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
unsigned int align;
/* Both cast and addr_expr types should be pointers. */
if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
return;
/* ??? We can still get unbounded array types, at least
from the C++ front end. This seems wrong, but attempt
to work around it for now. */
if (size < 0)
{
size = int_size_in_bytes (TREE_TYPE (object));
if (size >= 0)
TREE_TYPE (ctor) = type = TREE_TYPE (object);
}
/* The addr_expr type should be a pointer to an array. */
datype = TREE_TYPE (atype);
if (TREE_CODE (datype) != ARRAY_TYPE)
return;
/* Find the maximum alignment we can assume for the object. */
/* ??? Make use of DECL_OFFSET_ALIGN. */
if (DECL_P (object))
align = DECL_ALIGN (object);
else
align = TYPE_ALIGN (type);
/* Both cast and addr_expr types should address the same object type. */
dctype = TREE_TYPE (ctype);
ddatype = TREE_TYPE (datype);
if (!lang_hooks.types_compatible_p (ddatype, dctype))
return;
if (size > 0 && !can_move_by_pieces (size, align))
{
tree new = create_tmp_var_raw (type, "C");
gimple_add_tmp_var (new);
TREE_STATIC (new) = 1;
TREE_READONLY (new) = 1;
DECL_INITIAL (new) = ctor;
if (align > DECL_ALIGN (new))
{
DECL_ALIGN (new) = align;
DECL_USER_ALIGN (new) = 1;
}
walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
/* The addr_expr and the object type should match. */
obj_expr = TREE_OPERAND (addr_expr, 0);
otype = TREE_TYPE (obj_expr);
if (!lang_hooks.types_compatible_p (otype, datype))
return;
TREE_OPERAND (*expr_p, 1) = new;
break;
}
}
/* 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;
/* 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. */
/* All checks succeeded. Build a new node to merge the cast. */
*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);
}
/* 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)
cleared = true;
/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions
underneath as appropriate. */
/* ??? 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
{
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) != len)
cleared = 1;;
}
else if (len != fields_length (type))
cleared = 1;
}
static enum gimplify_status
gimplify_conversion (tree *expr_p)
{
/* Strip away as many useless type conversions as possible
at the toplevel. */
STRIP_USELESS_TYPE_CONVERSION (*expr_p);
if (cleared)
/* 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)
{
CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
append_to_statement_list (*expr_p, pre_p);
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);
}
for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list))
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
{
tree purpose, value, cref, init;
tree sub = TREE_OPERAND (*expr_p, 0);
purpose = TREE_PURPOSE (elt_list);
value = TREE_VALUE (elt_list);
/* If a NOP conversion is changing the type of a COMPONENT_REF
expression, then canonicalize its type now in order to expose more
redundant conversions. */
if (TREE_CODE (sub) == COMPONENT_REF)
canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
if (cleared && initializer_zerop (value))
continue;
/* If a NOP conversion is changing a pointer to array of foo
to a pointer to foo, embed that change in the ADDR_EXPR. */
else if (TREE_CODE (sub) == ADDR_EXPR)
canonicalize_addr_expr (expr_p);
}
if (TREE_CODE (type) == ARRAY_TYPE)
{
tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
return GS_OK;
}
/* ??? 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 ();
/* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification. */
cref = build (ARRAY_REF, t, object, purpose, NULL_TREE, NULL_TREE);
}
static enum gimplify_status
gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
tree op1 = TREE_OPERAND (*expr_p, 0);
tree op2 = TREE_OPERAND (*expr_p, 1);
enum tree_code code;
enum gimplify_status r0, r1;
if (TREE_CODE (*expr_p) == MIN_EXPR)
code = LE_EXPR;
else
cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
purpose, NULL_TREE);
code = GE_EXPR;
init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
/* Each member initialization is a full-expression. */
gimplify_and_add (init, pre_p);
}
*expr_p = build (COND_EXPR, TREE_TYPE (*expr_p),
build (code, boolean_type_node, op1, op2),
op1, op2);
*expr_p = NULL_TREE;
}
break;
if (r0 == GS_ERROR || r1 == GS_ERROR)
return GS_ERROR;
else
return GS_OK;
}
case COMPLEX_TYPE:
{
tree r, i;
/* Subroutine of gimplify_compound_lval.
Converts an ARRAY_REF to the equivalent *(&array + offset) form. */
/* Extract the real and imaginary parts out of the ctor. */
r = i = NULL_TREE;
if (elt_list)
{
r = TREE_VALUE (elt_list);
elt_list = TREE_CHAIN (elt_list);
if (elt_list)
{
i = TREE_VALUE (elt_list);
if (TREE_CHAIN (elt_list))
abort ();
}
}
if (r == NULL || i == NULL)
{
tree zero = convert (TREE_TYPE (type), integer_zero_node);
if (r == NULL)
r = zero;
if (i == NULL)
i = zero;
}
static enum gimplify_status
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 = 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 = unshare_expr (array_ref_low_bound (*expr_p));
tree offset, addr, result;
enum gimplify_status ret;
/* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
represent creation of a complex value. */
if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
{
ctor = build_complex (type, r, i);
TREE_OPERAND (*expr_p, 1) = ctor;
}
else
/* If the array domain does not start at zero, apply the offset. */
if (!integer_zerop (minidx))
{
ctor = build (COMPLEX_EXPR, type, r, i);
TREE_OPERAND (*expr_p, 1) = ctor;
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
is_gimple_rhs, fb_rvalue);
}
idx = convert (TREE_TYPE (minidx), idx);
idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
}
break;
case VECTOR_TYPE:
/* Go ahead and simplify constant constructors to VECTOR_CST. */
if (TREE_CONSTANT (ctor))
TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
else
{
/* Vector types use CONSTRUCTOR all the way through gimple
compilation as a general initializer. */
for (; elt_list; elt_list = TREE_CHAIN (elt_list))
/* 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.
Represent this as a subtraction of a positive rather than addition
of a negative. This will prevent any conversion back to ARRAY_REF
from getting the wrong results from the division. */
if (TREE_CODE (idx) == INTEGER_CST && tree_int_cst_sgn (idx) < 0)
{
enum gimplify_status tret;
tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
is_gimple_constructor_elt, fb_rvalue);
if (tret == GS_ERROR)
ret = GS_ERROR;
}
idx = fold (build1 (NEGATE_EXPR, TREE_TYPE (idx), idx));
add_code = MINUS_EXPR;
}
break;
default:
/* So how did we get a CONSTRUCTOR for a scalar type? */
abort ();
}
/* Pointer arithmetic must be done in sizetype. */
idx = fold_convert (sizetype, idx);
/* Convert the index to a byte offset. */
offset = size_binop (MULT_EXPR, size, idx);
ret = gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
if (ret == GS_ERROR)
return GS_ERROR;
else if (want_value)
{
append_to_statement_list (*expr_p, pre_p);
*expr_p = object;
return ret;
addr = build_fold_addr_expr_with_type (array, ptrtype);
result = fold (build (add_code, ptrtype, addr, offset));
*expr_p = build1 (INDIRECT_REF, elttype, result);
return GS_OK;
}
else
return GS_ALL_DONE;
}
/* *EXPR_P is a COMPONENT_REF being used as an rvalue. If its type is
different from its canonical type, wrap the whole thing inside a
NOP_EXPR and force the type of the COMPONENT_REF to be the canonical
type.
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
node pointed by EXPR_P.
The canonical type of a COMPONENT_REF is the type of the field being
referenced--unless the field is a bit-field which can be read directly
in a smaller mode, in which case the canonical type is the
sign-appropriate type corresponding to that mode. */
compound_lval
: min_lval '[' val ']'
| min_lval '.' ID
| compound_lval '[' val ']'
| compound_lval '.' ID
static void
canonicalize_component_ref (tree *expr_p)
{
tree expr = *expr_p;
tree type;
This is not part of the original SIMPLE definition, which separates
array and member references, but it seems reasonable to handle them
together. Also, this way we don't run into problems with union
aliasing; gcc requires that for accesses through a union to alias, the
union reference must be explicit, which was not always the case when we
were splitting up array and member refs.
if (TREE_CODE (expr) != COMPONENT_REF)
abort ();
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored.
if (INTEGRAL_TYPE_P (TREE_TYPE (expr)))
type = TREE_TYPE (get_unwidened (expr, NULL_TREE));
else
type = TREE_TYPE (TREE_OPERAND (expr, 1));
POST_P points to the list where side effects that must happen after
*EXPR_P should be stored. */
if (TREE_TYPE (expr) != type)
{
tree old_type = TREE_TYPE (expr);
static enum gimplify_status
gimplify_compound_lval (tree *expr_p, tree *pre_p,
tree *post_p, bool want_lvalue)
{
tree *p;
varray_type stack;
enum gimplify_status ret = GS_OK, tret;
int i;
/* Set the type of the COMPONENT_REF to the underlying type. */
TREE_TYPE (expr) = type;
#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
/* And wrap the whole thing inside a NOP_EXPR. */
expr = build1 (NOP_EXPR, old_type, expr);
/* Create a stack of the subexpressions so later we can walk them in
order from inner to outer. */
VARRAY_TREE_INIT (stack, 10, "stack");
*expr_p = expr;
}
}
/* 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))
VARRAY_PUSH_TREE (stack, *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 by converting
T array[U];
(T *)&array
==>
&array[L]
where L is the lower bound. For simplicity, only do this for constant
lower bound. */
/* Now STACK is a stack of pointers to all the refs we've walked through
and P points to the innermost expression.
static void
canonicalize_addr_expr (tree *expr_p)
{
tree expr = *expr_p;
tree ctype = TREE_TYPE (expr);
tree addr_expr = TREE_OPERAND (expr, 0);
tree atype = TREE_TYPE (addr_expr);
tree dctype, datype, ddatype, otype, obj_expr;
Java requires that we elaborated nodes in source order. That
means we must gimplify the inner expression followed by each of
the indices, in order. But we can't gimplify the inner
expression until we deal with any variable bounds, sizes, or
positions in order to deal with PLACEHOLDER_EXPRs.
/* Both cast and addr_expr types should be pointers. */
if (!POINTER_TYPE_P (ctype) || !POINTER_TYPE_P (atype))
return;
So we do this in three steps. First we deal with the annotations
for any variables in the components, then we gimplify the base,
then we gimplify any indices, from left to right. */
for (i = VARRAY_ACTIVE_SIZE (stack) - 1; i >= 0; i--)
{
tree t = VARRAY_TREE (stack, i);
/* The addr_expr type should be a pointer to an array. */
datype = TREE_TYPE (atype);
if (TREE_CODE (datype) != ARRAY_TYPE)
return;
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
/* 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 low = unshare_expr (array_ref_low_bound (t));
if (!is_gimple_min_invariant (low))
{
TREE_OPERAND (t, 2) = low;
tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
/* Both cast and addr_expr types should address the same object type. */
dctype = TREE_TYPE (ctype);
ddatype = TREE_TYPE (datype);
if (!lang_hooks.types_compatible_p (ddatype, dctype))
return;
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);
/* The addr_expr and the object type should match. */
obj_expr = TREE_OPERAND (addr_expr, 0);
otype = TREE_TYPE (obj_expr);
if (!lang_hooks.types_compatible_p (otype, datype))
return;
/* Divide the element size by the alignment of the element
type (above). */
elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
/* 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;
if (!is_gimple_min_invariant (elmt_size))
{
TREE_OPERAND (t, 3) = elmt_size;
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);
/* All checks succeeded. Build a new node to merge the cast. */
*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);
}
/* Divide the offset by its alignment. */
offset = size_binop (EXACT_DIV_EXPR, offset, factor);
/* *EXPR_P is a NOP_EXPR or CONVERT_EXPR. Remove it and/or other conversions
underneath as appropriate. */
if (!is_gimple_min_invariant (offset))
{
TREE_OPERAND (t, 2) = offset;
tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
}
}
static enum gimplify_status
gimplify_conversion (tree *expr_p)
{
/* Strip away as many useless type conversions as possible
at the toplevel. */
STRIP_USELESS_TYPE_CONVERSION (*expr_p);
/* Step 2 is to gimplify the base expression. */
tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
want_lvalue ? fb_lvalue : fb_rvalue);
ret = MIN (ret, tret);
/* 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)
/* And finally, the indices and operands to BIT_FIELD_REF. */
for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
{
tree t = VARRAY_TOP_TREE (stack);
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
/* 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
expressions into a minimal gimple lvalue. However, that
exposes bugs in alias analysis. The alias analyzer does
not handle &PTR->FIELD very well. Will fix after the
branch is merged into mainline (dnovillo 2004-05-03). */
if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
{
tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
else if (TREE_CODE (t) == BIT_FIELD_REF)
{
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);
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);
}
/* If we still have a conversion at the toplevel,
then canonicalize some constructs. */
if (TREE_CODE (*expr_p) == NOP_EXPR || TREE_CODE (*expr_p) == CONVERT_EXPR)
{
tree sub = TREE_OPERAND (*expr_p, 0);
/* The innermost expression P may have originally had TREE_SIDE_EFFECTS
set which would have caused all the outer expressions in EXPR_P
leading to P to also have had TREE_SIDE_EFFECTS set. */
recalculate_side_effects (t);
VARRAY_POP (stack);
}
/* If a NOP conversion is changing the type of a COMPONENT_REF
expression, then canonicalize its type now in order to expose more
redundant conversions. */
if (TREE_CODE (sub) == COMPONENT_REF)
canonicalize_component_ref (&TREE_OPERAND (*expr_p, 0));
tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
want_lvalue ? fb_lvalue : fb_rvalue);
ret = MIN (ret, tret);
/* If a NOP conversion is changing a pointer to array of foo
to a pointer to foo, embed that change in the ADDR_EXPR. */
else if (TREE_CODE (sub) == ADDR_EXPR)
canonicalize_addr_expr (expr_p);
/* If the outermost expression is a COMPONENT_REF, canonicalize its type. */
if (!want_lvalue && TREE_CODE (*expr_p) == COMPONENT_REF)
{
canonicalize_component_ref (expr_p);
ret = MIN (ret, GS_OK);
}
return GS_OK;
return ret;
}
/* Reduce MIN/MAX_EXPR to a COND_EXPR for further gimplification. */
/* Gimplify the self modifying expression 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.
WANT_VALUE is nonzero iff we want to use the value of this expression
in another expression. */
static enum gimplify_status
gimplify_minimax_expr (tree *expr_p, tree *pre_p, tree *post_p)
gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
bool want_value)
{
tree op1 = TREE_OPERAND (*expr_p, 0);
tree op2 = TREE_OPERAND (*expr_p, 1);
enum tree_code code;
enum gimplify_status r0, r1;
tree lhs, lvalue, rhs, t1;
bool postfix;
enum tree_code arith_code;
enum gimplify_status ret;
if (TREE_CODE (*expr_p) == MIN_EXPR)
code = LE_EXPR;
code = TREE_CODE (*expr_p);
#if defined ENABLE_CHECKING
if (code != POSTINCREMENT_EXPR
&& code != POSTDECREMENT_EXPR
&& code != PREINCREMENT_EXPR
&& code != PREDECREMENT_EXPR)
abort ();
#endif
/* Prefix or postfix? */
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
/* Faster to treat as prefix if result is not used. */
postfix = want_value;
else
code = GE_EXPR;
postfix = false;
r0 = gimplify_expr (&op1, pre_p, post_p, is_gimple_val, fb_rvalue);
r1 = gimplify_expr (&op2, pre_p, post_p, is_gimple_val, fb_rvalue);
/* Add or subtract? */
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
arith_code = PLUS_EXPR;
else
arith_code = MINUS_EXPR;
*expr_p = build (COND_EXPR, TREE_TYPE (*expr_p),
build (code, boolean_type_node, op1, op2),
op1, op2);
/* Gimplify the LHS into a GIMPLE lvalue. */
lvalue = TREE_OPERAND (*expr_p, 0);
ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
if (ret == GS_ERROR)
return ret;
if (r0 == GS_ERROR || r1 == GS_ERROR)
return GS_ERROR;
/* Extract the operands to the arithmetic operation. */
lhs = lvalue;
rhs = TREE_OPERAND (*expr_p, 1);
/* For postfix operator, we evaluate the LHS to an rvalue and then use
that as the result value and in the postqueue operation. */
if (postfix)
{
ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
if (ret == GS_ERROR)
return ret;
}
t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
if (postfix)
{
gimplify_and_add (t1, post_p);
*expr_p = lhs;
return GS_ALL_DONE;
}
else
{
*expr_p = t1;
return GS_OK;
}
}
/* Subroutine of gimplify_compound_lval.
Converts an ARRAY_REF to the equivalent *(&array + offset) form. */
/* Gimplify the CALL_EXPR node pointed by EXPR_P.
call_expr
: ID '(' arglist ')'
arglist
: arglist ',' val
| val
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored. */
static enum gimplify_status
gimplify_array_ref_to_plus (tree *expr_p, tree *pre_p, tree *post_p)
gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
{
tree array = TREE_OPERAND (*expr_p, 0);
tree arrtype = TREE_TYPE (array);
tree elttype = TREE_TYPE (arrtype);
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 = unshare_expr (array_ref_low_bound (*expr_p));
tree offset, addr, result;
tree decl;
tree arglist;
enum gimplify_status ret;
/* If the array domain does not start at zero, apply the offset. */
if (!integer_zerop (minidx))
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != CALL_EXPR)
abort ();
#endif
/* For reliable diagnostics during inlining, it is necessary that
every call_expr be annotated with file and line. */
if (!EXPR_LOCUS (*expr_p))
annotate_with_locus (*expr_p, input_location);
/* This may be a call to a builtin function.
Builtin function calls may be transformed into different
(and more efficient) builtin function calls under certain
circumstances. Unfortunately, gimplification can muck things
up enough that the builtin expanders are not aware that certain
transformations are still valid.
So we attempt transformation/gimplification of the call before
we gimplify the CALL_EXPR. At this time we do not manage to
transform all calls in the same manner as the expanders do, but
we do transform most of them. */
decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
idx = convert (TREE_TYPE (minidx), idx);
idx = fold (build (MINUS_EXPR, TREE_TYPE (minidx), idx, minidx));
tree new;
/* If it is allocation of stack, record the need to restore the memory
when the enclosing bind_expr is exited. */
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC)
gimplify_ctxp->save_stack = true;
/* If it is restore of the stack, reset it, since it means we are
regimplifying the bind_expr. Note that we use the fact that
for try_finally_expr, try part is processed first. */
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE)
gimplify_ctxp->save_stack = false;
new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
if (new && new != *expr_p)
{
/* There was a transformation of this call which computes the
same value, but in a more efficient way. Return and try
again. */
*expr_p = new;
return GS_OK;
}
}
/* 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.
Represent this as a subtraction of a positive rather than addition
of a negative. This will prevent any conversion back to ARRAY_REF
from getting the wrong results from the division. */
if (TREE_CODE (idx) == INTEGER_CST && tree_int_cst_sgn (idx) < 0)
/* There is a sequence point before the call, so any side effects in
the calling expression must occur before the actual call. Force
gimplify_expr to use an internal post queue. */
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
is_gimple_call_addr, fb_rvalue);
if (PUSH_ARGS_REVERSED)
TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
for (arglist = TREE_OPERAND (*expr_p, 1); arglist;
arglist = TREE_CHAIN (arglist))
{
idx = fold (build1 (NEGATE_EXPR, TREE_TYPE (idx), idx));
add_code = MINUS_EXPR;
enum gimplify_status t;
/* There is a sequence point before a function call. Side effects in
the argument list must occur before the actual call. So, when
gimplifying arguments, force gimplify_expr to use an internal
post queue which is then appended to the end of PRE_P. */
t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, is_gimple_val,
fb_rvalue);
if (t == GS_ERROR)
ret = GS_ERROR;
}
if (PUSH_ARGS_REVERSED)
TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
/* Pointer arithmetic must be done in sizetype. */
idx = fold_convert (sizetype, idx);
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
{
tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
/* Convert the index to a byte offset. */
offset = size_binop (MULT_EXPR, size, idx);
if (new && new != *expr_p)
{
/* There was a transformation of this call which computes the
same value, but in a more efficient way. Return and try
again. */
*expr_p = new;
return GS_OK;
}
}
/* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
decl. This allows us to eliminate redundant or useless
calls to "const" functions. */
if (TREE_CODE (*expr_p) == CALL_EXPR
&& (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
TREE_SIDE_EFFECTS (*expr_p) = 0;
ret = gimplify_expr (&array, pre_p, post_p, is_gimple_min_lval, fb_lvalue);
if (ret == GS_ERROR)
return ret;
addr = build_fold_addr_expr_with_type (array, ptrtype);
result = fold (build (add_code, ptrtype, addr, offset));
*expr_p = build1 (INDIRECT_REF, elttype, result);
return GS_OK;
}
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
node pointed by EXPR_P.
compound_lval
: min_lval '[' val ']'
| min_lval '.' ID
| compound_lval '[' val ']'
| compound_lval '.' ID
/* Handle shortcut semantics in the predicate operand of a COND_EXPR by
rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs.
This is not part of the original SIMPLE definition, which separates
array and member references, but it seems reasonable to handle them
together. Also, this way we don't run into problems with union
aliasing; gcc requires that for accesses through a union to alias, the
union reference must be explicit, which was not always the case when we
were splitting up array and member refs.
TRUE_LABEL_P and FALSE_LABEL_P point to the labels to jump to if the
condition is true or false, respectively. If null, we should generate
our own to skip over the evaluation of this specific expression.
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored.
This function is the tree equivalent of do_jump.
POST_P points to the list where side effects that must happen after
*EXPR_P should be stored. */
shortcut_cond_r should only be called by shortcut_cond_expr. */
static enum gimplify_status
gimplify_compound_lval (tree *expr_p, tree *pre_p,
tree *post_p, bool want_lvalue)
static tree
shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p)
{
tree *p;
varray_type stack;
enum gimplify_status ret = GS_OK, tret;
int i;
#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
tree local_label = NULL_TREE;
tree t, expr = NULL;
/* Create a stack of the subexpressions so later we can walk them in
order from inner to outer. */
VARRAY_TREE_INIT (stack, 10, "stack");
/* OK, it's not a simple case; we need to pull apart the COND_EXPR to
retain the shortcut semantics. Just insert the gotos here;
shortcut_cond_expr will append the real blocks later. */
if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
{
/* Turn if (a && b) into
/* 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))
VARRAY_PUSH_TREE (stack, *p);
if (a); else goto no;
if (b) goto yes; else goto no;
(no:) */
/* Now STACK is a stack of pointers to all the refs we've walked through
and P points to the innermost expression.
if (false_label_p == NULL)
false_label_p = &local_label;
Java requires that we elaborated nodes in source order. That
means we must gimplify the inner expression followed by each of
the indices, in order. But we can't gimplify the inner
expression until we deal with any variable bounds, sizes, or
positions in order to deal with PLACEHOLDER_EXPRs.
t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p);
append_to_statement_list (t, &expr);
So we do this in three steps. First we deal with the annotations
for any variables in the components, then we gimplify the base,
then we gimplify any indices, from left to right. */
for (i = VARRAY_ACTIVE_SIZE (stack) - 1; i >= 0; i--)
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p);
append_to_statement_list (t, &expr);
}
else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
tree t = VARRAY_TREE (stack, i);
/* Turn if (a || b) into
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
/* 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 low = unshare_expr (array_ref_low_bound (t));
if (!is_gimple_min_invariant (low))
{
TREE_OPERAND (t, 2) = low;
tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
if (a) goto yes;
if (b) goto yes; else goto no;
(yes:) */
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);
if (true_label_p == NULL)
true_label_p = &local_label;
/* Divide the element size by the alignment of the element
type (above). */
elmt_size = size_binop (EXACT_DIV_EXPR, elmt_size, factor);
t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL);
append_to_statement_list (t, &expr);
if (!is_gimple_min_invariant (elmt_size))
{
TREE_OPERAND (t, 3) = elmt_size;
tret = gimplify_expr (&TREE_OPERAND (t, 3), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p);
append_to_statement_list (t, &expr);
}
else if (TREE_CODE (t) == COMPONENT_REF)
else if (TREE_CODE (pred) == COND_EXPR)
{
/* Set the field offset into T and gimplify it. */
if (!TREE_OPERAND (t, 2))
/* As long as we're messing with gotos, turn if (a ? b : c) into
if (a)
if (b) goto yes; else goto no;
else
if (c) goto yes; else goto no; */
expr = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p),
shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p,
false_label_p));
}
else
{
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);
expr = build (COND_EXPR, void_type_node, pred,
build_and_jump (true_label_p),
build_and_jump (false_label_p));
}
if (!is_gimple_min_invariant (offset))
if (local_label)
{
TREE_OPERAND (t, 2) = offset;
tret = gimplify_expr (&TREE_OPERAND (t, 2), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
}
}
}
t = build1 (LABEL_EXPR, void_type_node, local_label);
append_to_statement_list (t, &expr);
}
/* Step 2 is to gimplify the base expression. */
tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval,
want_lvalue ? fb_lvalue : fb_rvalue);
ret = MIN (ret, tret);
return expr;
}
/* And finally, the indices and operands to BIT_FIELD_REF. */
for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
{
tree t = VARRAY_TOP_TREE (stack);
static tree
shortcut_cond_expr (tree expr)
{
tree pred = TREE_OPERAND (expr, 0);
tree then_ = TREE_OPERAND (expr, 1);
tree else_ = TREE_OPERAND (expr, 2);
tree true_label, false_label, end_label, t;
tree *true_label_p;
tree *false_label_p;
bool emit_end, emit_false;
bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
/* First do simple transformations. */
if (!else_se)
{
/* 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
expressions into a minimal gimple lvalue. However, that
exposes bugs in alias analysis. The alias analyzer does
not handle &PTR->FIELD very well. Will fix after the
branch is merged into mainline (dnovillo 2004-05-03). */
if (!is_gimple_min_invariant (TREE_OPERAND (t, 1)))
/* If there is no 'else', turn (a && b) into if (a) if (b). */
while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
{
tret = gimplify_expr (&TREE_OPERAND (t, 1), pre_p, post_p,
is_gimple_tmp_var, fb_rvalue);
ret = MIN (ret, tret);
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
then_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
}
}
else if (TREE_CODE (t) == BIT_FIELD_REF)
if (!then_se)
{
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);
/* If there is no 'then', turn
if (a || b); else d
into
if (a); else if (b); else d. */
while (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
else_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
}
}
/* If we're done, great. */
if (TREE_CODE (pred) != TRUTH_ANDIF_EXPR
&& TREE_CODE (pred) != TRUTH_ORIF_EXPR)
return expr;
/* Otherwise we need to mess with gotos. Change
if (a) c; else d;
to
if (a); else goto no;
c; goto end;
no: d; end:
and recursively gimplify the condition. */
true_label = false_label = end_label = NULL_TREE;
/* If our arms just jump somewhere, hijack those labels so we don't
generate jumps to jumps. */
/* The innermost expression P may have originally had TREE_SIDE_EFFECTS
set which would have caused all the outer expressions in EXPR_P
leading to P to also have had TREE_SIDE_EFFECTS set. */
recalculate_side_effects (t);
VARRAY_POP (stack);
if (then_
&& TREE_CODE (then_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
{
true_label = GOTO_DESTINATION (then_);
then_ = NULL;
then_se = false;
}
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)
if (else_
&& TREE_CODE (else_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
{
canonicalize_component_ref (expr_p);
ret = MIN (ret, GS_OK);
false_label = GOTO_DESTINATION (else_);
else_ = NULL;
else_se = false;
}
return ret;
}
/* If we aren't hijacking a label for the 'then' branch, it falls through. */
if (true_label)
true_label_p = &true_label;
else
true_label_p = NULL;
/* Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
/* The 'else' branch also needs a label if it contains interesting code. */
if (false_label || else_se)
false_label_p = &false_label;
else
false_label_p = NULL;
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored.
/* If there was nothing else in our arms, just forward the label(s). */
if (!then_se && !else_se)
return shortcut_cond_r (pred, true_label_p, false_label_p);
POST_P points to the list where side effects that must happen after
*EXPR_P should be stored.
/* If our last subexpression already has a terminal label, reuse it. */
if (else_se)
expr = expr_last (else_);
else if (then_se)
expr = expr_last (then_);
else
expr = NULL;
if (expr && TREE_CODE (expr) == LABEL_EXPR)
end_label = LABEL_EXPR_LABEL (expr);
WANT_VALUE is nonzero iff we want to use the value of this expression
in another expression. */
/* If we don't care about jumping to the 'else' branch, jump to the end
if the condition is false. */
if (!false_label_p)
false_label_p = &end_label;
static enum gimplify_status
gimplify_self_mod_expr (tree *expr_p, tree *pre_p, tree *post_p,
bool want_value)
{
enum tree_code code;
tree lhs, lvalue, rhs, t1;
bool postfix;
enum tree_code arith_code;
enum gimplify_status ret;
/* We only want to emit these labels if we aren't hijacking them. */
emit_end = (end_label == NULL_TREE);
emit_false = (false_label == NULL_TREE);
code = TREE_CODE (*expr_p);
pred = shortcut_cond_r (pred, true_label_p, false_label_p);
#if defined ENABLE_CHECKING
if (code != POSTINCREMENT_EXPR
&& code != POSTDECREMENT_EXPR
&& code != PREINCREMENT_EXPR
&& code != PREDECREMENT_EXPR)
abort ();
#endif
expr = NULL;
append_to_statement_list (pred, &expr);
/* Prefix or postfix? */
if (code == POSTINCREMENT_EXPR || code == POSTDECREMENT_EXPR)
/* Faster to treat as prefix if result is not used. */
postfix = want_value;
else
postfix = false;
append_to_statement_list (then_, &expr);
if (else_se)
{
t = build_and_jump (&end_label);
append_to_statement_list (t, &expr);
if (emit_false)
{
t = build1 (LABEL_EXPR, void_type_node, false_label);
append_to_statement_list (t, &expr);
}
append_to_statement_list (else_, &expr);
}
if (emit_end && end_label)
{
t = build1 (LABEL_EXPR, void_type_node, end_label);
append_to_statement_list (t, &expr);
}
/* Add or subtract? */
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
arith_code = PLUS_EXPR;
else
arith_code = MINUS_EXPR;
return expr;
}
/* Gimplify the LHS into a GIMPLE lvalue. */
lvalue = TREE_OPERAND (*expr_p, 0);
ret = gimplify_expr (&lvalue, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
if (ret == GS_ERROR)
return ret;
/* EXPR is used in a boolean context; make sure it has BOOLEAN_TYPE. */
/* Extract the operands to the arithmetic operation. */
lhs = lvalue;
rhs = TREE_OPERAND (*expr_p, 1);
static tree
gimple_boolify (tree expr)
{
tree type = TREE_TYPE (expr);
/* For postfix operator, we evaluate the LHS to an rvalue and then use
that as the result value and in the postqueue operation. */
if (postfix)
{
ret = gimplify_expr (&lhs, pre_p, post_p, is_gimple_val, fb_rvalue);
if (ret == GS_ERROR)
return ret;
}
if (TREE_CODE (type) == BOOLEAN_TYPE)
return expr;
t1 = build (arith_code, TREE_TYPE (*expr_p), lhs, rhs);
t1 = build (MODIFY_EXPR, TREE_TYPE (lvalue), lvalue, t1);
/* If this is the predicate of a COND_EXPR, it might not even be a
truthvalue yet. */
expr = lang_hooks.truthvalue_conversion (expr);
if (postfix)
{
gimplify_and_add (t1, post_p);
*expr_p = lhs;
return GS_ALL_DONE;
}
else
switch (TREE_CODE (expr))
{
*expr_p = t1;
return GS_OK;
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
/* Also boolify the arguments of truth exprs. */
TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1));
/* FALLTHRU */
case TRUTH_NOT_EXPR:
TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
/* FALLTHRU */
case EQ_EXPR: case NE_EXPR:
case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
/* 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. */
return convert (boolean_type_node, expr);
}
}
/* Gimplify the CALL_EXPR node pointed by EXPR_P.
/* Convert the conditional expression pointed by EXPR_P '(p) ? a : b;'
into
call_expr
: ID '(' arglist ')'
if (p) if (p)
t1 = a; a;
else or else
t1 = b; b;
t1;
arglist
: arglist ',' val
| val
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. */
static enum gimplify_status
gimplify_call_expr (tree *expr_p, tree *pre_p, bool (*gimple_test_f) (tree))
gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
{
tree decl;
tree arglist;
tree expr = *expr_p;
tree tmp, type;
enum gimplify_status ret;
#if defined ENABLE_CHECKING
if (TREE_CODE (*expr_p) != CALL_EXPR)
abort ();
#endif
type = TREE_TYPE (expr);
if (!type)
TREE_TYPE (expr) = void_type_node;
/* For reliable diagnostics during inlining, it is necessary that
every call_expr be annotated with file and line. */
if (!EXPR_LOCUS (*expr_p))
annotate_with_locus (*expr_p, input_location);
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
else if (! VOID_TYPE_P (type))
{
if (target)
{
tmp = target;
ret = GS_OK;
}
else
{
tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
ret = GS_ALL_DONE;
}
/* This may be a call to a builtin function.
/* Build the then clause, 't1 = a;'. But don't build an assignment
if this branch is void; in C++ it can be, if it's a throw. */
if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
TREE_OPERAND (expr, 1)
= build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
Builtin function calls may be transformed into different
(and more efficient) builtin function calls under certain
circumstances. Unfortunately, gimplification can muck things
up enough that the builtin expanders are not aware that certain
transformations are still valid.
/* Build the else clause, 't1 = b;'. */
if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
TREE_OPERAND (expr, 2)
= build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
So we attempt transformation/gimplification of the call before
we gimplify the CALL_EXPR. At this time we do not manage to
transform all calls in the same manner as the expanders do, but
we do transform most of them. */
decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
tree new;
TREE_TYPE (expr) = void_type_node;
recalculate_side_effects (expr);
/* If it is allocation of stack, record the need to restore the memory
when the enclosing bind_expr is exited. */
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_ALLOC)
gimplify_ctxp->save_stack = true;
/* Move the COND_EXPR to the prequeue and use the temp in its place. */
gimplify_and_add (expr, pre_p);
*expr_p = tmp;
return ret;
}
/* If it is restore of the stack, reset it, since it means we are
regimplifying the bind_expr. Note that we use the fact that
for try_finally_expr, try part is processed first. */
if (DECL_FUNCTION_CODE (decl) == BUILT_IN_STACK_RESTORE)
gimplify_ctxp->save_stack = false;
/* Make sure the condition has BOOLEAN_TYPE. */
TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
/* Break apart && and || conditions. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
|| TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
{
expr = shortcut_cond_expr (expr);
if (new && new != *expr_p)
if (expr != *expr_p)
{
/* There was a transformation of this call which computes the
same value, but in a more efficient way. Return and try
again. */
*expr_p = new;
return GS_OK;
*expr_p = expr;
/* We can't rely on gimplify_expr to re-gimplify the expanded
form properly, as cleanups might cause the target labels to be
wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to
set up a conditional context. */
gimple_push_condition ();
gimplify_stmt (expr_p);
gimple_pop_condition (pre_p);
return GS_ALL_DONE;
}
}
/* There is a sequence point before the call, so any side effects in
the calling expression must occur before the actual call. Force
gimplify_expr to use an internal post queue. */
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, NULL,
is_gimple_call_addr, fb_rvalue);
/* Now do the normal gimplification. */
ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
is_gimple_condexpr, fb_rvalue);
if (PUSH_ARGS_REVERSED)
TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
for (arglist = TREE_OPERAND (*expr_p, 1); arglist;
arglist = TREE_CHAIN (arglist))
{
enum gimplify_status t;
gimple_push_condition ();
/* There is a sequence point before a function call. Side effects in
the argument list must occur before the actual call. So, when
gimplifying arguments, force gimplify_expr to use an internal
post queue which is then appended to the end of PRE_P. */
t = gimplify_expr (&TREE_VALUE (arglist), pre_p, NULL, is_gimple_val,
fb_rvalue);
gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
recalculate_side_effects (expr);
if (t == GS_ERROR)
ret = GS_ERROR;
}
if (PUSH_ARGS_REVERSED)
TREE_OPERAND (*expr_p, 1) = nreverse (TREE_OPERAND (*expr_p, 1));
gimple_pop_condition (pre_p);
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
if (ret == GS_ERROR)
;
else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
ret = GS_ALL_DONE;
else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
/* Rewrite "if (a); else b" to "if (!a) b" */
{
tree new = simplify_builtin (*expr_p, gimple_test_f == is_gimple_stmt);
TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
is_gimple_condexpr, fb_rvalue);
if (new && new != *expr_p)
{
/* There was a transformation of this call which computes the
same value, but in a more efficient way. Return and try
again. */
*expr_p = new;
return GS_OK;
}
tmp = TREE_OPERAND (expr, 1);
TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
TREE_OPERAND (expr, 2) = tmp;
}
else
/* Both arms are empty; replace the COND_EXPR with its predicate. */
expr = TREE_OPERAND (expr, 0);
/* If the function is "const" or "pure", then clear TREE_SIDE_EFFECTS on its
decl. This allows us to eliminate redundant or useless
calls to "const" functions. */
if (TREE_CODE (*expr_p) == CALL_EXPR
&& (call_expr_flags (*expr_p) & (ECF_CONST | ECF_PURE)))
TREE_SIDE_EFFECTS (*expr_p) = 0;
*expr_p = expr;
return ret;
}
/* Handle shortcut semantics in the predicate operand of a COND_EXPR by
rewriting it into multiple COND_EXPRs, and possibly GOTO_EXPRs.
/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
a call to __builtin_memcpy. */
TRUE_LABEL_P and FALSE_LABEL_P point to the labels to jump to if the
condition is true or false, respectively. If null, we should generate
our own to skip over the evaluation of this specific expression.
static enum gimplify_status
gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
{
tree args, t, to, to_ptr, from;
This function is the tree equivalent of do_jump.
to = TREE_OPERAND (*expr_p, 0);
from = TREE_OPERAND (*expr_p, 1);
shortcut_cond_r should only be called by shortcut_cond_expr. */
t = TYPE_SIZE_UNIT (TREE_TYPE (to));
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, from);
t = unshare_expr (t);
args = tree_cons (NULL, t, NULL);
static tree
shortcut_cond_r (tree pred, tree *true_label_p, tree *false_label_p)
{
tree local_label = NULL_TREE;
tree t, expr = NULL;
t = build_fold_addr_expr (from);
args = tree_cons (NULL, t, args);
/* OK, it's not a simple case; we need to pull apart the COND_EXPR to
retain the shortcut semantics. Just insert the gotos here;
shortcut_cond_expr will append the real blocks later. */
if (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
{
/* Turn if (a && b) into
to_ptr = build_fold_addr_expr (to);
args = tree_cons (NULL, to, args);
t = implicit_built_in_decls[BUILT_IN_MEMCPY];
t = build_function_call_expr (t, args);
if (a); else goto no;
if (b) goto yes; else goto no;
(no:) */
if (want_value)
{
t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
}
if (false_label_p == NULL)
false_label_p = &local_label;
*expr_p = t;
return GS_OK;
}
t = shortcut_cond_r (TREE_OPERAND (pred, 0), NULL, false_label_p);
append_to_statement_list (t, &expr);
/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
a call to __builtin_memset. In this case we know that the RHS is
a CONSTRUCTOR with an empty element list. */
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p);
append_to_statement_list (t, &expr);
}
else if (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
{
/* Turn if (a || b) into
static enum gimplify_status
gimplify_modify_expr_to_memset (tree *expr_p, bool want_value)
{
tree args, t, to, to_ptr;
if (a) goto yes;
if (b) goto yes; else goto no;
(yes:) */
to = TREE_OPERAND (*expr_p, 0);
if (true_label_p == NULL)
true_label_p = &local_label;
t = TYPE_SIZE_UNIT (TREE_TYPE (to));
t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
t = unshare_expr (t);
args = tree_cons (NULL, t, NULL);
t = shortcut_cond_r (TREE_OPERAND (pred, 0), true_label_p, NULL);
append_to_statement_list (t, &expr);
args = tree_cons (NULL, integer_zero_node, args);
t = shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p);
append_to_statement_list (t, &expr);
}
else if (TREE_CODE (pred) == COND_EXPR)
{
/* As long as we're messing with gotos, turn if (a ? b : c) into
if (a)
if (b) goto yes; else goto no;
else
if (c) goto yes; else goto no; */
expr = build (COND_EXPR, void_type_node, TREE_OPERAND (pred, 0),
shortcut_cond_r (TREE_OPERAND (pred, 1), true_label_p,
false_label_p),
shortcut_cond_r (TREE_OPERAND (pred, 2), true_label_p,
false_label_p));
}
else
{
expr = build (COND_EXPR, void_type_node, pred,
build_and_jump (true_label_p),
build_and_jump (false_label_p));
}
to_ptr = build_fold_addr_expr (to);
args = tree_cons (NULL, to, args);
t = implicit_built_in_decls[BUILT_IN_MEMSET];
t = build_function_call_expr (t, args);
if (local_label)
if (want_value)
{
t = build1 (LABEL_EXPR, void_type_node, local_label);
append_to_statement_list (t, &expr);
t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
}
return expr;
*expr_p = t;
return GS_OK;
}
static tree
shortcut_cond_expr (tree expr)
/* A subroutine of gimplify_modify_expr. Break out elements of a
CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
Note that we still need to clear any elements that don't have explicit
initializers, so if not all elements are initialized we keep the
original MODIFY_EXPR, we just remove all of the constructor elements. */
static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
tree *post_p, bool want_value)
{
tree pred = TREE_OPERAND (expr, 0);
tree then_ = TREE_OPERAND (expr, 1);
tree else_ = TREE_OPERAND (expr, 2);
tree true_label, false_label, end_label, t;
tree *true_label_p;
tree *false_label_p;
bool emit_end, emit_false;
bool then_se = then_ && TREE_SIDE_EFFECTS (then_);
bool else_se = else_ && TREE_SIDE_EFFECTS (else_);
tree object = TREE_OPERAND (*expr_p, 0);
tree ctor = TREE_OPERAND (*expr_p, 1);
tree type = TREE_TYPE (ctor);
enum gimplify_status ret;
tree elt_list;
/* First do simple transformations. */
if (!else_se)
if (TREE_CODE (ctor) != CONSTRUCTOR)
return GS_UNHANDLED;
elt_list = CONSTRUCTOR_ELTS (ctor);
ret = GS_ALL_DONE;
switch (TREE_CODE (type))
{
/* If there is no 'else', turn (a && b) into if (a) if (b). */
while (TREE_CODE (pred) == TRUTH_ANDIF_EXPR)
case RECORD_TYPE:
case UNION_TYPE:
case QUAL_UNION_TYPE:
case ARRAY_TYPE:
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
then_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, then_, NULL_TREE);
}
}
if (!then_se)
HOST_WIDE_INT i, num_elements, num_nonzero_elements;
HOST_WIDE_INT num_nonconstant_elements;
bool cleared;
/* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node
with no elements indicates zero-initialization of the whole. */
if (elt_list == NULL)
{
/* If there is no 'then', turn
if (a || b); else d
into
if (a); else if (b); else d. */
while (TREE_CODE (pred) == TRUTH_ORIF_EXPR)
if (want_value)
{
TREE_OPERAND (expr, 0) = TREE_OPERAND (pred, 1);
else_ = shortcut_cond_expr (expr);
pred = TREE_OPERAND (pred, 0);
expr = build (COND_EXPR, void_type_node, pred, NULL_TREE, else_);
*expr_p = object;
return GS_OK;
}
else
return GS_UNHANDLED;
}
/* If we're done, great. */
if (TREE_CODE (pred) != TRUTH_ANDIF_EXPR
&& TREE_CODE (pred) != TRUTH_ORIF_EXPR)
return expr;
categorize_ctor_elements (ctor, &num_nonzero_elements,
&num_nonconstant_elements);
num_elements = count_type_elements (TREE_TYPE (ctor));
/* Otherwise we need to mess with gotos. Change
if (a) c; else d;
to
if (a); else goto no;
c; goto end;
no: d; end:
and recursively gimplify the condition. */
/* If a const aggregate variable is being initialized, then it
should never be a lose to promote the variable to be static. */
if (num_nonconstant_elements == 0
&& TREE_READONLY (object)
&& TREE_CODE (object) == VAR_DECL)
{
DECL_INITIAL (object) = ctor;
TREE_STATIC (object) = 1;
if (!DECL_NAME (object))
DECL_NAME (object) = create_tmp_var_name ("C");
walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
true_label = false_label = end_label = NULL_TREE;
/* ??? C++ doesn't automatically append a .<number> to the
assembler name, and even when it does, it looks a FE private
data structures to figure out what that number should be,
which are not set for this variable. I suppose this is
important for local statics for inline functions, which aren't
"local" in the object file sense. So in order to get a unique
TU-local symbol, we must invoke the lhd version now. */
lhd_set_decl_assembler_name (object);
/* If our arms just jump somewhere, hijack those labels so we don't
generate jumps to jumps. */
*expr_p = NULL_TREE;
break;
}
if (then_
&& TREE_CODE (then_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (then_)) == LABEL_DECL)
/* 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)
{
true_label = GOTO_DESTINATION (then_);
then_ = NULL;
then_se = false;
}
HOST_WIDE_INT size = int_size_in_bytes (type);
unsigned int align;
if (else_
&& TREE_CODE (else_) == GOTO_EXPR
&& TREE_CODE (GOTO_DESTINATION (else_)) == LABEL_DECL)
/* ??? We can still get unbounded array types, at least
from the C++ front end. This seems wrong, but attempt
to work around it for now. */
if (size < 0)
{
false_label = GOTO_DESTINATION (else_);
else_ = NULL;
else_se = false;
size = int_size_in_bytes (TREE_TYPE (object));
if (size >= 0)
TREE_TYPE (ctor) = type = TREE_TYPE (object);
}
/* If we aren't hijacking a label for the 'then' branch, it falls through. */
if (true_label)
true_label_p = &true_label;
else
true_label_p = NULL;
/* The 'else' branch also needs a label if it contains interesting code. */
if (false_label || else_se)
false_label_p = &false_label;
else
false_label_p = NULL;
/* If there was nothing else in our arms, just forward the label(s). */
if (!then_se && !else_se)
return shortcut_cond_r (pred, true_label_p, false_label_p);
/* If our last subexpression already has a terminal label, reuse it. */
if (else_se)
expr = expr_last (else_);
else if (then_se)
expr = expr_last (then_);
/* Find the maximum alignment we can assume for the object. */
/* ??? Make use of DECL_OFFSET_ALIGN. */
if (DECL_P (object))
align = DECL_ALIGN (object);
else
expr = NULL;
if (expr && TREE_CODE (expr) == LABEL_EXPR)
end_label = LABEL_EXPR_LABEL (expr);
align = TYPE_ALIGN (type);
/* If we don't care about jumping to the 'else' branch, jump to the end
if the condition is false. */
if (!false_label_p)
false_label_p = &end_label;
if (size > 0 && !can_move_by_pieces (size, align))
{
tree new = create_tmp_var_raw (type, "C");
gimple_add_tmp_var (new);
TREE_STATIC (new) = 1;
TREE_READONLY (new) = 1;
DECL_INITIAL (new) = ctor;
if (align > DECL_ALIGN (new))
{
DECL_ALIGN (new) = align;
DECL_USER_ALIGN (new) = 1;
}
walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
/* We only want to emit these labels if we aren't hijacking them. */
emit_end = (end_label == NULL_TREE);
emit_false = (false_label == NULL_TREE);
TREE_OPERAND (*expr_p, 1) = new;
break;
}
}
pred = shortcut_cond_r (pred, true_label_p, false_label_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. */
expr = NULL;
append_to_statement_list (pred, &expr);
/* 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)
cleared = true;
append_to_statement_list (then_, &expr);
if (else_se)
/* ??? 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
{
t = build_and_jump (&end_label);
append_to_statement_list (t, &expr);
if (emit_false)
HOST_WIDE_INT len = list_length (elt_list);
if (TREE_CODE (type) == ARRAY_TYPE)
{
t = build1 (LABEL_EXPR, void_type_node, false_label);
append_to_statement_list (t, &expr);
tree nelts = array_type_nelts (type);
if (!host_integerp (nelts, 1)
|| tree_low_cst (nelts, 1) != len)
cleared = 1;;
}
append_to_statement_list (else_, &expr);
else if (len != fields_length (type))
cleared = 1;
}
if (emit_end && end_label)
if (cleared)
{
t = build1 (LABEL_EXPR, void_type_node, end_label);
append_to_statement_list (t, &expr);
/* Zap the CONSTRUCTOR element list, which simplifies this case.
Note that we still have to gimplify, in order to handle the
case of variable sized types. */
CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
gimplify_stmt (expr_p);
append_to_statement_list (*expr_p, pre_p);
}
return expr;
}
/* EXPR is used in a boolean context; make sure it has BOOLEAN_TYPE. */
static tree
gimple_boolify (tree expr)
{
tree type = TREE_TYPE (expr);
for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list))
{
tree purpose, value, cref, init;
if (TREE_CODE (type) == BOOLEAN_TYPE)
return expr;
purpose = TREE_PURPOSE (elt_list);
value = TREE_VALUE (elt_list);
/* If this is the predicate of a COND_EXPR, it might not even be a
truthvalue yet. */
expr = lang_hooks.truthvalue_conversion (expr);
if (cleared && initializer_zerop (value))
continue;
switch (TREE_CODE (expr))
if (TREE_CODE (type) == ARRAY_TYPE)
{
case TRUTH_AND_EXPR:
case TRUTH_OR_EXPR:
case TRUTH_XOR_EXPR:
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
/* Also boolify the arguments of truth exprs. */
TREE_OPERAND (expr, 1) = gimple_boolify (TREE_OPERAND (expr, 1));
/* FALLTHRU */
case TRUTH_NOT_EXPR:
TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
/* FALLTHRU */
tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
case EQ_EXPR: case NE_EXPR:
case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR:
/* These expressions always produce boolean results. */
TREE_TYPE (expr) = boolean_type_node;
return 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 ();
default:
/* Other expressions that get here must have boolean values, but
might need to be converted to the appropriate mode. */
return convert (boolean_type_node, expr);
cref = build (ARRAY_REF, t, object, purpose,
NULL_TREE, NULL_TREE);
}
}
/* Convert the conditional expression pointed by EXPR_P '(p) ? a : b;'
into
if (p) if (p)
t1 = a; a;
else or else
t1 = b; b;
t1;
The second form is used when *EXPR_P is of type void.
else
cref = build (COMPONENT_REF, TREE_TYPE (purpose), object,
purpose, NULL_TREE);
TARGET is the tree for T1 above.
init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored. */
/* Each member initialization is a full-expression. */
gimplify_and_add (init, pre_p);
}
static enum gimplify_status
gimplify_cond_expr (tree *expr_p, tree *pre_p, tree target)
{
tree expr = *expr_p;
tree tmp, type;
enum gimplify_status ret;
*expr_p = NULL_TREE;
}
break;
type = TREE_TYPE (expr);
if (!type)
TREE_TYPE (expr) = void_type_node;
case COMPLEX_TYPE:
{
tree r, i;
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
else if (! VOID_TYPE_P (type))
/* Extract the real and imaginary parts out of the ctor. */
r = i = NULL_TREE;
if (elt_list)
{
r = TREE_VALUE (elt_list);
elt_list = TREE_CHAIN (elt_list);
if (elt_list)
{
if (target)
i = TREE_VALUE (elt_list);
if (TREE_CHAIN (elt_list))
abort ();
}
}
if (r == NULL || i == NULL)
{
tmp = target;
ret = GS_OK;
tree zero = convert (TREE_TYPE (type), integer_zero_node);
if (r == NULL)
r = zero;
if (i == NULL)
i = zero;
}
/* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
represent creation of a complex value. */
if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
{
ctor = build_complex (type, r, i);
TREE_OPERAND (*expr_p, 1) = ctor;
}
else
{
tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
ret = GS_ALL_DONE;
ctor = build (COMPLEX_EXPR, type, r, i);
TREE_OPERAND (*expr_p, 1) = ctor;
ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
is_gimple_rhs, fb_rvalue);
}
}
break;
/* Build the then clause, 't1 = a;'. But don't build an assignment
if this branch is void; in C++ it can be, if it's a throw. */
if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
TREE_OPERAND (expr, 1)
= build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
/* Build the else clause, 't1 = b;'. */
if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
TREE_OPERAND (expr, 2)
= build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
TREE_TYPE (expr) = void_type_node;
recalculate_side_effects (expr);
case VECTOR_TYPE:
/* Go ahead and simplify constant constructors to VECTOR_CST. */
if (TREE_CONSTANT (ctor))
TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
else
{
/* Vector types use CONSTRUCTOR all the way through gimple
compilation as a general initializer. */
for (; elt_list; elt_list = TREE_CHAIN (elt_list))
{
enum gimplify_status tret;
tret = gimplify_expr (&TREE_VALUE (elt_list), pre_p, post_p,
is_gimple_constructor_elt, fb_rvalue);
if (tret == GS_ERROR)
ret = GS_ERROR;
}
}
break;
/* Move the COND_EXPR to the prequeue and use the temp in its place. */
gimplify_and_add (expr, pre_p);
*expr_p = tmp;
default:
/* So how did we get a CONSTRUCTOR for a scalar type? */
abort ();
}
return ret;
if (ret == GS_ERROR)
return GS_ERROR;
else if (want_value)
{
append_to_statement_list (*expr_p, pre_p);
*expr_p = object;
return GS_OK;
}
else
return GS_ALL_DONE;
}
/* Make sure the condition has BOOLEAN_TYPE. */
TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
/* 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. */
/* Break apart && and || conditions. */
if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
|| TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
{
expr = shortcut_cond_expr (expr);
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;
if (expr != *expr_p)
while (ret != GS_UNHANDLED)
switch (TREE_CODE (*from_p))
{
*expr_p = expr;
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.
/* We can't rely on gimplify_expr to re-gimplify the expanded
form properly, as cleanups might cause the target labels to be
wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to
set up a conditional context. */
gimple_push_condition ();
gimplify_stmt (expr_p);
gimple_pop_condition (pre_p);
??? 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);
return GS_ALL_DONE;
if (!VOID_TYPE_P (TREE_TYPE (init)))
{
*from_p = init;
ret = GS_OK;
}
else
ret = GS_UNHANDLED;
}
break;
/* Now do the normal gimplification. */
ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
is_gimple_condexpr, fb_rvalue);
gimple_push_condition ();
gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
recalculate_side_effects (expr);
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;
gimple_pop_condition (pre_p);
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);
if (ret == GS_ERROR)
;
else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
ret = GS_ALL_DONE;
else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
/* Rewrite "if (a); else b" to "if (!a) b" */
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)))
{
TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
is_gimple_condexpr, fb_rvalue);
tmp = TREE_OPERAND (expr, 1);
TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
TREE_OPERAND (expr, 2) = tmp;
*expr_p = *from_p;
return gimplify_cond_expr (expr_p, pre_p, *to_p);
}
else
/* Both arms are empty; replace the COND_EXPR with its predicate. */
expr = TREE_OPERAND (expr, 0);
ret = GS_UNHANDLED;
break;
default:
ret = GS_UNHANDLED;
break;
}
*expr_p = expr;
return ret;
}
......@@ -2628,31 +2770,15 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
return ret;
/* 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
if the copy by converting the whole thing to a memcpy/memset.
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 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 (TREE_CODE (*from_p) == CONSTRUCTOR)
return gimplify_modify_expr_to_memset (expr_p, want_value);
else
return gimplify_modify_expr_to_memcpy (expr_p, want_value);
}
ret = gimplify_expr (to_p, pre_p, post_p, is_gimple_lvalue, fb_lvalue);
......@@ -2707,75 +2833,6 @@ gimplify_modify_expr (tree *expr_p, tree *pre_p, tree *post_p, bool want_value)
return ret;
}
/* Subroutine of above to do simplifications 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. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment