+ struct gimplify_init_ctor_preeval_data preeval_data;
+ HOST_WIDE_INT num_type_elements, num_ctor_elements;
+ HOST_WIDE_INT num_nonzero_elements, 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)
+ break;
+
+ categorize_ctor_elements (ctor, &num_nonzero_elements,
+ &num_nonconstant_elements,
+ &num_ctor_elements, &cleared);
+
+ /* 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
+ && num_nonzero_elements > 1
+ && 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;
+
+ /* This is no longer an assignment of a CONSTRUCTOR, but
+ we still may have processing to do on the LHS. So
+ pretend we didn't do anything here to let that happen. */
+ return GS_UNHANDLED;
+ }
+ }
+
+ /* 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.
+ 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;
+ object = unshare_expr (object);
+ gimplify_stmt (expr_p);
+ append_to_statement_list (*expr_p, pre_p);
+ }
+
+ /* If we have not block cleared the object, or if there are nonzero
+ elements in the constructor, add assignments to the individual
+ scalar fields of the object. */
+ if (!cleared || num_nonzero_elements > 0)
+ {
+ preeval_data.lhs_base_decl = get_base_address (object);
+ if (!DECL_P (preeval_data.lhs_base_decl))
+ preeval_data.lhs_base_decl = NULL;
+ preeval_data.lhs_alias_set = get_alias_set (object);
+
+ 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);
+ }
+
+ *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);
+ gcc_assert (!TREE_CHAIN (elt_list));
+ }
+ }
+ 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,
+ rhs_predicate_for (TREE_OPERAND (*expr_p, 0)),
+ fb_rvalue);
+ }
+ }
+ break;
+
+ case VECTOR_TYPE:
+ /* Go ahead and simplify constant constructors to VECTOR_CST. */
+ if (TREE_CONSTANT (ctor))
+ {
+ tree tem;
+
+ /* 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;
+
+ if (! tem)
+ {
+ TREE_OPERAND (*expr_p, 1) = build_vector (type, elt_list);
+ 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;
+ }
+ break;
+
+ default:
+ /* So how did we get a CONSTRUCTOR for a scalar type? */
+ gcc_unreachable ();
+ }
+
+ if (ret == GS_ERROR)
+ return GS_ERROR;
+ else if (want_value)
+ {
+ append_to_statement_list (*expr_p, pre_p);
+ *expr_p = object;
+ return GS_OK;
+ }
+ else
+ return GS_ALL_DONE;
+}
+
+/* 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,
+ tree *post_p, bool want_value)
+{
+ enum gimplify_status ret = GS_OK;
+
+ while (ret != GS_UNHANDLED)
+ switch (TREE_CODE (*from_p))
+ {
+ case INDIRECT_REF:
+ {
+ /* If we have code like
+
+ *(const A*)(A*)&x
+
+ where the type of "x" is a (possibly cv-qualified variant
+ of "A"), treat the entire expression as identical to "x".
+ 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)
+ {
+ *from_p = t;
+ ret = GS_OK;
+ }
+ else
+ ret = GS_UNHANDLED;
+ break;
+ }
+
+ case TARGET_EXPR:
+ {
+ /* If we are initializing something from a TARGET_EXPR, strip the