You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
-#include "errors.h"
#include "varray.h"
#include "tree-gimple.h"
#include "tree-inline.h"
#include "output.h"
#include "expr.h"
#include "ggc.h"
+#include "toplev.h"
#include "target.h"
static struct gimplify_ctx
tree conditional_cleanups;
tree exit_label;
tree return_temp;
- varray_type case_labels;
+ VEC(tree,heap) *case_labels;
/* The formal temporary table. Should this be persistent? */
htab_t temp_htab;
int conditions;
t = lookup_tmp_var (val, is_formal);
+ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE)
+ DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
+
mod = build (MODIFY_EXPR, TREE_TYPE (t), t, val);
if (EXPR_HAS_LOCATION (val))
|| TREE_CODE_CLASS (code) == tcc_constant
|| code == SAVE_EXPR || code == TARGET_EXPR
/* We can't do anything sensible with a BLOCK used as an expression,
- but we also can't abort when we see it because of non-expression
+ but we also can't just die when we see it because of non-expression
uses. So just avert our eyes and cross our fingers. Silly Java. */
|| code == BLOCK)
*walk_subtrees = 0;
/* Mark variables seen in this bind expr. */
for (t = BIND_EXPR_VARS (bind_expr); t ; t = TREE_CHAIN (t))
- DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
+ {
+ DECL_SEEN_IN_BIND_EXPR_P (t) = 1;
+
+ /* Preliminarily mark non-addressed complex variables as eligible
+ for promotion to gimple registers. We'll transform their uses
+ as we find them. */
+ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE
+ && !TREE_THIS_VOLATILE (t)
+ && (TREE_CODE (t) == VAR_DECL && !DECL_HARD_REGISTER (t))
+ && !needs_to_live_in_memory (t))
+ DECL_COMPLEX_GIMPLE_REG_P (t) = 1;
+ }
gimple_push_bind_expr (bind_expr);
gimplify_ctxp->save_stack = false;
returned in registers. If we're returning values in registers, then
we don't want to extend the lifetime of the RESULT_DECL, particularly
across another call. In addition, for those aggregates for which
- hard_function_value generates a PARALLEL, we'll abort during normal
+ hard_function_value generates a PARALLEL, we'll die during normal
expansion of structure assignments; there's special code in expand_return
to handle this case that does not exist in expand_expr. */
if (!result_decl
if (TREE_TYPE (decl) == error_mark_node)
return GS_ERROR;
- else if (TREE_CODE (decl) == TYPE_DECL)
+ if ((TREE_CODE (decl) == TYPE_DECL
+ || TREE_CODE (decl) == VAR_DECL)
+ && !TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
- else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
{
tree init = DECL_INITIAL (decl);
of the emitted code: see mx_register_decls(). */
tree t, args, addr, ptr_type;
- /* ??? We really shouldn't need to gimplify the type of the variable
- since it already should have been done. But leave this here
- for now to avoid disrupting too many things at once. */
- if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (decl)))
- gimplify_type_sizes (TREE_TYPE (decl), stmt_p);
-
gimplify_one_sizepos (&DECL_SIZE (decl), stmt_p);
gimplify_one_sizepos (&DECL_SIZE_UNIT (decl), stmt_p);
addr = create_tmp_var (ptr_type, get_name (decl));
DECL_IGNORED_P (addr) = 0;
t = build_fold_indirect_ref (addr);
- DECL_VALUE_EXPR (decl) = t;
+ SET_DECL_VALUE_EXPR (decl, t);
+ DECL_HAS_VALUE_EXPR_P (decl) = 1;
args = tree_cons (NULL, DECL_SIZE_UNIT (decl), NULL);
t = built_in_decls[BUILT_IN_ALLOCA];
if (SWITCH_BODY (switch_expr))
{
- varray_type labels, saved_labels;
+ VEC(tree,heap) *labels, *saved_labels;
tree label_vec, default_case = NULL_TREE;
size_t i, len;
gcc_assert (!SWITCH_LABELS (switch_expr));
saved_labels = gimplify_ctxp->case_labels;
- VARRAY_TREE_INIT (gimplify_ctxp->case_labels, 8, "case_labels");
+ gimplify_ctxp->case_labels = VEC_alloc (tree, heap, 8);
gimplify_to_stmt_list (&SWITCH_BODY (switch_expr));
labels = gimplify_ctxp->case_labels;
gimplify_ctxp->case_labels = saved_labels;
- len = VARRAY_ACTIVE_SIZE (labels);
+ len = VEC_length (tree, labels);
for (i = 0; i < len; ++i)
{
- tree t = VARRAY_TREE (labels, i);
+ tree t = VEC_index (tree, labels, i);
if (!CASE_LOW (t))
{
/* The default case must be the last label in the list. */
default_case = t;
- VARRAY_TREE (labels, i) = VARRAY_TREE (labels, len - 1);
+ VEC_replace (tree, labels, i, VEC_index (tree, labels, len - 1));
len--;
break;
}
*expr_p = SWITCH_BODY (switch_expr);
for (i = 0; i < len; ++i)
- TREE_VEC_ELT (label_vec, i) = VARRAY_TREE (labels, i);
+ TREE_VEC_ELT (label_vec, i) = VEC_index (tree, labels, i);
TREE_VEC_ELT (label_vec, len) = default_case;
+ VEC_free (tree, heap, labels);
+
sort_case_labels (label_vec);
SWITCH_BODY (switch_expr) = NULL;
tree expr = *expr_p;
gcc_assert (gimplify_ctxp->case_labels);
- VARRAY_PUSH_TREE (gimplify_ctxp->case_labels, expr);
+ VEC_safe_push (tree, heap, gimplify_ctxp->case_labels, expr);
*expr_p = build (LABEL_EXPR, void_type_node, CASE_LABEL (expr));
return GS_ALL_DONE;
}
tree *post_p, fallback_t fallback)
{
tree *p;
- varray_type stack;
+ VEC(tree,heap) *stack;
enum gimplify_status ret = GS_OK, tret;
int i;
/* Create a stack of the subexpressions so later we can walk them in
- order from inner to outer.
-
- This array is very memory consuming. Don't even think of making
- it VARRAY_TREE. */
- VARRAY_GENERIC_PTR_NOGC_INIT (stack, 10, "stack");
+ order from inner to outer. */
+ stack = VEC_alloc (tree, heap, 10);
/* We can handle anything that get_inner_reference can deal with. */
for (p = expr_p; ; p = &TREE_OPERAND (*p, 0))
*p = fold_indirect_ref (*p);
if (!handled_component_p (*p))
break;
- VARRAY_PUSH_GENERIC_PTR_NOGC (stack, *p);
+ VEC_safe_push (tree, heap, stack, *p);
}
- gcc_assert (VARRAY_ACTIVE_SIZE (stack));
+ gcc_assert (VEC_length (tree, stack));
/* Now STACK is a stack of pointers to all the refs we've walked through
and P points to the innermost expression.
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--)
+ for (i = VEC_length (tree, stack) - 1; i >= 0; i--)
{
- tree t = VARRAY_GENERIC_PTR_NOGC (stack, i);
+ tree t = VEC_index (tree, stack, i);
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
/* And finally, the indices and operands to BIT_FIELD_REF. During this
loop we also remove any useless conversions. */
- for (; VARRAY_ACTIVE_SIZE (stack) > 0; )
+ for (; VEC_length (tree, stack) > 0; )
{
- tree t = VARRAY_TOP_TREE (stack);
+ tree t = VEC_pop (tree, stack);
if (TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
{
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);
}
tret = gimplify_expr (p, pre_p, post_p, is_gimple_min_lval, fallback);
ret = MIN (ret, GS_OK);
}
- VARRAY_FREE (stack);
+ VEC_free (tree, heap, stack);
return ret;
}
decl = get_callee_fndecl (*expr_p);
if (decl && DECL_BUILT_IN (decl))
{
- tree new = fold_builtin (*expr_p, !want_value);
+ tree fndecl = get_callee_fndecl (*expr_p);
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+ tree new = fold_builtin (fndecl, arglist, !want_value);
if (new && new != *expr_p)
{
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
&& DECL_FUNCTION_CODE (decl) == BUILT_IN_VA_START)
{
- tree arglist = TREE_OPERAND (*expr_p, 1);
-
if (!arglist || !TREE_CHAIN (arglist))
{
error ("too few arguments to function %<va_start%>");
/* Try this again in case gimplification exposed something. */
if (ret != GS_ERROR && decl && DECL_BUILT_IN (decl))
{
- tree new = fold_builtin (*expr_p, !want_value);
+ tree fndecl = get_callee_fndecl (*expr_p);
+ tree arglist = TREE_OPERAND (*expr_p, 1);
+ tree new = fold_builtin (fndecl, arglist, !want_value);
if (new && new != *expr_p)
{
if (TREE_CODE (type) == BOOLEAN_TYPE)
return expr;
- /* If this is the predicate of a COND_EXPR, it might not even be a
- truthvalue yet. */
- expr = lang_hooks.truthvalue_conversion (expr);
-
switch (TREE_CODE (expr))
{
case TRUTH_AND_EXPR:
*EXPR_P should be stored. */
static enum gimplify_status
-gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target)
+gimplify_cond_expr (tree *expr_p, tree *pre_p, tree *post_p, tree target,
+ fallback_t fallback)
{
tree expr = *expr_p;
tree tmp, tmp2, type;
enum gimplify_status ret;
type = TREE_TYPE (expr);
- if (!type)
- TREE_TYPE (expr) = void_type_node;
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
- else if (! VOID_TYPE_P (type))
+ if (! VOID_TYPE_P (type))
{
+ tree result;
+
if (target)
{
ret = gimplify_expr (&target, pre_p, post_p,
is_gimple_min_lval, fb_lvalue);
if (ret != GS_ERROR)
ret = GS_OK;
- tmp = target;
+ result = tmp = target;
tmp2 = unshare_expr (target);
}
+ else if ((fallback & fb_lvalue) == 0)
+ {
+ result = tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+ ret = GS_ALL_DONE;
+ }
else
{
- tmp2 = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+ tree type = build_pointer_type (TREE_TYPE (expr));
+
+ if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
+ TREE_OPERAND (expr, 1) =
+ build_fold_addr_expr (TREE_OPERAND (expr, 1));
+
+ 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 = build (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
+ TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
+
+ result = build_fold_indirect_ref (tmp);
ret = GS_ALL_DONE;
}
/* Move the COND_EXPR to the prequeue. */
gimplify_and_add (expr, pre_p);
- *expr_p = tmp;
+ *expr_p = result;
return ret;
}
pre_p);
}
+/* Return true if FDECL is accessing a field that is zero sized. */
+
+static bool
+zero_sized_field_decl (tree fdecl)
+{
+ if (TREE_CODE (fdecl) == FIELD_DECL && DECL_SIZE (fdecl)
+ && integer_zerop (DECL_SIZE (fdecl)))
+ return true;
+ return false;
+}
+
/* A subroutine of gimplify_init_constructor. Generate individual
MODIFY_EXPRs for a CONSTRUCTOR. OBJECT is the LHS against which the
assignments should happen. LIST is the CONSTRUCTOR_ELTS of the
so we don't have to figure out what's missing ourselves. */
gcc_assert (purpose);
+ if (zero_sized_field_decl (purpose))
+ continue;
+
/* If we have a RANGE_EXPR, we have to build a loop to assign the
whole range. */
if (TREE_CODE (purpose) == RANGE_EXPR)
break;
}
+ /* If there are "lots" of initialized elements, even discounting
+ those that are not address constants (and thus *must* be
+ computed at runtime), then partition the constructor into
+ constant and non-constant parts. Block copy the constant
+ parts in, then generate code for the non-constant parts. */
+ /* TODO. There's code in cp/typeck.c to do this. */
+
+ num_type_elements = count_type_elements (TREE_TYPE (ctor));
+
+ /* If there are "lots" of zeros, then block clear the object first. */
+ if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
+ && num_nonzero_elements < num_type_elements/4)
+ cleared = true;
+
+ /* ??? This bit ought not be needed. For any element not present
+ in the initializer, we should simply set them to zero. Except
+ we'd need to *find* the elements that are not present, and that
+ requires trickery to avoid quadratic compile-time behavior in
+ large cases or excessive memory use in small cases. */
+ else if (num_ctor_elements < num_type_elements)
+ cleared = true;
+
/* If there are "lots" of initialized elements, and all of them
are valid address constants, then the entire initializer can
- be dropped to memory, and then memcpy'd out. */
- if (num_nonconstant_elements == 0)
+ be dropped to memory, and then memcpy'd out. Don't do this
+ for sparse arrays, though, as it's more efficient to follow
+ the standard CONSTRUCTOR behavior of memset followed by
+ individual element initialization. */
+ if (num_nonconstant_elements == 0 && !cleared)
{
HOST_WIDE_INT size = int_size_in_bytes (type);
unsigned int align;
}
}
- /* If there are "lots" of initialized elements, even discounting
- those that are not address constants (and thus *must* be
- computed at runtime), then partition the constructor into
- constant and non-constant parts. Block copy the constant
- parts in, then generate code for the non-constant parts. */
- /* TODO. There's code in cp/typeck.c to do this. */
-
- num_type_elements = count_type_elements (TREE_TYPE (ctor));
-
- /* If there are "lots" of zeros, then block clear the object first. */
- if (num_type_elements - num_nonzero_elements > CLEAR_RATIO
- && num_nonzero_elements < num_type_elements/4)
- cleared = true;
-
- /* ??? This bit ought not be needed. For any element not present
- in the initializer, we should simply set them to zero. Except
- we'd need to *find* the elements that are not present, and that
- requires trickery to avoid quadratic compile-time behavior in
- large cases or excessive memory use in small cases. */
- else if (num_ctor_elements < num_type_elements)
- cleared = true;
-
if (cleared)
{
/* Zap the CONSTRUCTOR element list, which simplifies this case.
return GS_ALL_DONE;
}
+/* Given a pointer value OP0, return a simplified version of an
+ indirection through OP0, or NULL_TREE if no simplification is
+ possible. This may only be applied to a rhs of an expression.
+ Note that the resulting type may be different from the type pointed
+ to in the sense that it is still compatible from the langhooks
+ point of view. */
+
+static tree
+fold_indirect_ref_rhs (tree t)
+{
+ tree type = TREE_TYPE (TREE_TYPE (t));
+ tree sub = t;
+ tree subtype;
+
+ STRIP_NOPS (sub);
+ subtype = TREE_TYPE (sub);
+ if (!POINTER_TYPE_P (subtype))
+ return NULL_TREE;
+
+ if (TREE_CODE (sub) == ADDR_EXPR)
+ {
+ tree op = TREE_OPERAND (sub, 0);
+ tree optype = TREE_TYPE (op);
+ /* *&p => p */
+ if (lang_hooks.types_compatible_p (type, optype))
+ return op;
+ /* *(foo *)&fooarray => fooarray[0] */
+ else if (TREE_CODE (optype) == ARRAY_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (optype)))
+ {
+ tree type_domain = TYPE_DOMAIN (optype);
+ tree min_val = size_zero_node;
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
+ }
+ }
+
+ /* *(foo *)fooarrptr => (*fooarrptr)[0] */
+ if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+ && lang_hooks.types_compatible_p (type, TREE_TYPE (TREE_TYPE (subtype))))
+ {
+ tree type_domain;
+ tree min_val = size_zero_node;
+ sub = fold_indirect_ref_rhs (sub);
+ if (! sub)
+ sub = build1 (INDIRECT_REF, TREE_TYPE (subtype), sub);
+ type_domain = TYPE_DOMAIN (TREE_TYPE (sub));
+ if (type_domain && TYPE_MIN_VALUE (type_domain))
+ min_val = TYPE_MIN_VALUE (type_domain);
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
+ }
+
+ return NULL_TREE;
+}
+
/* Subroutine of gimplify_modify_expr to do simplifications of MODIFY_EXPRs
based on the code of the RHS. We loop for as long as something changes. */
This kind of code arises in C++ when an object is bound
to a const reference, and if "x" is a TARGET_EXPR we want
to take advantage of the optimization below. */
- tree t = fold_indirect_ref (*from_p);
- if (t != *from_p)
+ tree t = fold_indirect_ref_rhs (TREE_OPERAND (*from_p, 0));
+ if (t)
{
*from_p = t;
ret = GS_OK;
??? 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
+ an initializer. If I'm wrong, we'll die 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 (!is_gimple_reg_type (TREE_TYPE (*from_p)))
{
*expr_p = *from_p;
- return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p);
+ return gimplify_cond_expr (expr_p, pre_p, post_p, *to_p,
+ fb_rvalue);
}
else
ret = GS_UNHANDLED;
break;
+ case CALL_EXPR:
+ /* For calls that return in memory, give *to_p as the CALL_EXPR's
+ return slot so that we don't generate a temporary. */
+ if (!CALL_EXPR_RETURN_SLOT_OPT (*from_p)
+ && aggregate_value_p (*from_p, *from_p))
+ {
+ bool use_target;
+
+ if (TREE_CODE (*to_p) == RESULT_DECL
+ && needs_to_live_in_memory (*to_p))
+ /* It's always OK to use the return slot directly. */
+ use_target = true;
+ else if (!is_gimple_non_addressable (*to_p))
+ /* Don't use the original target if it's already addressable;
+ if its address escapes, and the called function uses the
+ NRV optimization, a conforming program could see *to_p
+ change before the called function returns; see c++/19317.
+ When optimizing, the return_slot pass marks more functions
+ as safe after we have escape info. */
+ use_target = false;
+ else if (DECL_GIMPLE_FORMAL_TEMP_P (*to_p))
+ /* Don't use the original target if it's a formal temp; we
+ don't want to take their addresses. */
+ use_target = false;
+ else if (is_gimple_reg_type (TREE_TYPE (*to_p)))
+ /* Also don't force regs into memory. */
+ use_target = false;
+ else
+ use_target = true;
+
+ if (use_target)
+ {
+ CALL_EXPR_RETURN_SLOT_OPT (*from_p) = 1;
+ lang_hooks.mark_addressable (*to_p);
+ }
+ }
+
+ ret = GS_UNHANDLED;
+ break;
+
default:
ret = GS_UNHANDLED;
break;
return ret;
}
+/* 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_COMPLEX_GIMPLE_REG_P set. */
+
+static enum gimplify_status
+gimplify_modify_expr_complex_part (tree *expr_p, tree *pre_p, bool want_value)
+{
+ enum tree_code code, ocode;
+ tree lhs, rhs, new_rhs, other, realpart, imagpart;
+
+ lhs = TREE_OPERAND (*expr_p, 0);
+ rhs = TREE_OPERAND (*expr_p, 1);
+ code = TREE_CODE (lhs);
+ lhs = TREE_OPERAND (lhs, 0);
+
+ ocode = code == REALPART_EXPR ? IMAGPART_EXPR : REALPART_EXPR;
+ other = build1 (ocode, TREE_TYPE (rhs), lhs);
+ other = get_formal_tmp_var (other, pre_p);
+
+ realpart = code == REALPART_EXPR ? rhs : other;
+ imagpart = code == REALPART_EXPR ? other : rhs;
+
+ if (TREE_CONSTANT (realpart) && TREE_CONSTANT (imagpart))
+ new_rhs = build_complex (TREE_TYPE (lhs), realpart, imagpart);
+ else
+ new_rhs = build2 (COMPLEX_EXPR, TREE_TYPE (lhs), realpart, imagpart);
+
+ TREE_OPERAND (*expr_p, 0) = lhs;
+ TREE_OPERAND (*expr_p, 1) = new_rhs;
+
+ if (want_value)
+ {
+ append_to_statement_list (*expr_p, pre_p);
+ *expr_p = rhs;
+ }
+
+ return GS_ALL_DONE;
+}
+
/* Gimplify the MODIFY_EXPR node pointed by EXPR_P.
modify_expr
}
}
+ /* Transform partial stores to non-addressable complex variables into
+ total stores. This allows us to use real instead of virtual operands
+ for these variables, which improves optimization. */
+ if ((TREE_CODE (*to_p) == REALPART_EXPR
+ || TREE_CODE (*to_p) == IMAGPART_EXPR)
+ && is_gimple_reg (TREE_OPERAND (*to_p, 0)))
+ return gimplify_modify_expr_complex_part (expr_p, pre_p, want_value);
+
if (gimplify_ctxp->into_ssa && is_gimple_reg (*to_p))
{
/* If we've somehow already got an SSA_NAME on the LHS, then
- we're probably modifying it twice. Not good. */
+ we're probably modified it twice. Not good. */
gcc_assert (TREE_CODE (*to_p) != SSA_NAME);
*to_p = make_ssa_name (*to_p, *expr_p);
}
builtins like __builtin_va_end). */
/* Caution: the silent array decomposition semantics we allow for
ADDR_EXPR means we can't always discard the pair. */
+ /* Gimplification of the ADDR_EXPR operand may drop
+ cv-qualification conversions, so make sure we add them if
+ needed. */
{
tree op00 = TREE_OPERAND (op0, 0);
tree t_expr = TREE_TYPE (expr);
{
#ifdef ENABLE_CHECKING
tree t_op0 = TREE_TYPE (op0);
- gcc_assert (TREE_CODE (t_op0) == ARRAY_TYPE
- && POINTER_TYPE_P (t_expr)
- && cpt_same_type (TREE_TYPE (t_op0),
+ gcc_assert (POINTER_TYPE_P (t_expr)
+ && cpt_same_type (TREE_CODE (t_op0) == ARRAY_TYPE
+ ? TREE_TYPE (t_op0) : t_op0,
TREE_TYPE (t_expr))
&& POINTER_TYPE_P (t_op00)
&& cpt_same_type (t_op0, TREE_TYPE (t_op00)));
break;
case COND_EXPR:
- ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE);
+ ret = gimplify_cond_expr (expr_p, pre_p, post_p, NULL_TREE,
+ fallback);
+ /* C99 code may assign to an array in a structure value of a
+ conditional expression, and this has undefined behavior
+ only on execution, so create a temporary if an lvalue is
+ required. */
+ if (fallback == fb_lvalue)
+ {
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ lang_hooks.mark_addressable (*expr_p);
+ }
break;
case CALL_EXPR:
ret = gimplify_call_expr (expr_p, pre_p, fallback != fb_none);
+ /* C99 code may assign to an array in a structure returned
+ from a function, and this has undefined behavior only on
+ execution, so create a temporary if an lvalue is
+ required. */
+ if (fallback == fb_lvalue)
+ {
+ *expr_p = get_initialized_tmp_var (*expr_p, pre_p, post_p);
+ lang_hooks.mark_addressable (*expr_p);
+ }
break;
case TREE_LIST:
/* If this is a local variable sized decl, it must be accessed
indirectly. Perform that substitution. */
- if (DECL_VALUE_EXPR (tmp))
+ if (DECL_HAS_VALUE_EXPR_P (tmp))
{
*expr_p = unshare_expr (DECL_VALUE_EXPR (tmp));
ret = GS_OK;
#endif
gcc_assert (fallback & fb_mayfail);
/* If this is an asm statement, and the user asked for the
- impossible, don't abort. Fail and let gimplify_asm_expr
+ impossible, don't die. Fail and let gimplify_asm_expr
issue an error. */
ret = GS_ERROR;
goto out;
{
tree field, t;
- /* Note that we do not check for TYPE_SIZES_GIMPLIFIED already set because
- that's not supposed to happen on types where gimplification does anything.
- We should assert that it isn't set, but we can indeed be called multiple
- times on pointers. Unfortunately, this includes fat pointers which we
- can't easily test for. We could pass TYPE down to gimplify_one_sizepos
- and test there, but it doesn't seem worth it. */
+ if (type == NULL)
+ return;
/* We first do the main variant, then copy into any other variants. */
type = TYPE_MAIN_VARIANT (type);
+ /* Avoid infinite recursion. */
+ if (TYPE_SIZES_GIMPLIFIED (type)
+ || type == error_mark_node)
+ return;
+
+ TYPE_SIZES_GIMPLIFIED (type) = 1;
+
switch (TREE_CODE (type))
{
- case ERROR_MARK:
- return;
-
case INTEGER_TYPE:
case ENUMERAL_TYPE:
case BOOLEAN_TYPE:
{
TYPE_MIN_VALUE (t) = TYPE_MIN_VALUE (type);
TYPE_MAX_VALUE (t) = TYPE_MAX_VALUE (type);
- TYPE_SIZES_GIMPLIFIED (t) = 1;
}
break;
case ARRAY_TYPE:
/* These types may not have declarations, so handle them here. */
- if (!TYPE_SIZES_GIMPLIFIED (TREE_TYPE (type)))
- gimplify_type_sizes (TREE_TYPE (type), list_p);
-
- if (!TYPE_SIZES_GIMPLIFIED (TYPE_DOMAIN (type)))
- gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
+ gimplify_type_sizes (TREE_TYPE (type), list_p);
+ gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
break;
case RECORD_TYPE:
case QUAL_UNION_TYPE:
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
- gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
+ {
+ gimplify_one_sizepos (&DECL_FIELD_OFFSET (field), list_p);
+ gimplify_type_sizes (TREE_TYPE (field), list_p);
+ }
+ break;
+
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ gimplify_type_sizes (TREE_TYPE (type), list_p);
break;
default:
TYPE_SIZE_UNIT (t) = TYPE_SIZE_UNIT (type);
TYPE_SIZES_GIMPLIFIED (t) = 1;
}
-
- TYPE_SIZES_GIMPLIFIED (type) = 1;
}
/* A subroutine of gimplify_type_sizes to make sure that *EXPR_P,
{
/* We don't do anything if the value isn't there, is constant, or contains
A PLACEHOLDER_EXPR. We also don't want to do anything if it's already
- a VAR_DECL. If it's a VAR_DECL from another function, the gimplfier
+ a VAR_DECL. If it's a VAR_DECL from another function, the gimplifier
will want to replace it with a new variable, but that will cause problems
if this type is from outside the function. It's OK to have that here. */
if (*expr_p == NULL_TREE || TREE_CONSTANT (*expr_p)
void
gimplify_function_tree (tree fndecl)
{
- tree oldfn;
+ tree oldfn, parm, ret;
oldfn = current_function_decl;
current_function_decl = fndecl;
if (cfun == NULL)
allocate_struct_function (fndecl);
+ for (parm = DECL_ARGUMENTS (fndecl); parm ; parm = TREE_CHAIN (parm))
+ {
+ /* Preliminarily mark non-addressed complex variables as eligible
+ for promotion to gimple registers. We'll transform their uses
+ as we find them. */
+ if (TREE_CODE (TREE_TYPE (parm)) == COMPLEX_TYPE
+ && !TREE_THIS_VOLATILE (parm)
+ && !needs_to_live_in_memory (parm))
+ DECL_COMPLEX_GIMPLE_REG_P (parm) = 1;
+ }
+
+ ret = DECL_RESULT (fndecl);
+ if (TREE_CODE (TREE_TYPE (ret)) == COMPLEX_TYPE
+ && !needs_to_live_in_memory (ret))
+ DECL_COMPLEX_GIMPLE_REG_P (ret) = 1;
+
gimplify_body (&DECL_SAVED_TREE (fndecl), fndecl, true);
/* If we're instrumenting function entry/exit, then prepend the call to
gimple_test_f = simple ? is_gimple_val : is_gimple_reg_rhs;
push_gimplify_context ();
- gimplify_ctxp->into_ssa = true;
+ gimplify_ctxp->into_ssa = in_ssa_p;
if (var)
expr = build (MODIFY_EXPR, TREE_TYPE (var), var, expr);
gimple_test_f, fb_rvalue);
gcc_assert (ret != GS_ERROR);
- for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
- add_referenced_tmp_var (t);
+ if (referenced_vars)
+ {
+ for (t = gimplify_ctxp->temps; t ; t = TREE_CHAIN (t))
+ add_referenced_tmp_var (t);
+ }
pop_gimplify_context (NULL);
return expr;
}
+/* Invokes force_gimple_operand for EXPR with parameters SIMPLE_P and VAR. If
+ some statements are produced, emits them before BSI. */
+
+tree
+force_gimple_operand_bsi (block_stmt_iterator *bsi, tree expr,
+ bool simple_p, tree var)
+{
+ tree stmts;
+
+ expr = force_gimple_operand (expr, &stmts, simple_p, var);
+ if (stmts)
+ bsi_insert_before (bsi, stmts, BSI_SAME_STMT);
+
+ return expr;
+}
+
#include "gt-gimplify.h"