diff options
author | Richard Sandiford <rdsandiford@googlemail.com> | 2012-11-18 17:32:45 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2012-11-18 17:32:45 +0000 |
commit | 26f8b976309c42177332866ae3c6bf5a257c61fc (patch) | |
tree | d3308fcd82a8463340faa0e773e18fdd07c823f5 /gcc | |
parent | 5f2cbd0debd8670fdf8689891ea0d2e711a2fecd (diff) | |
download | gcc-26f8b976309c42177332866ae3c6bf5a257c61fc.zip gcc-26f8b976309c42177332866ae3c6bf5a257c61fc.tar.gz gcc-26f8b976309c42177332866ae3c6bf5a257c61fc.tar.bz2 |
expmed.c (narrow_bit_field_mem): New function.
gcc/
* expmed.c (narrow_bit_field_mem): New function.
(store_bit_field_using_insv, store_bit_field_1, store_fixed_bit_field)
(extract_bit_field_1): Use it.
From-SVN: r193602
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/expmed.c | 76 |
2 files changed, 51 insertions, 31 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8c7a6a1..5d41ef9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2012-11-18 Richard Sandiford <rdsandiford@googlemail.com> + * expmed.c (narrow_bit_field_mem): New function. + (store_bit_field_using_insv, store_bit_field_1, store_fixed_bit_field) + (extract_bit_field_1): Use it. + +2012-11-18 Richard Sandiford <rdsandiford@googlemail.com> + * expr.h (adjust_address_1): Add a size parameter. (adjust_address, adjust_address_nv, adjust_bitfield_address) (adjust_bitfield_address_nv): Adjust accordingly. diff --git a/gcc/expmed.c b/gcc/expmed.c index 8640427..106b78b 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -387,6 +387,34 @@ mode_for_extraction (enum extraction_pattern pattern, int opno) return data->operand[opno].mode; } +/* Adjust bitfield memory MEM so that it points to the first unit of mode + MODE that contains a bitfield of size BITSIZE at bit position BITNUM. + If MODE is BLKmode, return a reference to every byte in the bitfield. + Set *NEW_BITNUM to the bit position of the field within the new memory. */ + +static rtx +narrow_bit_field_mem (rtx mem, enum machine_mode mode, + unsigned HOST_WIDE_INT bitsize, + unsigned HOST_WIDE_INT bitnum, + unsigned HOST_WIDE_INT *new_bitnum) +{ + if (mode == BLKmode) + { + *new_bitnum = bitnum % BITS_PER_UNIT; + HOST_WIDE_INT offset = bitnum / BITS_PER_UNIT; + HOST_WIDE_INT size = ((*new_bitnum + bitsize + BITS_PER_UNIT - 1) + / BITS_PER_UNIT); + return adjust_bitfield_address_size (mem, mode, offset, size); + } + else + { + unsigned int unit = GET_MODE_BITSIZE (mode); + *new_bitnum = bitnum % unit; + HOST_WIDE_INT offset = (bitnum - *new_bitnum) / BITS_PER_UNIT; + return adjust_bitfield_address (mem, mode, offset); + } +} + /* Return true if a bitfield of size BITSIZE at bit number BITNUM within a structure of mode STRUCT_MODE represents a lowpart subreg. The subreg offset is then BITNUM / BITS_PER_UNIT. */ @@ -424,11 +452,8 @@ store_bit_field_using_insv (rtx op0, unsigned HOST_WIDE_INT bitsize, return false; if (MEM_P (xop0)) - { - /* Get a reference to the first byte of the field. */ - xop0 = adjust_bitfield_address (xop0, byte_mode, bitnum / BITS_PER_UNIT); - bitnum %= BITS_PER_UNIT; - } + /* Get a reference to the first byte of the field. */ + xop0 = narrow_bit_field_mem (xop0, byte_mode, bitsize, bitnum, &bitnum); else { /* Convert from counting within OP0 to counting in OP_MODE. */ @@ -831,18 +856,15 @@ store_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0))) { rtx last, tempreg, xop0; - unsigned int unit; - unsigned HOST_WIDE_INT offset, bitpos; + unsigned HOST_WIDE_INT bitpos; last = get_last_insn (); /* Adjust address to point to the containing unit of that mode. Compute the offset as a multiple of this unit, counting in bytes. */ - unit = GET_MODE_BITSIZE (bestmode); - offset = (bitnum / unit) * GET_MODE_SIZE (bestmode); - bitpos = bitnum % unit; - xop0 = adjust_bitfield_address (op0, bestmode, offset); + xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum, + &bitpos); /* Fetch that unit, store the bitfield in it, then store the unit. */ @@ -975,9 +997,7 @@ store_fixed_bit_field (rtx op0, unsigned HOST_WIDE_INT bitsize, return; } - HOST_WIDE_INT bit_offset = bitnum - bitnum % GET_MODE_BITSIZE (mode); - op0 = adjust_bitfield_address (op0, mode, bit_offset / BITS_PER_UNIT); - bitnum -= bit_offset; + op0 = narrow_bit_field_mem (op0, mode, bitsize, bitnum, &bitnum); } mode = GET_MODE (op0); @@ -1246,11 +1266,8 @@ extract_bit_field_using_extv (rtx op0, unsigned HOST_WIDE_INT bitsize, return NULL_RTX; if (MEM_P (op0)) - { - /* Get a reference to the first byte of the field. */ - op0 = adjust_bitfield_address (op0, byte_mode, bitnum / BITS_PER_UNIT); - bitnum %= BITS_PER_UNIT; - } + /* Get a reference to the first byte of the field. */ + op0 = narrow_bit_field_mem (op0, byte_mode, bitsize, bitnum, &bitnum); else { /* Convert from counting within OP0 to counting in EXT_MODE. */ @@ -1640,23 +1657,20 @@ extract_bit_field_1 (rtx str_rtx, unsigned HOST_WIDE_INT bitsize, && !(SLOW_UNALIGNED_ACCESS (bestmode, MEM_ALIGN (op0)) && GET_MODE_BITSIZE (bestmode) > MEM_ALIGN (op0))) { - unsigned HOST_WIDE_INT offset, bitpos; - - /* Compute the offset as a multiple of this unit, - counting in bytes. */ - unsigned int unit = GET_MODE_BITSIZE (bestmode); - offset = (bitnum / unit) * GET_MODE_SIZE (bestmode); - bitpos = bitnum % unit; - - /* Make sure the register is big enough for the whole field. */ - if (bitpos + bitsize <= unit) + unsigned HOST_WIDE_INT bitpos; + rtx xop0 = narrow_bit_field_mem (op0, bestmode, bitsize, bitnum, + &bitpos); + + /* Make sure the register is big enough for the whole field. + (It might not be if bestmode == GET_MODE (op0) and the input + code was invalid.) */ + if (bitpos + bitsize <= GET_MODE_BITSIZE (bestmode)) { - rtx last, result, xop0; + rtx last, result; last = get_last_insn (); /* Fetch it to a register in that size. */ - xop0 = adjust_bitfield_address (op0, bestmode, offset); xop0 = force_reg (bestmode, xop0); result = extract_bit_field_1 (xop0, bitsize, bitpos, unsignedp, packedp, target, |