/* 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, 2008, 2009
+ Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
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>.
#include "tm.h"
#include "tree.h"
#include "rtl.h"
-#include "varray.h"
#include "gimple.h"
#include "tree-iterator.h"
#include "tree-inline.h"
return tmp_var;
}
+/* Create a new temporary variable declaration of type TYPE by calling
+ create_tmp_var and if TYPE is a vector or a complex number, mark the new
+ temporary as gimple register. */
+
+tree
+create_tmp_reg (tree type, const char *prefix)
+{
+ tree tmp;
+
+ tmp = create_tmp_var (type, prefix);
+ if (TREE_CODE (type) == COMPLEX_TYPE
+ || TREE_CODE (type) == VECTOR_TYPE)
+ DECL_GIMPLE_REG_P (tmp) = 1;
+
+ return tmp;
+}
+
/* Create a temporary with a name derived from VAL. Subroutine of
lookup_tmp_var; nobody else should call this function. */
result = gimplify_ctxp->return_temp;
else
{
- result = create_tmp_var (TREE_TYPE (result_decl), NULL);
- if (TREE_CODE (TREE_TYPE (result)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (result)) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (result) = 1;
+ result = create_tmp_reg (TREE_TYPE (result_decl), NULL);
/* ??? With complex control flow (usually involving abnormal edges),
we can wind up warning about an uninitialized value for this. Due
tree type = TREE_TYPE (expr);
location_t loc = EXPR_LOCATION (expr);
+ if (TREE_CODE (expr) == NE_EXPR
+ && TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR
+ && integer_zerop (TREE_OPERAND (expr, 1)))
+ {
+ tree call = TREE_OPERAND (expr, 0);
+ tree fn = get_callee_fndecl (call);
+
+ /* For __builtin_expect ((long) (x), y) recurse into x as well
+ if x is truth_value_p. */
+ if (fn
+ && DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL
+ && DECL_FUNCTION_CODE (fn) == BUILT_IN_EXPECT
+ && call_expr_nargs (call) == 2)
+ {
+ tree arg = CALL_EXPR_ARG (call, 0);
+ if (arg)
+ {
+ if (TREE_CODE (arg) == NOP_EXPR
+ && TREE_TYPE (arg) == TREE_TYPE (call))
+ arg = TREE_OPERAND (arg, 0);
+ if (truth_value_p (TREE_CODE (arg)))
+ {
+ arg = gimple_boolify (arg);
+ CALL_EXPR_ARG (call, 0)
+ = fold_convert_loc (loc, TREE_TYPE (call), arg);
+ }
+ }
+ }
+ }
+
if (TREE_CODE (type) == BOOLEAN_TYPE)
return expr;
gimplify_cond_expr (tree *expr_p, gimple_seq *pre_p, fallback_t fallback)
{
tree expr = *expr_p;
- tree tmp, type, arm1, arm2;
+ tree type = TREE_TYPE (expr);
+ location_t loc = EXPR_LOCATION (expr);
+ tree tmp, arm1, arm2;
enum gimplify_status ret;
tree label_true, label_false, label_cont;
bool have_then_clause_p, have_else_clause_p;
gimple gimple_cond;
enum tree_code pred_code;
gimple_seq seq = NULL;
- location_t loc = EXPR_LOCATION (*expr_p);
-
- type = TREE_TYPE (expr);
/* If this COND_EXPR has a value, copy the values into a temporary within
the arms. */
- if (! VOID_TYPE_P (type))
+ if (!VOID_TYPE_P (type))
{
+ tree then_ = TREE_OPERAND (expr, 1), else_ = TREE_OPERAND (expr, 2);
tree result;
- /* If an rvalue is ok or we do not require an lvalue, avoid creating
- an addressable temporary. */
- if (((fallback & fb_rvalue)
- || !(fallback & fb_lvalue))
+ /* If either an rvalue is ok or we do not require an lvalue, create the
+ temporary. But we cannot do that if the type is addressable. */
+ 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)))
+ && !TREE_SIDE_EFFECTS (then_)
+ && !generic_expr_could_trap_p (then_)
+ && !TREE_SIDE_EFFECTS (else_)
+ && !generic_expr_could_trap_p (else_))
return gimplify_pure_cond_expr (expr_p, pre_p);
- result = tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
- ret = GS_ALL_DONE;
+ tmp = create_tmp_var (type, "iftmp");
+ result = tmp;
}
+
+ /* Otherwise, only create and copy references to the values. */
else
{
- tree type = build_pointer_type (TREE_TYPE (expr));
+ type = build_pointer_type (type);
- if (TREE_TYPE (TREE_OPERAND (expr, 1)) != void_type_node)
- TREE_OPERAND (expr, 1) =
- build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 1));
+ if (!VOID_TYPE_P (TREE_TYPE (then_)))
+ then_ = build_fold_addr_expr_loc (loc, then_);
- if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
- TREE_OPERAND (expr, 2) =
- build_fold_addr_expr_loc (loc, TREE_OPERAND (expr, 2));
+ if (!VOID_TYPE_P (TREE_TYPE (else_)))
+ else_ = build_fold_addr_expr_loc (loc, else_);
+
+ expr
+ = build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), then_, else_);
tmp = create_tmp_var (type, "iftmp");
-
- expr = build3 (COND_EXPR, void_type_node, TREE_OPERAND (expr, 0),
- TREE_OPERAND (expr, 1), TREE_OPERAND (expr, 2));
-
result = build_fold_indirect_ref_loc (loc, tmp);
}
- /* 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)
- = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 1));
+ /* Build the new then clause, `tmp = then_;'. But don't build the
+ assignment if the value is void; in C++ it can be if it's a throw. */
+ if (!VOID_TYPE_P (TREE_TYPE (then_)))
+ TREE_OPERAND (expr, 1) = build2 (MODIFY_EXPR, type, tmp, then_);
- /* Build the else clause, 't1 = b;'. */
- if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
- TREE_OPERAND (expr, 2)
- = build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp, TREE_OPERAND (expr, 2));
+ /* Similarly, build the new else clause, `tmp = else_;'. */
+ if (!VOID_TYPE_P (TREE_TYPE (else_)))
+ TREE_OPERAND (expr, 2) = build2 (MODIFY_EXPR, type, tmp, else_);
TREE_TYPE (expr) = void_type_node;
recalculate_side_effects (expr);
&& num_nonzero_elements > 1
&& !can_move_by_pieces (size, align))
{
- tree new_tree;
-
if (notify_temp_creation)
return GS_ERROR;
- new_tree = create_tmp_var_raw (type, "C");
-
- gimple_add_tmp_var (new_tree);
- TREE_STATIC (new_tree) = 1;
- TREE_READONLY (new_tree) = 1;
- DECL_INITIAL (new_tree) = ctor;
- if (align > DECL_ALIGN (new_tree))
- {
- DECL_ALIGN (new_tree) = align;
- DECL_USER_ALIGN (new_tree) = 1;
- }
- walk_tree (&DECL_INITIAL (new_tree), force_labels_r, NULL, NULL);
-
- TREE_OPERAND (*expr_p, 1) = new_tree;
+ walk_tree (&ctor, force_labels_r, NULL, NULL);
+ TREE_OPERAND (*expr_p, 1) = tree_output_constant_def (ctor);
/* This is no longer an assignment of a CONSTRUCTOR, but
we still may have processing to do on the LHS. So
}
}
+ /* If the target is volatile and we have non-zero elements
+ initialize the target from a temporary. */
+ if (TREE_THIS_VOLATILE (object)
+ && !TREE_ADDRESSABLE (type)
+ && num_nonzero_elements > 0)
+ {
+ tree temp = create_tmp_var (TYPE_MAIN_VARIANT (type), NULL);
+ TREE_OPERAND (*expr_p, 0) = temp;
+ *expr_p = build2 (COMPOUND_EXPR, TREE_TYPE (*expr_p),
+ *expr_p,
+ build2 (MODIFY_EXPR, void_type_node,
+ object, temp));
+ return GS_OK;
+ }
+
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. */
- if (num_nonzero_elements > 0)
+ /* If there are nonzero elements and if needed, 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. */
+ if (num_nonzero_elements > 0 && TREE_CODE (*expr_p) != INIT_EXPR)
{
preeval_data.lhs_base_decl = get_base_address (object);
if (!DECL_P (preeval_data.lhs_base_decl))
tree sub = t;
tree subtype;
- STRIP_USELESS_TYPE_CONVERSION (sub);
+ STRIP_NOPS (sub);
subtype = TREE_TYPE (sub);
if (!POINTER_TYPE_P (subtype))
return NULL_TREE;
/* *(foo *)&fooarray => fooarray[0] */
if (TREE_CODE (optype) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (optype))) == INTEGER_CST
&& useless_type_conversion_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);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, op, min_val, NULL_TREE, NULL_TREE);
}
+ /* *(foo *)&complexfoo => __real__ complexfoo */
+ else if (TREE_CODE (optype) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ return fold_build1 (REALPART_EXPR, type, op);
+ /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */
+ else if (TREE_CODE (optype) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (optype)))
+ {
+ tree part_width = TYPE_SIZE (type);
+ tree index = bitsize_int (0);
+ return fold_build3 (BIT_FIELD_REF, type, op, part_width, index);
+ }
+ }
+
+ /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+ {
+ tree op00 = TREE_OPERAND (sub, 0);
+ tree op01 = TREE_OPERAND (sub, 1);
+ tree op00type;
+
+ STRIP_NOPS (op00);
+ op00type = TREE_TYPE (op00);
+ if (TREE_CODE (op00) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (op00type)) == VECTOR_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
+ {
+ HOST_WIDE_INT offset = tree_low_cst (op01, 0);
+ tree part_width = TYPE_SIZE (type);
+ unsigned HOST_WIDE_INT part_widthi
+ = tree_low_cst (part_width, 0) / BITS_PER_UNIT;
+ unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT;
+ tree index = bitsize_int (indexi);
+ if (offset / part_widthi
+ <= TYPE_VECTOR_SUBPARTS (TREE_TYPE (op00type)))
+ return fold_build3 (BIT_FIELD_REF, type, TREE_OPERAND (op00, 0),
+ part_width, index);
+ }
+ }
+
+ /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */
+ if (TREE_CODE (sub) == POINTER_PLUS_EXPR
+ && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST)
+ {
+ tree op00 = TREE_OPERAND (sub, 0);
+ tree op01 = TREE_OPERAND (sub, 1);
+ tree op00type;
+
+ STRIP_NOPS (op00);
+ op00type = TREE_TYPE (op00);
+ if (TREE_CODE (op00) == ADDR_EXPR
+ && TREE_CODE (TREE_TYPE (op00type)) == COMPLEX_TYPE
+ && useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (op00type))))
+ {
+ tree size = TYPE_SIZE_UNIT (type);
+ if (tree_int_cst_equal (size, op01))
+ return fold_build1 (IMAGPART_EXPR, type, TREE_OPERAND (op00, 0));
+ }
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE
+ && TREE_CODE (TYPE_SIZE (TREE_TYPE (TREE_TYPE (subtype)))) == INTEGER_CST
&& useless_type_conversion_p (type, TREE_TYPE (TREE_TYPE (subtype))))
{
tree type_domain;
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);
+ if (TREE_CODE (min_val) == INTEGER_CST)
+ return build4 (ARRAY_REF, type, sub, min_val, NULL_TREE, NULL_TREE);
}
return NULL_TREE;
ret = GS_UNHANDLED;
break;
+ case WITH_SIZE_EXPR:
+ /* Likewise for calls that return an aggregate of non-constant size,
+ since we would not be able to generate a temporary at all. */
+ if (TREE_CODE (TREE_OPERAND (*from_p, 0)) == CALL_EXPR)
+ {
+ *from_p = TREE_OPERAND (*from_p, 0);
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+
/* If we're initializing from a container, push the initialization
inside it. */
case CLEANUP_POINT_EXPR:
tree type = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (addr)));
tree tmp_load;
- tmp_load = create_tmp_var (type, NULL);
- if (TREE_CODE (type) == COMPLEX_TYPE || TREE_CODE (type) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (tmp_load) = 1;
+ tmp_load = create_tmp_reg (type, NULL);
if (goa_stabilize_expr (&rhs, pre_p, addr, tmp_load) < 0)
return GS_ERROR;
/* These types may not have declarations, so handle them here. */
gimplify_type_sizes (TREE_TYPE (type), list_p);
gimplify_type_sizes (TYPE_DOMAIN (type), list_p);
- /* When not optimizing, ensure VLA bounds aren't removed. */
- if (!optimize
- && TYPE_DOMAIN (type)
+ /* Ensure VLA bounds aren't removed, for -O0 they should be variables
+ with assigned stack slots, for -O1+ -g they should be tracked
+ by VTA. */
+ if (TYPE_DOMAIN (type)
&& INTEGRAL_TYPE_P (TYPE_DOMAIN (type)))
{
t = TYPE_MIN_VALUE (TYPE_DOMAIN (type));
*body_p = NULL_TREE;
/* If we had callee-copies statements, insert them at the beginning
- of the function. */
+ of the function and clear DECL_VALUE_EXPR_P on the parameters. */
if (!gimple_seq_empty_p (parm_stmts))
{
+ tree parm;
+
gimplify_seq_add_seq (&parm_stmts, gimple_bind_body (outer_bind));
gimple_bind_set_body (outer_bind, parm_stmts);
+
+ for (parm = DECL_ARGUMENTS (current_function_decl);
+ parm; parm = TREE_CHAIN (parm))
+ if (DECL_HAS_VALUE_EXPR_P (parm))
+ {
+ DECL_HAS_VALUE_EXPR_P (parm) = 0;
+ DECL_IGNORED_P (parm) = 0;
+ }
}
if (nonlocal_vlas)
}
if (need_temp)
{
- tree temp = create_tmp_var (TREE_TYPE (lhs), NULL);
+ tree temp = create_tmp_reg (TREE_TYPE (lhs), NULL);
- if (TREE_CODE (TREE_TYPE (lhs)) == COMPLEX_TYPE
- || TREE_CODE (TREE_TYPE (lhs)) == VECTOR_TYPE)
- DECL_GIMPLE_REG_P (temp) = 1;
if (TREE_CODE (orig_lhs) == SSA_NAME)
orig_lhs = SSA_NAME_VAR (orig_lhs);