+/* Generate code for computing CONSTRUCTOR EXP.
+ An rtx for the computed value is returned. If AVOID_TEMP_MEM
+ is TRUE, instead of creating a temporary variable in memory
+ NULL is returned and the caller needs to handle it differently. */
+
+static rtx
+expand_constructor (tree exp, rtx target, enum expand_modifier modifier,
+ bool avoid_temp_mem)
+{
+ tree type = TREE_TYPE (exp);
+ enum machine_mode mode = TYPE_MODE (type);
+
+ /* Try to avoid creating a temporary at all. This is possible
+ if all of the initializer is zero.
+ FIXME: try to handle all [0..255] initializers we can handle
+ with memset. */
+ if (TREE_STATIC (exp)
+ && !TREE_ADDRESSABLE (exp)
+ && target != 0 && mode == BLKmode
+ && all_zeros_p (exp))
+ {
+ clear_storage (target, expr_size (exp), BLOCK_OP_NORMAL);
+ return target;
+ }
+
+ /* All elts simple constants => refer to a constant in memory. But
+ if this is a non-BLKmode mode, let it store a field at a time
+ since that should make a CONST_INT or CONST_DOUBLE when we
+ fold. Likewise, if we have a target we can use, it is best to
+ store directly into the target unless the type is large enough
+ that memcpy will be used. If we are making an initializer and
+ all operands are constant, put it in memory as well.
+
+ FIXME: Avoid trying to fill vector constructors piece-meal.
+ Output them with output_constant_def below unless we're sure
+ they're zeros. This should go away when vector initializers
+ are treated like VECTOR_CST instead of arrays. */
+ if ((TREE_STATIC (exp)
+ && ((mode == BLKmode
+ && ! (target != 0 && safe_from_p (target, exp, 1)))
+ || TREE_ADDRESSABLE (exp)
+ || (host_integerp (TYPE_SIZE_UNIT (type), 1)
+ && (! MOVE_BY_PIECES_P
+ (tree_low_cst (TYPE_SIZE_UNIT (type), 1),
+ TYPE_ALIGN (type)))
+ && ! mostly_zeros_p (exp))))
+ || ((modifier == EXPAND_INITIALIZER || modifier == EXPAND_CONST_ADDRESS)
+ && TREE_CONSTANT (exp)))
+ {
+ rtx constructor;
+
+ if (avoid_temp_mem)
+ return NULL_RTX;
+
+ constructor = expand_expr_constant (exp, 1, modifier);
+
+ if (modifier != EXPAND_CONST_ADDRESS
+ && modifier != EXPAND_INITIALIZER
+ && modifier != EXPAND_SUM)
+ constructor = validize_mem (constructor);
+
+ return constructor;
+ }
+
+ /* Handle calls that pass values in multiple non-contiguous
+ locations. The Irix 6 ABI has examples of this. */
+ if (target == 0 || ! safe_from_p (target, exp, 1)
+ || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM)
+ {
+ if (avoid_temp_mem)
+ return NULL_RTX;
+
+ target
+ = assign_temp (build_qualified_type (type, (TYPE_QUALS (type)
+ | (TREE_READONLY (exp)
+ * TYPE_QUAL_CONST))),
+ 0, TREE_ADDRESSABLE (exp), 1);
+ }
+
+ store_constructor (exp, target, 0, int_expr_size (exp));
+ return target;
+}
+