diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-09-23 11:34:28 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2007-09-23 11:34:28 +0200 |
commit | 32eed0456c8c9c52b6b33a375788b09f476542cd (patch) | |
tree | b61cf5aa1683abc17ffef926b5895ba08f2bb920 /gcc/expr.c | |
parent | f2531eb6e5d9c62379284931f9994e69718015b2 (diff) | |
download | gcc-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.c | 172 |
1 files changed, 103 insertions, 69 deletions
@@ -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) |