From: Eric Botcazou <ebotcazou@adacore.com>
To: Richard Sandiford <rdsandiford@googlemail.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: Tidy store_bit_field_1 & co.
Date: Wed, 17 Oct 2012 20:52:00 -0000 [thread overview]
Message-ID: <8248446.zrYi3fceYI@polaris> (raw)
In-Reply-To: <87obk4lu63.fsf@talisman.home>
> The patch is probably quite hard to review, sorry. I've made the changelog
> a bit more detailed than usual in order to list the individual points.
You meant scary, didn't you? :-)
> * expmed.c (store_bit_field_1): Remove unit, offset, bitpos and
> byte_offset from the outermost scope. Express conditions in terms
> of bitnum rather than offset, bitpos and byte_offset. Split the
> plain move cases into two, one for memory accesses and one for
> register accesses. Allow simplify_gen_subreg to fail rather
> than calling validate_subreg. Move the handling of multiword
> OP0s after the code that coerces VALUE to an integer mode.
> Use simplify_gen_subreg for this case and assert that it succeeds.
> If the field still spans several words, pass it directly to
> store_split_bit_field. Assume after that point that both sources
> and register targets fit within a word. Replace x-prefixed
> variables with non-prefixed forms. Compute the bitpos for insv
> register operands directly in the chosen unit size, rather than
> going through an intermediate BITS_PER_WORD unit size.
> Update the call to store_fixed_bit_field.
> (store_fixed_bit_field): Replace the bitpos and offset parameters
> with a single bitnum parameter, of the same form as store_bit_field.
> Assume that OP0 contains the full field. Simplify the memory offset
> calculation. Assert that the processed OP0 has an integral mode.
> (store_split_bit_field): Update the call to store_fixed_bit_field.
I agree that splitting the memory and register cases is a good idea, as well
as unifying the interface. A few remarks:
> -476,34 +468,36 @@ store_bit_field_1 (rtx str_rtx, unsigne
> }
>
> /* If the target is a register, overwriting the entire object, or storing
> - a full-word or multi-word field can be done with just a SUBREG. +
> a full-word or multi-word field can be done with just a SUBREG. */ + if
> (!MEM_P (op0)
> + && bitsize == GET_MODE_BITSIZE (fieldmode)
> + && ((bitsize % BITS_PER_WORD == 0
> + && bitnum % BITS_PER_WORD == 0)
> + || (bitsize == GET_MODE_BITSIZE (GET_MODE (op0))
> + && bitnum == 0)))
> + {
> + /* Use the subreg machinery either to narrow OP0 to the required
> + words or to cope with mode punning between equal-sized modes. */
> + rtx sub = simplify_gen_subreg (fieldmode, op0, GET_MODE (op0),
> + bitnum / BITS_PER_UNIT);
> + if (sub)
> + {
> + emit_move_insn (sub, value);
> + return true;
> + }
> + }
I'd use the following variant for the sake of symmetry with the MEM_P case:
if (!MEM_P (op0)
&& bitnum % BITS_PER_WORD == 0
&& bitsize == GET_MODE_BITSIZE (fieldmode)
&& [...]
> - /* If OP0 is a register, BITPOS must count within a word.
> - But as we have it, it counts within whatever size OP0 now has.
> - On a bigendian machine, these are not the same, so convert. */
> - if (BYTES_BIG_ENDIAN
> - && !MEM_P (op0)
> - && unit > GET_MODE_BITSIZE (GET_MODE (op0)))
> - bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
> -
> /* Storing an lsb-aligned field in a register
> - can be done with a movestrict instruction. */
> + can be done with a movstrict instruction. */
>
> if (!MEM_P (op0)
> - && (BYTES_BIG_ENDIAN ? bitpos + bitsize == unit : bitpos == 0)
> + && (BYTES_BIG_ENDIAN
> + ? bitnum + bitsize == GET_MODE_BITSIZE (GET_MODE (op0))
> + : bitnum == 0)
> && bitsize == GET_MODE_BITSIZE (fieldmode)
> && optab_handler (movstrict_optab, fieldmode) != CODE_FOR_nothing)
> {
> @@ -558,8 +546,7 @@ store_bit_field_1 (rtx str_rtx, unsigned
> arg0 = SUBREG_REG (arg0);
> }
>
> - subreg_off = (bitnum % BITS_PER_WORD) / BITS_PER_UNIT
> - + (offset * UNITS_PER_WORD);
> + subreg_off = bitnum / BITS_PER_UNIT;
> if (validate_subreg (fieldmode, GET_MODE (arg0), arg0, subreg_off))
> {
> arg0 = gen_rtx_SUBREG (fieldmode, arg0, subreg_off);
Aren't you losing movstrict opportunities in big-endian mode? If GET_MODE
(op0) is 2 words and bitnum + bitsize == BITS_PER_WORD.
> @@ -638,34 +625,6 @@ store_bit_field_1 (rtx str_rtx, unsigned
> return true;
> }
>
> - /* From here on we can assume that the field to be stored in is
> - a full-word (whatever type that is), since it is shorter than a word.
> */ -
> - /* OFFSET is the number of words or bytes (UNIT says which)
> - from STR_RTX to the first word or byte containing part of the field.
> */ -
> - if (!MEM_P (op0))
> - {
> - if (offset != 0
> - || GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
> - {
> - if (!REG_P (op0))
> - {
> - /* Since this is a destination (lvalue), we can't copy
> - it to a pseudo. We can remove a SUBREG that does not
> - change the size of the operand. Such a SUBREG may
> - have been added above. */
> - gcc_assert (GET_CODE (op0) == SUBREG
> - && (GET_MODE_SIZE (GET_MODE (op0))
> - == GET_MODE_SIZE (GET_MODE (SUBREG_REG (op0)))));
> - op0 = SUBREG_REG (op0);
> - }
> - op0 = gen_rtx_SUBREG (mode_for_size (BITS_PER_WORD, MODE_INT, 0),
> - op0, (offset * UNITS_PER_WORD));
> - }
> - offset = 0;
> - }
> -
> /* If VALUE has a floating-point or complex mode, access it as an
> integer of the corresponding size. This can occur on a machine
> with 64 bit registers that uses SFmode for float. It can also
> @@ -679,9 +638,30 @@ store_bit_field_1 (rtx str_rtx, unsigned
> emit_move_insn (gen_lowpart (GET_MODE (orig_value), value),
> orig_value); }
>
> - /* Now OFFSET is nonzero only if OP0 is memory
> - and is therefore always measured in bytes. */
> + /* If OP0 is a multi-word register, narrow it to the affected word.
> + If the region spans two words, defer to store_split_bit_field. */
> + if (!MEM_P (op0) && GET_MODE_SIZE (GET_MODE (op0)) > UNITS_PER_WORD)
> + {
> + op0 = simplify_gen_subreg (word_mode, op0, GET_MODE (op0),
> + bitnum / BITS_PER_WORD * UNITS_PER_WORD);
> + gcc_assert (op0);
> + bitnum %= BITS_PER_WORD;
> + if (bitnum + bitsize > BITS_PER_WORD)
> + {
> + if (!fallback_p)
> + return false;
> +
> + store_split_bit_field (op0, bitsize, bitnum, bitregion_start,
> + bitregion_end, value);
> + return true;
> + }
> + }
> +
> + /* From here on we can assume that the field to be stored in fits
> + within a word. If the destination is a register, it too fits
> + in a word. */
I presume the reasoning is that the offset != 0 test is redundant with the
test on the mode size because of the REG_P && ... early exit?
> + enum machine_mode op_mode = mode_for_extraction (EP_insv, 3);
> if (HAVE_insv
> && GET_MODE (value) != BLKmode
> && bitsize > 0
> @@ -690,25 +670,34 @@ store_bit_field_1 (rtx str_rtx, unsigned
> -fstrict-volatile-bitfields is in effect. */
> && !(MEM_P (op0) && MEM_VOLATILE_P (op0)
> && flag_strict_volatile_bitfields > 0)
> - && ! ((REG_P (op0) || GET_CODE (op0) == SUBREG)
> - && (bitsize + bitpos > GET_MODE_BITSIZE (op_mode)))
> /* Do not use insv if the bit region is restricted and
> op_mode integer at offset doesn't fit into the
> restricted region. */
> && !(MEM_P (op0) && bitregion_end
> - && bitnum - bitpos + GET_MODE_BITSIZE (op_mode)
> + && bitnum - (bitnum % BITS_PER_UNIT) + GET_MODE_BITSIZE (op_mode)
>
> > bitregion_end + 1))
>
> {
> struct expand_operand ops[4];
> - int xbitpos = bitpos;
> + unsigned HOST_WIDE_INT bitpos = bitnum;
> rtx value1;
> rtx xop0 = op0;
> rtx last = get_last_insn ();
> bool copy_back = false;
>
> - /* Add OFFSET into OP0's address. */
> + unsigned int unit = GET_MODE_BITSIZE (op_mode);
> if (MEM_P (xop0))
> - xop0 = adjust_bitfield_address (xop0, byte_mode, offset);
> + {
> + /* Get a reference to the first byte of the field. */
> + xop0 = adjust_bitfield_address (xop0, byte_mode,
> + bitpos / BITS_PER_UNIT);
> + bitpos %= BITS_PER_UNIT;
> + }
> + else
> + {
> + /* Convert from counting within OP0 to counting in OP_MODE. */
> + if (BYTES_BIG_ENDIAN)
> + bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
> + }
>
> /* If xop0 is a register, we need it in OP_MODE
> to make it acceptable to the format of insv. */
> @@ -735,20 +724,13 @@ store_bit_field_1 (rtx str_rtx, unsigned
> copy_back = true;
> }
>
> - /* We have been counting XBITPOS within UNIT.
> - Count instead within the size of the register. */
> - if (BYTES_BIG_ENDIAN && !MEM_P (xop0))
> - xbitpos += GET_MODE_BITSIZE (op_mode) - unit;
> -
> - unit = GET_MODE_BITSIZE (op_mode);
> -
> /* If BITS_BIG_ENDIAN is zero on a BYTES_BIG_ENDIAN machine, we count
> "backwards" from the size of the unit we are inserting into. Otherwise, we
> count bits from the most significant on a
> BYTES/BITS_BIG_ENDIAN machine. */
>
> if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
> - xbitpos = unit - bitsize - xbitpos;
> + bitpos = unit - bitsize - bitpos;
>
> /* Convert VALUE to op_mode (which insv insn wants) in VALUE1. */
> value1 = value;
I guess I see the reasoning, but I cannot say whether it's right or wrong...
> - total_bits = GET_MODE_BITSIZE (mode);
> -
> - /* Make sure bitpos is valid for the chosen mode. Adjust BITPOS to
> - be in the range 0 to total_bits-1, and put any excess bytes in
> - OFFSET. */
> - if (bitpos >= total_bits)
> - {
> - offset += (bitpos / total_bits) * (total_bits / BITS_PER_UNIT);
> - bitpos -= ((bitpos / total_bits) * (total_bits / BITS_PER_UNIT)
> - * BITS_PER_UNIT);
> - }
> -
> - /* Get ref to an aligned byte, halfword, or word containing the
> field. - Adjust BITPOS to be position within a word,
> - and OFFSET to be the offset of that word.
> - Then alter OP0 to refer to that word. */
> - bitpos += (offset % (total_bits / BITS_PER_UNIT)) * BITS_PER_UNIT;
> - offset -= (offset % (total_bits / BITS_PER_UNIT));
> - op0 = adjust_bitfield_address (op0, mode, offset);
> + 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;
> }
Gorgeous.
> mode = GET_MODE (op0);
> -
> - /* Now MODE is either some integral mode for a MEM as OP0,
> - or is a full-word for a REG as OP0. TOTAL_BITS corresponds.
> - The bit field is contained entirely within OP0.
> - BITPOS is the starting bit number within OP0.
> - (OP0's mode may actually be narrower than MODE.) */
> + gcc_assert (SCALAR_INT_MODE_P (mode));
> + /* Note that bitsize + bitnum can be greater than GET_MODE_BITSIZE (mode)
> + for invalid input, such as f5 from gcc.dg/pr48335-2.c. */
Blank line after the assertion.
> if (BYTES_BIG_ENDIAN)
> - /* BITPOS is the distance between our msb
> - and that of the containing datum.
> - Convert it to the distance from the lsb. */
> - bitpos = total_bits - bitsize - bitpos;
> + /* BITNUM is the distance between our msb
> + and that of the containing datum.
> + Convert it to the distance from the lsb. */
> + bitnum = GET_MODE_BITSIZE (mode) - bitsize - bitnum;
So bitnum can be negative? Is that new or pre-existing?
--
Eric Botcazou
next prev parent reply other threads:[~2012-10-17 20:30 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-14 19:50 Richard Sandiford
2012-10-17 20:52 ` Eric Botcazou [this message]
2012-10-18 21:35 ` Richard Sandiford
2012-10-20 14:44 ` Eric Botcazou
2012-10-23 18:13 ` Richard Sandiford
2012-10-23 21:46 ` Eric Botcazou
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8248446.zrYi3fceYI@polaris \
--to=ebotcazou@adacore.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=rdsandiford@googlemail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).