summaryrefslogtreecommitdiff
path: root/gcc/expmed.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-01 21:13:29 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2011-04-01 21:13:29 +0000
commit3a1751607f510e49bd0c35ecb7b10e9f9b918111 (patch)
treefeaee55ecf6450268c89a7644e7055c18ceee503 /gcc/expmed.c
parent87ad9affc67d7c397f56d27367f8f8c0266b4414 (diff)
downloadgcc-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.c48
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;
}
}