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"
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;
tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
}
-/* Add T to the end of the list container pointed by LIST_P.
+/* Add T to the end of the list container pointed to by LIST_P.
If T is an expression with no effects, it is ignored. */
void
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))
/* 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;
+ {
+ if (TREE_CODE (t) == VAR_DECL)
+ 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;
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;
}
}
/* Gimplify the COMPONENT_REF, ARRAY_REF, REALPART_EXPR or IMAGPART_EXPR
- node pointed by EXPR_P.
+ node pointed to by EXPR_P.
compound_lval
: min_lval '[' val ']'
return ret;
}
-/* Gimplify the self modifying expression pointed by EXPR_P (++, --, +=, -=).
+/* Gimplify the self modifying expression pointed to by EXPR_P
+ (++, --, +=, -=).
PRE_P points to the list where side effects that must happen before
*EXPR_P should be stored.
return gimplify_expr (expr_p, pre_p, NULL, test, fb);
}
-/* Gimplify the CALL_EXPR node pointed by EXPR_P. PRE_P points to the
+/* Gimplify the CALL_EXPR node pointed to by EXPR_P. PRE_P points to the
list where side effects that must happen before *EXPR_P should be stored.
WANT_VALUE is true if the result of the call is desired. */
}
}
-/* Convert the conditional expression pointed by EXPR_P '(p) ? a : b;'
+/* Convert the conditional expression pointed to by EXPR_P '(p) ? a : b;'
into
if (p) if (p)
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;
/* Recurse for nested constructors. */
if (TREE_CODE (*expr_p) == CONSTRUCTOR)
{
- tree list;
- for (list = CONSTRUCTOR_ELTS (*expr_p); list ; list = TREE_CHAIN (list))
- gimplify_init_ctor_preeval (&TREE_VALUE (list), pre_p, post_p, data);
+ unsigned HOST_WIDE_INT ix;
+ constructor_elt *ce;
+ VEC(constructor_elt,gc) *v = CONSTRUCTOR_ELTS (*expr_p);
+
+ for (ix = 0; VEC_iterate (constructor_elt, v, ix, ce); ix++)
+ gimplify_init_ctor_preeval (&ce->value, pre_p, post_p, data);
return;
}
Note that we never have to deal with SAVE_EXPRs here, because this has
already been taken care of for us, in gimplify_init_ctor_preeval(). */
-static void gimplify_init_ctor_eval (tree, tree, tree *, bool);
+static void gimplify_init_ctor_eval (tree, VEC(constructor_elt,gc) *,
+ tree *, bool);
static void
gimplify_init_ctor_eval_range (tree object, tree lower, tree upper,
return false;
}
+/* Return true if TYPE is zero sized. */
+
+static bool
+zero_sized_type (tree type)
+{
+ if (AGGREGATE_TYPE_P (type) && TYPE_SIZE (type)
+ && integer_zerop (TYPE_SIZE (type)))
+ 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
+ assignments should happen. ELTS is the CONSTRUCTOR_ELTS of the
CONSTRUCTOR. CLEARED is true if the entire LHS object has been
zeroed first. */
static void
-gimplify_init_ctor_eval (tree object, tree list, tree *pre_p, bool cleared)
+gimplify_init_ctor_eval (tree object, VEC(constructor_elt,gc) *elts,
+ tree *pre_p, bool cleared)
{
tree array_elt_type = NULL;
+ unsigned HOST_WIDE_INT ix;
+ tree purpose, value;
if (TREE_CODE (TREE_TYPE (object)) == ARRAY_TYPE)
array_elt_type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
- for (; list; list = TREE_CHAIN (list))
+ FOR_EACH_CONSTRUCTOR_ELT (elts, ix, purpose, value)
{
- tree purpose, value, cref, init;
-
- purpose = TREE_PURPOSE (list);
- value = TREE_VALUE (list);
+ tree cref, init;
/* NULL values are created above for gimplification errors. */
if (value == NULL)
so we don't have to figure out what's missing ourselves. */
gcc_assert (purpose);
- if (zero_sized_field_decl (purpose))
+ /* Skip zero-sized fields, unless value has side-effects. This can
+ happen with calls to functions returning a zero-sized type, which
+ we shouldn't discard. As a number of downstream passes don't
+ expect sets of zero-sized fields, we rely on the gimplification of
+ the MODIFY_EXPR we make below to drop the assignment statement. */
+ if (! TREE_SIDE_EFFECTS (value) && zero_sized_field_decl (purpose))
continue;
/* If we have a RANGE_EXPR, we have to build a loop to assign the
purpose, NULL_TREE, NULL_TREE);
}
else
- cref = build (COMPONENT_REF, TREE_TYPE (purpose),
- unshare_expr (object), purpose, NULL_TREE);
+ {
+ gcc_assert (TREE_CODE (purpose) == FIELD_DECL);
+ cref = build (COMPONENT_REF, TREE_TYPE (purpose),
+ unshare_expr (object), purpose, NULL_TREE);
+ }
- if (TREE_CODE (value) == CONSTRUCTOR)
+ if (TREE_CODE (value) == CONSTRUCTOR
+ && TREE_CODE (TREE_TYPE (value)) != VECTOR_TYPE)
gimplify_init_ctor_eval (cref, CONSTRUCTOR_ELTS (value),
pre_p, cleared);
else
tree ctor = TREE_OPERAND (*expr_p, 1);
tree type = TREE_TYPE (ctor);
enum gimplify_status ret;
- tree elt_list;
+ VEC(constructor_elt,gc) *elts;
if (TREE_CODE (ctor) != CONSTRUCTOR)
return GS_UNHANDLED;
return ret;
object = TREE_OPERAND (*expr_p, 0);
- elt_list = CONSTRUCTOR_ELTS (ctor);
+ elts = CONSTRUCTOR_ELTS (ctor);
ret = GS_ALL_DONE;
switch (TREE_CODE (type))
/* 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 (VEC_empty (constructor_elt, elts))
break;
categorize_ctor_elements (ctor, &num_nonzero_elements,
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));
+ num_type_elements = count_type_elements (type, true);
+ /* If count_type_elements could not determine number of type elements
+ for a constant-sized object, assume clearing is needed.
+ Don't do this for variable-sized objects, as store_constructor
+ will ignore the clearing of variable-sized objects. */
+ if (num_type_elements < 0 && int_size_in_bytes (type) >= 0)
+ cleared = true;
/* 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)
+ else 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
/* 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. Avoid shared tree structures. */
- CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
+ CONSTRUCTOR_ELTS (ctor) = NULL;
object = unshare_expr (object);
gimplify_stmt (expr_p);
append_to_statement_list (*expr_p, pre_p);
gimplify_init_ctor_preeval (&TREE_OPERAND (*expr_p, 1),
pre_p, post_p, &preeval_data);
- gimplify_init_ctor_eval (object, elt_list, pre_p, cleared);
+ gimplify_init_ctor_eval (object, elts, pre_p, cleared);
}
*expr_p = NULL_TREE;
tree r, i;
/* 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);
- gcc_assert (!TREE_CHAIN (elt_list));
- }
- }
+ gcc_assert (VEC_length (constructor_elt, elts) == 2);
+ r = VEC_index (constructor_elt, elts, 0)->value;
+ i = VEC_index (constructor_elt, elts, 1)->value;
if (r == NULL || i == NULL)
{
tree zero = convert (TREE_TYPE (type), integer_zero_node);
break;
case VECTOR_TYPE:
- /* Go ahead and simplify constant constructors to VECTOR_CST. */
- if (TREE_CONSTANT (ctor))
- {
- tree tem;
+ {
+ unsigned HOST_WIDE_INT ix;
+ constructor_elt *ce;
- /* Even when ctor is constant, it might contain non-*_CST
- elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
- belong into VECTOR_CST nodes. */
- for (tem = elt_list; tem; tem = TREE_CHAIN (tem))
- if (! CONSTANT_CLASS_P (TREE_VALUE (tem)))
- break;
+ /* Go ahead and simplify constant constructors to VECTOR_CST. */
+ if (TREE_CONSTANT (ctor))
+ {
+ bool constant_p = true;
+ tree value;
+
+ /* Even when ctor is constant, it might contain non-*_CST
+ elements (e.g. { 1.0/0.0 - 1.0/0.0, 0.0 }) and those don't
+ belong into VECTOR_CST nodes. */
+ FOR_EACH_CONSTRUCTOR_VALUE (elts, ix, value)
+ if (!CONSTANT_CLASS_P (value))
+ {
+ constant_p = false;
+ break;
+ }
- if (! tem)
- {
- TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
- break;
- }
- }
+ if (constant_p)
+ {
+ TREE_OPERAND (*expr_p, 1) = build_vector_from_ctor (type, elts);
+ break;
+ }
+ }
- /* 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_val, fb_rvalue);
- if (tret == GS_ERROR)
- ret = GS_ERROR;
- }
+ /* Vector types use CONSTRUCTOR all the way through gimple
+ compilation as a general initializer. */
+ for (ix = 0; VEC_iterate (constructor_elt, elts, ix, ce); ix++)
+ {
+ enum gimplify_status tret;
+ tret = gimplify_expr (&ce->value, pre_p, post_p,
+ is_gimple_val, fb_rvalue);
+ if (tret == GS_ERROR)
+ ret = GS_ERROR;
+ }
+ }
break;
default:
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 (TREE_CODE (*to_p) != PARM_DECL
+ && 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;
}
-/* Gimplify the MODIFY_EXPR node pointed by EXPR_P.
+/* 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 to by EXPR_P.
modify_expr
: varname '=' rhs
/* The distinction between MODIFY_EXPR and INIT_EXPR is no longer useful. */
if (TREE_CODE (*expr_p) == INIT_EXPR)
TREE_SET_CODE (*expr_p, MODIFY_EXPR);
+
+ /* For zero sized types only gimplify the left hand side and right hand side
+ as statements and throw away the assignment. */
+ if (zero_sized_type (TREE_TYPE (*from_p)))
+ {
+ gimplify_stmt (from_p);
+ gimplify_stmt (to_p);
+ append_to_statement_list (*from_p, pre_p);
+ append_to_statement_list (*to_p, pre_p);
+ *expr_p = NULL_TREE;
+ return GS_ALL_DONE;
+ }
/* See if any simplifications can be done based on what the RHS is. */
ret = gimplify_modify_expr_rhs (expr_p, from_p, to_p, pre_p, post_p,
}
}
+ /* 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
return ret;
}
-/* Re-write the ADDR_EXPR node pointed by EXPR_P
+/* Re-write the ADDR_EXPR node pointed to by EXPR_P
unary_expr
: ...
}
-/* Gimplifies the expression tree pointed by EXPR_P. Return 0 if
+/* Gimplifies the expression tree pointed to by EXPR_P. Return 0 if
gimplification failed.
PRE_P points to the list where side effects that must happen before
gimplify any element that has side-effects. */
if (fallback == fb_none)
{
- for (tmp = CONSTRUCTOR_ELTS (*expr_p); tmp;
- tmp = TREE_CHAIN (tmp))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (tmp)))
- gimplify_expr (&TREE_VALUE (tmp), pre_p, post_p,
+ unsigned HOST_WIDE_INT ix;
+ constructor_elt *ce;
+ for (ix = 0;
+ VEC_iterate (constructor_elt, CONSTRUCTOR_ELTS (*expr_p),
+ ix, ce);
+ ix++)
+ if (TREE_SIDE_EFFECTS (ce->value))
+ gimplify_expr (&ce->value, pre_p, post_p,
gimple_test_f, fallback);
*expr_p = NULL_TREE;
/* 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;
{
/* Historically, the compiler has treated a bare
reference to a volatile lvalue as forcing a load. */
- tree tmp = create_tmp_var (TREE_TYPE (*expr_p), "vol");
- *expr_p = build (MODIFY_EXPR, TREE_TYPE (tmp), tmp, *expr_p);
+ tree type = TYPE_MAIN_VARIANT (TREE_TYPE (*expr_p));
+ /* Normally, we do want to create a temporary for a
+ TREE_ADDRESSABLE type because such a type should not be
+ copied by bitwise-assignment. However, we make an
+ exception here, as all we are doing here is ensuring that
+ we read the bytes that make up the type. We use
+ create_tmp_var_raw because create_tmp_var will abort when
+ given a TREE_ADDRESSABLE type. */
+ tree tmp = create_tmp_var_raw (type, "vol");
+ gimple_add_tmp_var (tmp);
+ *expr_p = build (MODIFY_EXPR, type, tmp, *expr_p);
}
else
/* We can't do anything useful with a volatile reference to
{
tree field, t;
- if (type == NULL)
+ if (type == NULL || type == error_mark_node)
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)
+ if (TYPE_SIZES_GIMPLIFIED (type))
return;
TYPE_SIZES_GIMPLIFIED (type) = 1;
void
gimplify_one_sizepos (tree *expr_p, tree *stmt_p)
{
+ tree type, expr = *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 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)
- || TREE_CODE (*expr_p) == VAR_DECL
- || CONTAINS_PLACEHOLDER_P (*expr_p))
+ if (expr == NULL_TREE || TREE_CONSTANT (expr)
+ || TREE_CODE (expr) == VAR_DECL
+ || CONTAINS_PLACEHOLDER_P (expr))
return;
- *expr_p = unshare_expr (*expr_p);
+ type = TREE_TYPE (expr);
+ *expr_p = unshare_expr (expr);
+
gimplify_expr (expr_p, stmt_p, NULL, is_gimple_val, fb_rvalue);
+ expr = *expr_p;
+
+ /* Verify that we've an exact type match with the original expression.
+ In particular, we do not wish to drop a "sizetype" in favour of a
+ type of similar dimensions. We don't want to pollute the generic
+ type-stripping code with this knowledge because it doesn't matter
+ for the bulk of GENERIC/GIMPLE. It only matters that TYPE_SIZE_UNIT
+ and friends retain their "sizetype-ness". */
+ if (TREE_TYPE (expr) != type
+ && TREE_CODE (type) == INTEGER_TYPE
+ && TYPE_IS_SIZETYPE (type))
+ {
+ tree tmp;
+
+ *expr_p = create_tmp_var (type, NULL);
+ tmp = build1 (NOP_EXPR, type, expr);
+ tmp = build2 (MODIFY_EXPR, type, *expr_p, expr);
+ if (EXPR_HAS_LOCATION (expr))
+ SET_EXPR_LOCUS (tmp, EXPR_LOCUS (expr));
+ else
+ SET_EXPR_LOCATION (tmp, input_location);
+
+ gimplify_and_add (tmp, stmt_p);
+ }
}
\f
#ifdef ENABLE_CHECKING
}
#endif
-/* Gimplify the body of statements pointed by BODY_P. FNDECL is the
+/* Gimplify the body of statements pointed to by BODY_P. FNDECL is the
function decl containing BODY. */
void
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