diff options
author | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-04-01 21:13:29 +0000 |
---|---|---|
committer | jakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-04-01 21:13:29 +0000 |
commit | 3a1751607f510e49bd0c35ecb7b10e9f9b918111 (patch) | |
tree | feaee55ecf6450268c89a7644e7055c18ceee503 /gcc/expmed.c | |
parent | 87ad9affc67d7c397f56d27367f8f8c0266b4414 (diff) | |
download | gcc-3a1751607f510e49bd0c35ecb7b10e9f9b918111.tar.gz |
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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171855 138bc75d-0d04-0410-961f-82ee72b054a4
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 6218f3d4ce8..9458df3747e 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; } } |