/* Tree lowering pass. This pass converts the GENERIC functions-as-trees
tree representation into the GIMPLE form.
- Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
Major work done by Sebastian Pop <s.pop@laposte.net>,
Diego Novillo <dnovillo@redhat.com> and Jason Merrill <jason@redhat.com>.
{
tree result;
- if ((fallback & fb_lvalue) == 0)
+ /* If an rvalue is ok or we do not require an lvalue, avoid creating
+ an addressable temporary. */
+ if (((fallback & fb_rvalue)
+ || !(fallback & fb_lvalue))
+ && !TREE_ADDRESSABLE (type))
{
if (gimplify_ctxp->allow_rhs_cond_expr
/* If either branch has side effects or could trap, it can't be
if (array_elt_type)
{
+ /* Do not use bitsizetype for ARRAY_REF indices. */
+ if (TYPE_DOMAIN (TREE_TYPE (object)))
+ purpose = fold_convert (TREE_TYPE (TYPE_DOMAIN (TREE_TYPE (object))),
+ purpose);
cref = build4 (ARRAY_REF, array_elt_type, unshare_expr (object),
purpose, NULL_TREE, NULL_TREE);
}
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. */
+ original MODIFY_EXPR, we just remove all of the constructor elements.
+
+ If NOTIFY_TEMP_CREATION is true, do not gimplify, just return
+ GS_ERROR if we would have to create a temporary when gimplifying
+ this constructor. Otherwise, return GS_OK.
+
+ If NOTIFY_TEMP_CREATION is false, just do the gimplification. */
static enum gimplify_status
gimplify_init_constructor (tree *expr_p, tree *pre_p,
- tree *post_p, bool want_value)
+ tree *post_p, bool want_value,
+ bool notify_temp_creation)
{
tree object;
tree ctor = GENERIC_TREE_OPERAND (*expr_p, 1);
if (TREE_CODE (ctor) != CONSTRUCTOR)
return GS_UNHANDLED;
- ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p,
- is_gimple_lvalue, fb_lvalue);
- if (ret == GS_ERROR)
- return ret;
+ if (!notify_temp_creation)
+ {
+ ret = gimplify_expr (&GENERIC_TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+ is_gimple_lvalue, fb_lvalue);
+ if (ret == GS_ERROR)
+ return ret;
+ }
object = GENERIC_TREE_OPERAND (*expr_p, 0);
elts = CONSTRUCTOR_ELTS (ctor);
individual elements. The exception is that a CONSTRUCTOR node
with no elements indicates zero-initialization of the whole. */
if (VEC_empty (constructor_elt, elts))
- break;
+ {
+ if (notify_temp_creation)
+ return GS_OK;
+ break;
+ }
/* Fetch information about the constructor to direct later processing.
We might want to make static versions of it in various cases, and
&& TREE_READONLY (object)
&& TREE_CODE (object) == VAR_DECL)
{
+ if (notify_temp_creation)
+ return GS_ERROR;
DECL_INITIAL (object) = ctor;
TREE_STATIC (object) = 1;
if (!DECL_NAME (object))
if (size > 0 && !can_move_by_pieces (size, align))
{
- tree new = create_tmp_var_raw (type, "C");
+ tree new;
+
+ if (notify_temp_creation)
+ return GS_ERROR;
+
+ new = create_tmp_var_raw (type, "C");
gimple_add_tmp_var (new);
TREE_STATIC (new) = 1;
}
}
+ if (notify_temp_creation)
+ return GS_OK;
+
/* If there are nonzero elements, pre-evaluate to capture elements
overlapping with the lhs into temporaries. We must do this before
clearing to fetch the values before they are zeroed-out. */
{
tree r, i;
+ if (notify_temp_creation)
+ return GS_OK;
+
/* Extract the real and imaginary parts out of the ctor. */
gcc_assert (VEC_length (constructor_elt, elts) == 2);
r = VEC_index (constructor_elt, elts, 0)->value;
unsigned HOST_WIDE_INT ix;
constructor_elt *ce;
+ if (notify_temp_creation)
+ return GS_OK;
+
/* Go ahead and simplify constant constructors to VECTOR_CST. */
if (TREE_CONSTANT (ctor))
{
/* 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. */
+ possible. 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
+gimple_fold_indirect_ref (tree t)
{
tree type = TREE_TYPE (TREE_TYPE (t));
tree sub = t;
/* *&p => p */
if (useless_type_conversion_p (type, optype))
return op;
+
/* *(foo *)&fooarray => fooarray[0] */
- else if (TREE_CODE (optype) == ARRAY_TYPE
- && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ if (TREE_CODE (optype) == ARRAY_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
{
tree type_domain = TYPE_DOMAIN (optype);
tree min_val = size_zero_node;
tree type_domain;
tree min_val = size_zero_node;
tree osub = sub;
- sub = fold_indirect_ref_rhs (sub);
+ sub = gimple_fold_indirect_ref (sub);
if (! sub)
sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), osub);
type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
return NULL_TREE;
}
+/* 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
+gimple_fold_indirect_ref_rhs (tree t)
+{
+ return gimple_fold_indirect_ref (t);
+}
+
/* 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. */
constructor expression to the RHS of the MODIFY_EXPR. */
if (DECL_INITIAL (*from_p)
&& TYPE_READONLY (TREE_TYPE (*from_p))
+ && !TREE_THIS_VOLATILE (*from_p)
&& TREE_CODE (DECL_INITIAL (*from_p)) == CONSTRUCTOR)
{
- *from_p = DECL_INITIAL (*from_p);
- ret = GS_OK;
+ tree old_from = *from_p;
+
+ /* Move the constructor into the RHS. */
+ *from_p = unshare_expr (DECL_INITIAL (*from_p));
+
+ /* Let's see if gimplify_init_constructor will need to put
+ it in memory. If so, revert the change. */
+ ret = gimplify_init_constructor (expr_p, NULL, NULL, false, true);
+ if (ret == GS_ERROR)
+ {
+ *from_p = old_from;
+ /* Fall through. */
+ }
+ else
+ {
+ ret = GS_OK;
+ break;
+ }
}
ret = GS_UNHANDLED;
break;
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_rhs (TREE_OPERAND (*from_p, 0));
+ tree t = gimple_fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
if (t)
{
*from_p = t;
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);
+ return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
+ false);
case COND_EXPR:
/* If we're assigning to a non-register type, push the assignment
/* Promote partial stores to COMPLEX variables to total stores. *EXPR_P is
a MODIFY_EXPR with a lhs of a REAL/IMAGPART_EXPR of a variable with
- DECL_GIMPLE_REG_P set. */
+ DECL_GIMPLE_REG_P set.
+
+ IMPORTANT NOTE: This promotion is performed by introducing a load of the
+ other, unmodified part of the complex object just before the total store.
+ As a consequence, if the object is still uninitialized, an undefined value
+ will be loaded into a register, which may result in a spurious exception
+ if the register is floating-point and the value happens to be a signaling
+ NaN for example. Then the fully-fledged complex operations lowering pass
+ followed by a DCE pass are necessary in order to fix things up. */
static enum gimplify_status
gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
else
var = decl;
+ /* If OMP_FOR is re-gimplified, ensure all variables in pre-body
+ are noticed. */
+ gimplify_stmt (&OMP_FOR_PRE_BODY (for_stmt));
+
ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
&OMP_FOR_PRE_BODY (for_stmt),
NULL, is_gimple_val, fb_rvalue);
ret = DECL_RESULT (fndecl);
if ((TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
+ || TREE_CODE (TREE_TYPE (ret)) == VECTOR_TYPE)
&& !needs_to_live_in_memory (ret))
DECL_GIMPLE_REG_P (ret) = 1;
pop_gimplify_context (NULL);
+ if (*stmts && gimple_in_ssa_p (cfun))
+ {
+ tree_stmt_iterator tsi;
+
+ for (tsi = tsi_start (*stmts); !tsi_end_p (tsi); tsi_next (&tsi))
+ mark_symbols_for_renaming (tsi_stmt (tsi));
+ }
+
return expr;
}
expr = force_gimple_operand (expr, &stmts, simple_p, var);
if (stmts)
{
- if (gimple_in_ssa_p (cfun))
- {
- tree_stmt_iterator tsi;
-
- for (tsi = tsi_start (stmts); !tsi_end_p (tsi); tsi_next (&tsi))
- mark_symbols_for_renaming (tsi_stmt (tsi));
- }
-
if (before)
bsi_insert_before (bsi, stmts, m);
else