diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/expr.c | 172 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr28755.c | 22 |
4 files changed, 138 insertions, 69 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3d7faf5..33f900f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2007-09-23 Jakub Jelinek <jakub@redhat.com> + + 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. + 2007-09-23 Richard Sandiford <rsandifo@nildram.co.uk> * config/mips/mips.c (dump_constants_1): Generalize to include @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 21df8be..a6d1660 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-09-23 Jakub Jelinek <jakub@redhat.com> + + PR middle-end/28755 + * gcc.dg/pr28755.c: New test. + 2007-09-23 Richard Sandiford <rsandifo@nildram.co.uk> * lib/target-supports.exp (check_effective_target_nomips16): New diff --git a/gcc/testsuite/gcc.dg/pr28755.c b/gcc/testsuite/gcc.dg/pr28755.c new file mode 100644 index 0000000..9a01f88 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr28755.c @@ -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]; +} |