aboutsummaryrefslogtreecommitdiff
path: root/gcc/expr.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2007-09-23 11:34:28 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2007-09-23 11:34:28 +0200
commit32eed0456c8c9c52b6b33a375788b09f476542cd (patch)
treeb61cf5aa1683abc17ffef926b5895ba08f2bb920 /gcc/expr.c
parentf2531eb6e5d9c62379284931f9994e69718015b2 (diff)
downloadgcc-32eed0456c8c9c52b6b33a375788b09f476542cd.zip
gcc-32eed0456c8c9c52b6b33a375788b09f476542cd.tar.gz
gcc-32eed0456c8c9c52b6b33a375788b09f476542cd.tar.bz2
re PR middle-end/28755 (duplicate members of arrays)
PR middle-end/28755 * 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. * gcc.dg/pr28755.c: New test. From-SVN: r128685
Diffstat (limited to 'gcc/expr.c')
-rw-r--r--gcc/expr.c172
1 files changed, 103 insertions, 69 deletions
diff --git a/gcc/expr.c b/gcc/expr.c
index 9302810..c7b29b5 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6887,6 +6887,89 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode,
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 = 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;
+}
+
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
@@ -7379,71 +7462,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
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 = expand_expr_constant (exp, 1, modifier);
-
- 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:
@@ -7585,10 +7604,25 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode,
field, value)
if (tree_int_cst_equal (field, index))
{
- if (!TREE_SIDE_EFFECTS (value))
- return expand_expr (fold (value), target, tmode,
- modifier);
- break;
+ if (TREE_SIDE_EFFECTS (value))
+ break;
+
+ 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);
}
}
else if(TREE_CODE (init) == STRING_CST)