/* 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>.
int conditions;
bool save_stack;
bool into_ssa;
+ bool allow_rhs_cond_expr;
};
static struct gimplify_ctx *gimplify_ctxp;
}
}
+/* Given a conditional expression *EXPR_P without side effects, gimplify
+ its operands. New statements are inserted to PRE_P. */
+
+static enum gimplify_status
+gimplify_pure_cond_expr (tree *expr_p, tree *pre_p)
+{
+ tree expr = *expr_p, cond;
+ enum gimplify_status ret, tret;
+ enum tree_code code;
+
+ cond = gimple_boolify (COND_EXPR_COND (expr));
+
+ /* We need to handle && and || specially, as their gimplification
+ creates pure cond_expr, thus leading to an infinite cycle otherwise. */
+ code = TREE_CODE (cond);
+ if (code == TRUTH_ANDIF_EXPR)
+ TREE_SET_CODE (cond, TRUTH_AND_EXPR);
+ else if (code == TRUTH_ORIF_EXPR)
+ TREE_SET_CODE (cond, TRUTH_OR_EXPR);
+ ret = gimplify_expr (&cond, pre_p, NULL,
+ is_gimple_condexpr, fb_rvalue);
+ COND_EXPR_COND (*expr_p) = cond;
+
+ tret = gimplify_expr (&COND_EXPR_THEN (expr), pre_p, NULL,
+ is_gimple_val, fb_rvalue);
+ ret = MIN (ret, tret);
+ tret = gimplify_expr (&COND_EXPR_ELSE (expr), pre_p, NULL,
+ is_gimple_val, fb_rvalue);
+
+ return MIN (ret, tret);
+}
+
+/* Returns true if evaluating EXPR could trap.
+ EXPR is GENERIC, while tree_could_trap_p can be called
+ only on GIMPLE. */
+
+static bool
+generic_expr_could_trap_p (tree expr)
+{
+ unsigned i, n;
+
+ if (!expr || is_gimple_val (expr))
+ return false;
+
+ if (!EXPR_P (expr) || tree_could_trap_p (expr))
+ return true;
+
+ n = TREE_OPERAND_LENGTH (expr);
+ for (i = 0; i < n; i++)
+ if (generic_expr_could_trap_p (TREE_OPERAND (expr, i)))
+ return true;
+
+ return false;
+}
+
/* Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;'
into
{
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
+ evaluated unconditionally. */
+ && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 1))
+ && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 1))
+ && !TREE_SIDE_EFFECTS (TREE_OPERAND (*expr_p, 2))
+ && !generic_expr_could_trap_p (TREE_OPERAND (*expr_p, 2)))
+ return gimplify_pure_cond_expr (expr_p, pre_p);
+
result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
ret = GS_ALL_DONE;
}
if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
TREE_OPERAND (expr, 2) =
build_fold_addr_expr (TREE_OPERAND (expr, 2));
-
+
tmp2 = tmp = create_tmp_var (type, "iftmp");
expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
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;
}
-/* 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. */
+/* 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. */
static enum gimplify_status
gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p, tree *pre_p,
while (ret != GS_UNHANDLED)
switch (TREE_CODE (*from_p))
{
+ case VAR_DECL:
+ /* If we're assigning from a constant constructor, move the
+ 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)
+ {
+ 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;
case INDIRECT_REF:
{
/* If we have code like
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;
push_gimplify_context ();
gimplify_ctxp->into_ssa = gimple_in_ssa_p (cfun);
+ gimplify_ctxp->allow_rhs_cond_expr = true;
if (var)
expr = build_gimple_modify_stmt (var, expr);
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