+ 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 (target)
+ {
+ tmp = target;
+ ret = GS_OK;
+ }
+ else
+ {
+ tmp = create_tmp_var (TREE_TYPE (expr), "iftmp");
+ ret = GS_ALL_DONE;
+ }
+
+ /* 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)
+ = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 1));
+
+ /* Build the else clause, 't1 = b;'. */
+ if (TREE_TYPE (TREE_OPERAND (expr, 2)) != void_type_node)
+ TREE_OPERAND (expr, 2)
+ = build (MODIFY_EXPR, void_type_node, tmp, TREE_OPERAND (expr, 2));
+
+ TREE_TYPE (expr) = void_type_node;
+ recalculate_side_effects (expr);
+
+ /* Move the COND_EXPR to the prequeue and use the temp in its place. */
+ gimplify_and_add (expr, pre_p);
+ *expr_p = tmp;
+
+ return ret;
+ }
+
+ /* Make sure the condition has BOOLEAN_TYPE. */
+ TREE_OPERAND (expr, 0) = gimple_boolify (TREE_OPERAND (expr, 0));
+
+ /* Break apart && and || conditions. */
+ if (TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ANDIF_EXPR
+ || TREE_CODE (TREE_OPERAND (expr, 0)) == TRUTH_ORIF_EXPR)
+ {
+ expr = shortcut_cond_expr (expr);
+
+ if (expr != *expr_p)
+ {
+ *expr_p = expr;
+
+ /* We can't rely on gimplify_expr to re-gimplify the expanded
+ form properly, as cleanups might cause the target labels to be
+ wrapped in a TRY_FINALLY_EXPR. To prevent that, we need to
+ set up a conditional context. */
+ gimple_push_condition ();
+ gimplify_stmt (expr_p);
+ gimple_pop_condition (pre_p);
+
+ return GS_ALL_DONE;
+ }
+ }
+
+ /* Now do the normal gimplification. */
+ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+ is_gimple_condexpr, fb_rvalue);
+
+ gimple_push_condition ();
+
+ gimplify_to_stmt_list (&TREE_OPERAND (expr, 1));
+ gimplify_to_stmt_list (&TREE_OPERAND (expr, 2));
+ recalculate_side_effects (expr);
+
+ gimple_pop_condition (pre_p);
+
+ if (ret == GS_ERROR)
+ ;
+ else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+ ret = GS_ALL_DONE;
+ else if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 2)))
+ /* Rewrite "if (a); else b" to "if (!a) b" */
+ {
+ TREE_OPERAND (expr, 0) = invert_truthvalue (TREE_OPERAND (expr, 0));
+ ret = gimplify_expr (&TREE_OPERAND (expr, 0), pre_p, NULL,
+ is_gimple_condexpr, fb_rvalue);
+
+ tmp = TREE_OPERAND (expr, 1);
+ TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 2);
+ TREE_OPERAND (expr, 2) = tmp;
+ }
+ else
+ /* Both arms are empty; replace the COND_EXPR with its predicate. */
+ expr = TREE_OPERAND (expr, 0);
+
+ *expr_p = expr;
+ return ret;
+}
+
+/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
+ a call to __builtin_memcpy. */
+
+static enum gimplify_status
+gimplify_modify_expr_to_memcpy (tree *expr_p, bool want_value)
+{
+ tree args, t, to, to_ptr, from;
+
+ to = TREE_OPERAND (*expr_p, 0);
+ from = TREE_OPERAND (*expr_p, 1);
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (from));
+ t = unshare_expr (t);
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, from);
+ args = tree_cons (NULL, t, NULL);
+
+ t = build_fold_addr_expr (from);
+ args = tree_cons (NULL, t, args);
+
+ to_ptr = build_fold_addr_expr (to);
+ args = tree_cons (NULL, to_ptr, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMCPY];
+ t = build_function_call_expr (t, args);
+
+ if (want_value)
+ {
+ t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
+ t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+ }
+
+ *expr_p = t;
+ return GS_OK;
+}
+
+/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
+ a call to __builtin_memset. In this case we know that the RHS is
+ a CONSTRUCTOR with an empty element list. */
+
+static enum gimplify_status
+gimplify_modify_expr_to_memset (tree *expr_p, bool want_value)
+{
+ tree args, t, to, to_ptr;
+
+ to = TREE_OPERAND (*expr_p, 0);
+
+ t = TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (*expr_p, 1)));
+ t = unshare_expr (t);
+ t = SUBSTITUTE_PLACEHOLDER_IN_EXPR (t, to);
+ args = tree_cons (NULL, t, NULL);
+
+ args = tree_cons (NULL, integer_zero_node, args);
+
+ to_ptr = build_fold_addr_expr (to);
+ args = tree_cons (NULL, to_ptr, args);
+ t = implicit_built_in_decls[BUILT_IN_MEMSET];
+ t = build_function_call_expr (t, args);
+
+ if (want_value)
+ {
+ t = build1 (NOP_EXPR, TREE_TYPE (to_ptr), t);
+ t = build1 (INDIRECT_REF, TREE_TYPE (to), t);
+ }
+
+ *expr_p = t;
+ return GS_OK;
+}
+
+/* A subroutine of gimplify_modify_expr. Break out elements of a
+ CONSTRUCTOR used as an initializer into separate MODIFY_EXPRs.
+
+ 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. */
+
+static enum gimplify_status
+gimplify_init_constructor (tree *expr_p, tree *pre_p,
+ tree *post_p, bool want_value)
+{
+ tree object = TREE_OPERAND (*expr_p, 0);
+ tree ctor = TREE_OPERAND (*expr_p, 1);
+ tree type = TREE_TYPE (ctor);
+ enum gimplify_status ret;
+ tree elt_list;
+
+ if (TREE_CODE (ctor) != CONSTRUCTOR)
+ return GS_UNHANDLED;
+
+ elt_list = CONSTRUCTOR_ELTS (ctor);
+
+ ret = GS_ALL_DONE;
+ switch (TREE_CODE (type))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case ARRAY_TYPE:
+ {
+ HOST_WIDE_INT i, num_elements, num_nonzero_elements;
+ HOST_WIDE_INT num_nonconstant_elements;
+ bool cleared;
+
+ /* 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 (want_value)
+ {
+ *expr_p = object;
+ return GS_OK;
+ }
+ else
+ return GS_UNHANDLED;
+ }
+
+ categorize_ctor_elements (ctor, &num_nonzero_elements,
+ &num_nonconstant_elements);
+ num_elements = count_type_elements (TREE_TYPE (ctor));
+
+ /* If a const aggregate variable is being initialized, then it
+ should never be a lose to promote the variable to be static. */
+ if (num_nonconstant_elements == 0
+ && TREE_READONLY (object)
+ && TREE_CODE (object) == VAR_DECL)
+ {
+ DECL_INITIAL (object) = ctor;
+ TREE_STATIC (object) = 1;
+ if (!DECL_NAME (object))
+ DECL_NAME (object) = create_tmp_var_name ("C");
+ walk_tree (&DECL_INITIAL (object), force_labels_r, NULL, NULL);
+
+ /* ??? C++ doesn't automatically append a .<number> to the
+ assembler name, and even when it does, it looks a FE private
+ data structures to figure out what that number should be,
+ which are not set for this variable. I suppose this is
+ important for local statics for inline functions, which aren't
+ "local" in the object file sense. So in order to get a unique
+ TU-local symbol, we must invoke the lhd version now. */
+ lhd_set_decl_assembler_name (object);
+
+ *expr_p = NULL_TREE;
+ break;
+ }
+
+ /* 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)
+ {
+ HOST_WIDE_INT size = int_size_in_bytes (type);
+ unsigned int align;
+
+ /* ??? We can still get unbounded array types, at least
+ from the C++ front end. This seems wrong, but attempt
+ to work around it for now. */
+ if (size < 0)
+ {
+ size = int_size_in_bytes (TREE_TYPE (object));
+ if (size >= 0)
+ TREE_TYPE (ctor) = type = TREE_TYPE (object);
+ }
+
+ /* Find the maximum alignment we can assume for the object. */
+ /* ??? Make use of DECL_OFFSET_ALIGN. */
+ if (DECL_P (object))
+ align = DECL_ALIGN (object);
+ else
+ align = TYPE_ALIGN (type);
+
+ if (size > 0 && !can_move_by_pieces (size, align))
+ {
+ tree new = create_tmp_var_raw (type, "C");
+ gimple_add_tmp_var (new);
+ TREE_STATIC (new) = 1;
+ TREE_READONLY (new) = 1;
+ DECL_INITIAL (new) = ctor;
+ if (align > DECL_ALIGN (new))
+ {
+ DECL_ALIGN (new) = align;
+ DECL_USER_ALIGN (new) = 1;
+ }
+ walk_tree (&DECL_INITIAL (new), force_labels_r, NULL, NULL);
+
+ TREE_OPERAND (*expr_p, 1) = new;
+ 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. */
+
+ /* If there are "lots" of zeros, then block clear the object first. */
+ cleared = false;
+ if (num_elements - num_nonzero_elements > CLEAR_RATIO
+ && num_nonzero_elements < num_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
+ {
+ HOST_WIDE_INT len = list_length (elt_list);
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree nelts = array_type_nelts (type);
+ if (!host_integerp (nelts, 1)
+ || tree_low_cst (nelts, 1) + 1 != len)
+ cleared = 1;;
+ }
+ else if (len != fields_length (type))
+ cleared = 1;
+ }
+
+ if (cleared)
+ {
+ /* 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. Make an unshared copy of
+ OBJECT before that so we can match a PLACEHOLDER_EXPR to it
+ later, if needed. */
+ CONSTRUCTOR_ELTS (ctor) = NULL_TREE;
+ object = unshare_expr (TREE_OPERAND (*expr_p, 0));
+ gimplify_stmt (expr_p);
+ append_to_statement_list (*expr_p, pre_p);
+ }
+
+ for (i = 0; elt_list; i++, elt_list = TREE_CHAIN (elt_list))
+ {
+ tree purpose, value, cref, init;
+
+ purpose = TREE_PURPOSE (elt_list);
+ value = TREE_VALUE (elt_list);
+
+ if (cleared && initializer_zerop (value))
+ continue;
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree t = TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (object)));
+
+ /* ??? Here's to hoping the front end fills in all of the
+ indicies, so we don't have to figure out what's missing
+ ourselves. */
+ if (!purpose)
+ abort ();
+ /* ??? Need to handle this. */
+ if (TREE_CODE (purpose) == RANGE_EXPR)
+ abort ();
+
+ cref = build (ARRAY_REF, t, unshare_expr (object), purpose,
+ NULL_TREE, NULL_TREE);
+ }
+ else
+ cref = build (COMPONENT_REF, TREE_TYPE (purpose),
+ unshare_expr (object), purpose, NULL_TREE);
+
+ init = build (MODIFY_EXPR, TREE_TYPE (purpose), cref, value);
+
+ /* Each member initialization is a full-expression. */
+ gimplify_and_add (init, pre_p);
+ }
+
+ *expr_p = NULL_TREE;
+ }
+ break;
+
+ case COMPLEX_TYPE:
+ {
+ 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);
+ if (TREE_CHAIN (elt_list))
+ abort ();
+ }
+ }
+ if (r == NULL || i == NULL)
+ {
+ tree zero = convert (TREE_TYPE (type), integer_zero_node);
+ if (r == NULL)
+ r = zero;
+ if (i == NULL)
+ i = zero;
+ }
+
+ /* Complex types have either COMPLEX_CST or COMPLEX_EXPR to
+ represent creation of a complex value. */
+ if (TREE_CONSTANT (r) && TREE_CONSTANT (i))
+ {
+ ctor = build_complex (type, r, i);
+ TREE_OPERAND (*expr_p, 1) = ctor;
+ }
+ else
+ {
+ ctor = build (COMPLEX_EXPR, type, r, i);
+ TREE_OPERAND (*expr_p, 1) = ctor;
+ ret = gimplify_expr (&TREE_OPERAND (*expr_p, 1), pre_p, post_p,
+ is_gimple_tmp_rhs, fb_rvalue);
+ }
+ }
+ break;
+
+ case VECTOR_TYPE:
+ /* Go ahead and simplify constant constructors to VECTOR_CST. */
+ if (TREE_CONSTANT (ctor))
+ TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);