diff options
author | Jakub Jelinek <jakub@redhat.com> | 2011-04-01 23:13:29 +0200 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2011-04-01 23:13:29 +0200 |
commit | 19228b93eacef5d8661c5d5a82272d42a82e0e26 (patch) | |
tree | feaee55ecf6450268c89a7644e7055c18ceee503 /gcc/expmed.c | |
parent | 88cb339e2fc095381098658177b8600ee151c58f (diff) | |
download | gcc-19228b93eacef5d8661c5d5a82272d42a82e0e26.zip gcc-19228b93eacef5d8661c5d5a82272d42a82e0e26.tar.gz gcc-19228b93eacef5d8661c5d5a82272d42a82e0e26.tar.bz2 |
re PR middle-end/48335 (ICE in convert_move)
PR middle-end/48335
* expr.c (expand_assignment): Handle all possibilities
if TO_RTX is CONCAT.
* expmed.c (store_bit_field_1): Avoid trying to create
invalid SUBREGs.
(store_split_bit_field): If SUBREG_REG (op0) or
op0 itself has smaller mode than word, return it
for offset 0 and const0_rtx for out-of-bounds stores.
If word is const0_rtx, skip it.
* gcc.c-torture/compile/pr48335-1.c: New test.
* gcc.dg/pr48335-1.c: New test.
* gcc.dg/pr48335-2.c: New test.
* gcc.dg/pr48335-3.c: New test.
* gcc.dg/pr48335-4.c: New test.
* gcc.dg/pr48335-5.c: New test.
* gcc.dg/pr48335-6.c: New test.
* gcc.dg/pr48335-7.c: New test.
* gcc.dg/pr48335-8.c: New test.
* gcc.target/i386/pr48335-1.c: New test.
From-SVN: r171855
Diffstat (limited to 'gcc/expmed.c')
-rw-r--r-- | gcc/expmed.c | 48 |
1 files changed, 32 insertions, 16 deletions
diff --git a/gcc/expmed.c b/gcc/expmed.c index 6218f3d..9458df3 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -418,8 +418,10 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && bitsize == GET_MODE_BITSIZE (fieldmode) && (!MEM_P (op0) ? ((GET_MODE_SIZE (fieldmode) >= UNITS_PER_WORD - || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)) - && byte_offset % GET_MODE_SIZE (fieldmode) == 0) + || GET_MODE_SIZE (GET_MODE (op0)) == GET_MODE_SIZE (fieldmode)) + && ((GET_MODE (op0) == fieldmode && byte_offset == 0) + || validate_subreg (fieldmode, GET_MODE (op0), op0, + byte_offset))) : (! SLOW_UNALIGNED_ACCESS (fieldmode, MEM_ALIGN (op0)) || (offset * BITS_PER_UNIT % bitsize == 0 && MEM_ALIGN (op0) % GET_MODE_BITSIZE (fieldmode) == 0)))) @@ -479,6 +481,7 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, struct expand_operand ops[2]; enum insn_code icode = optab_handler (movstrict_optab, fieldmode); rtx arg0 = op0; + unsigned HOST_WIDE_INT subreg_off; if (GET_CODE (arg0) == SUBREG) { @@ -491,15 +494,18 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, arg0 = SUBREG_REG (arg0); } - arg0 = gen_rtx_SUBREG (fieldmode, arg0, - (bitnum % BITS_PER_WORD) / BITS_PER_UNIT - + (offset * UNITS_PER_WORD)); + subreg_off = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT + + (offset * UNITS_PER_WORD); + if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off)) + { + arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off); - create_fixed_operand (&ops[0], arg0); - /* Shrink the source operand to FIELDMODE. */ - create_convert_operand_to (&ops[1], value, fieldmode, false); - if (maybe_expand_insn (icode, 2, ops)) - return true; + create_fixed_operand (&ops[0], arg0); + /* Shrink the source operand to FIELDMODE. */ + create_convert_operand_to (&ops[1], value, fieldmode, false); + if (maybe_expand_insn (icode, 2, ops)) + return true; + } } /* Handle fields bigger than a word. */ @@ -1045,22 +1051,32 @@ store_split_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, if (GET_CODE (op0) == SUBREG) { int word_offset = (SUBREG_BYTE (op0) / UNITS_PER_WORD) + offset; - word = operand_subword_force (SUBREG_REG (op0), word_offset, - GET_MODE (SUBREG_REG (op0))); + enum machine_mode sub_mode = GET_MODE (SUBREG_REG (op0)); + if (sub_mode != BLKmode && GET_MODE_SIZE (sub_mode) < UNITS_PER_WORD) + word = word_offset ? const0_rtx : op0; + else + word = operand_subword_force (SUBREG_REG (op0), word_offset, + GET_MODE (SUBREG_REG (op0))); offset = 0; } else if (REG_P (op0)) { - word = operand_subword_force (op0, offset, GET_MODE (op0)); + enum machine_mode op0_mode = GET_MODE (op0); + if (op0_mode != BLKmode && GET_MODE_SIZE (op0_mode) < UNITS_PER_WORD) + word = offset ? const0_rtx : op0; + else + word = operand_subword_force (op0, offset, GET_MODE (op0)); offset = 0; } else word = op0; /* OFFSET is in UNITs, and UNIT is in bits. - store_fixed_bit_field wants offset in bytes. */ - store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize, - thispos, part); + store_fixed_bit_field wants offset in bytes. If WORD is const0_rtx, + it is just an out-of-bounds access. Ignore it. */ + if (word != const0_rtx) + store_fixed_bit_field (word, offset * unit / BITS_PER_UNIT, thissize, + thispos, part); bitsdone += thissize; } } |