diff --git a/gcc/ChangeLog b/gcc/ChangeLog index d8c0e23c013d64b0dea7b0e6363f8e0d40975f25..ed8d8b1575b8f1a0d2d45e0b64119d586f607e84 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2012-09-18 Eric Botcazou <ebotcazou@adacore.com> + + PR middle-end/54617 + * expr.c (store_field): Handle a PARALLEL in more cases. + 2012-09-18 Segher Boessenkool <segher@kernel.crashing.org> * config/rs6000/rs6000.md (sminsi3, smaxsi3, uminsi3, umaxsi3): diff --git a/gcc/expr.c b/gcc/expr.c index c53f1a8dc9b7d0dba5ddb88e3c923acaaf430933..36f4dd7d53ec1626e4d795e502a78c100e62bb85 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -6452,16 +6452,33 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, /* Handle calls that return values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ - if (bitpos == 0 - && bitsize == GET_MODE_BITSIZE (mode) - && GET_CODE (temp) == PARALLEL) - emit_group_store (target, temp, TREE_TYPE (exp), - int_size_in_bytes (TREE_TYPE (exp))); - else - /* Store the value in the bitfield. */ - store_bit_field (target, bitsize, bitpos, - bitregion_start, bitregion_end, - mode, temp); + if (GET_CODE (temp) == PARALLEL) + { + rtx temp_target; + + /* We are not supposed to have a true bitfield in this case. */ + gcc_assert (bitsize == GET_MODE_BITSIZE (mode)); + + /* If we don't store at bit 0, we need an intermediate pseudo + since emit_group_store only stores at bit 0. */ + if (bitpos != 0) + temp_target = gen_reg_rtx (mode); + else + temp_target = target; + + emit_group_store (temp_target, temp, TREE_TYPE (exp), + int_size_in_bytes (TREE_TYPE (exp))); + + if (temp_target == target) + return const0_rtx; + + temp = temp_target; + } + + /* Store the value in the bitfield. */ + store_bit_field (target, bitsize, bitpos, + bitregion_start, bitregion_end, + mode, temp); return const0_rtx; }