2007-09-25 16:09:05 +00:00
|
|
|
2007-09-23 Jakub Jelinek <jakub@redhat.com>
|
2006-08-18 08:02:11 +00:00
|
|
|
|
|
|
|
PR middle-end/28755
|
2007-09-25 16:09:05 +00:00
|
|
|
* expr.c (expand_constructor): New function.
|
|
|
|
(expand_expr_real_1) <case CONSTRUCTOR>: Call it.
|
|
|
|
(expand_expr_real_1) <case ARRAY_REF>: Call it if VALUE is
|
|
|
|
CONSTRUCTOR.
|
2006-08-18 08:02:11 +00:00
|
|
|
|
|
|
|
* gcc.dg/pr28755.c: New test.
|
|
|
|
|
2007-09-25 16:09:05 +00:00
|
|
|
--- gcc/expr.c (revision 128684)
|
|
|
|
+++ gcc/expr.c (revision 128685)
|
|
|
|
@@ -6435,6 +6435,89 @@ expand_expr_addr_expr (tree exp, rtx tar
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
+/* 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 = output_constant_def (exp, 1);
|
|
|
|
+
|
|
|
|
+ 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;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
|
|
/* expand_expr: generate code for computing expression EXP.
|
|
|
|
An rtx for the computed value is returned. The value is never null.
|
|
|
|
@@ -6899,71 +6982,7 @@ expand_expr_real_1 (tree exp, rtx target
|
|
|
|
return const0_rtx;
|
|
|
|
}
|
|
|
|
|
|
|
|
- /* 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. */
|
|
|
|
- else 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.
|
|
|
|
- */
|
|
|
|
- else 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 = output_constant_def (exp, 1);
|
|
|
|
-
|
|
|
|
- if (modifier != EXPAND_CONST_ADDRESS
|
|
|
|
- && modifier != EXPAND_INITIALIZER
|
|
|
|
- && modifier != EXPAND_SUM)
|
|
|
|
- constructor = validize_mem (constructor);
|
|
|
|
-
|
|
|
|
- return constructor;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- /* 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)
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
+ return expand_constructor (exp, target, modifier, false);
|
|
|
|
|
|
|
|
case MISALIGNED_INDIRECT_REF:
|
|
|
|
case ALIGN_INDIRECT_REF:
|
|
|
|
@@ -7105,10 +7124,25 @@ expand_expr_real_1 (tree exp, rtx target
|
2006-08-18 08:02:11 +00:00
|
|
|
field, value)
|
|
|
|
if (tree_int_cst_equal (field, index))
|
|
|
|
{
|
|
|
|
- if (!TREE_SIDE_EFFECTS (value))
|
2007-09-25 16:09:05 +00:00
|
|
|
- return expand_expr (fold (value), target, tmode,
|
|
|
|
- modifier);
|
|
|
|
- break;
|
2006-08-18 08:02:11 +00:00
|
|
|
+ if (TREE_SIDE_EFFECTS (value))
|
|
|
|
+ break;
|
|
|
|
+
|
2007-09-25 16:09:05 +00:00
|
|
|
+ if (TREE_CODE (value) == CONSTRUCTOR)
|
|
|
|
+ {
|
|
|
|
+ /* If VALUE is a CONSTRUCTOR, this
|
|
|
|
+ optimization is only useful if
|
|
|
|
+ this doesn't store the CONSTRUCTOR
|
|
|
|
+ into memory. If it does, it is more
|
|
|
|
+ efficient to just load the data from
|
|
|
|
+ the array directly. */
|
|
|
|
+ rtx ret = expand_constructor (value, target,
|
|
|
|
+ modifier, true);
|
|
|
|
+ if (ret == NULL_RTX)
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return expand_expr (fold (value), target, tmode,
|
|
|
|
+ modifier);
|
2006-08-18 08:02:11 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 16:09:05 +00:00
|
|
|
else if(TREE_CODE (init) == STRING_CST)
|
|
|
|
--- gcc/testsuite/gcc.dg/pr28755.c (revision 0)
|
|
|
|
+++ gcc/testsuite/gcc.dg/pr28755.c (revision 128685)
|
2006-08-18 08:02:11 +00:00
|
|
|
@@ -0,0 +1,22 @@
|
|
|
|
+/* PR middle-end/28755 */
|
|
|
|
+/* { dg-do compile } */
|
|
|
|
+/* { dg-options "-Os" } */
|
|
|
|
+/* { dg-final { scan-assembler-times "2112543726\|7deadbee" 2 } } */
|
|
|
|
+
|
|
|
|
+struct S
|
|
|
|
+{
|
|
|
|
+ void *s1;
|
|
|
|
+ unsigned s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const struct S array[] = {
|
|
|
|
+ { (void *) 0, 60, 640, 2112543726, 39682, 48, 16, 33, 10, 96, 2, 0, 0, 4 },
|
|
|
|
+ { (void *) 0, 60, 2112543726, 192, 18251, 16, 33, 10, 96, 2, 0, 0, 4, 212 }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+foo (struct S *x)
|
|
|
|
+{
|
|
|
|
+ x[0] = array[0];
|
|
|
|
+ x[5] = array[1];
|
|
|
|
+}
|