public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
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: Tue, 23 Oct 2012 21:46:00 -0000	[thread overview]
Message-ID: <1760664.7SOE4dSe93@polaris> (raw)
In-Reply-To: <87r4opm550.fsf@talisman.home>

> I should probably have responded to this earlier, sorry.  I'm not sure
> which part you mean, so here's an attempt at justifying the whole block:
> 
> 1) WORDS_BIG_ENDIAN is deliberately ignored:
> 
>       /* The following line once was done only if WORDS_BIG_ENDIAN,
> 	 but I think that is a mistake.  WORDS_BIG_ENDIAN is
> 	 meaningful at a much higher level; when structures are copied
> 	 between memory and regs, the higher-numbered regs
> 	 always get higher addresses.  */
> 
> 2) For MEM:
> 
>   The old code reached this "if" statement with:
> 
>     unsigned int unit = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
>     offset = bitnum / unit;
>     bitpos = bitnum % unit;
> 
>   I.e.:
> 
>     offset = bitnum / BITS_PER_UNIT;
>     bitpos = bitnum % BITS_PER_UNIT;
> 
>   which the new code does explicitly with:
> 
>     unsigned HOST_WIDE_INT bitpos = bitnum;
>     if (MEM_P (xop0))
>       {
>         /* Get a reference to the first byte of the field.  */
>         xop0 = adjust_bitfield_address (xop0, byte_mode,
>                                         bitpos / BITS_PER_UNIT);  <-- offset
> bitpos %= BITS_PER_UNIT;
>       }
> 
>   The following:
> 
>     unit = GET_MODE_BITSIZE (op_mode);
>     if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
>       xbitpos = unit - bitsize - xbitpos;
> 
>   code is the same as before.
> 
> 3) For REG, !BYTES_BIG_ENDIAN, !BITS_BIG_ENDIAN:
> 
>   The easy case.  The old code reached this "if" statement with:
> 
>     unsigned int unit = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
>     offset = bitnum / unit;
>     bitpos = bitnum % unit;
>     ...
>     if (!MEM_P (op0) && ...)
>       {
>         ...set op0 to the word containing the field...
>         offset = 0;
>       }
> 
>   where the awkward thing is that OFFSET and BITPOS are now out of sync
>   with BITNUM.  So before the "if" statement:
> 
>     offset = 0;
>     bitpos = bitnum % BITS_PER_WORD;
> 
>   which if the !MEM_P block above had updated BITNUM too would just
>   have been:
> 
>     offset = 0;
>     bitpos = bitnum;
> 
>   The new code does update BITNUM:
> 
>     if (!MEM_P (op0) && ...)
>       {
>         ...set op0 to the word containing the field...
>         bitnum %= BITS_PER_WORD;
>       }
>     ...
>     unsigned HOST_WIDE_INT bitpos = bitnum;
> 
>   so both the following hold:
> 
>     offset = 0;
>     bitpos = bitnum % BITS_PER_WORD;
> 
>     offset = 0;
>     bitpos = bitnum;
> 
>   The "if" statement doesn't do any endian modification to (X)BITPOS
>   before or after the patch.
> 
> 4) For REG, !BYTES_BIG_ENDIAN, BITS_BIG_ENDIAN:
> 
>   Like (3), but at the end we also have:
> 
>     unit = GET_MODE_BITSIZE (op_mode);
>     if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
>       xbitpos = unit - bitsize - xbitpos;
> 
>   This is the same as before, although the assignment to UNIT has moved
>   up a bit.
> 
> 5) For REG, BYTES_BIG_ENDIAN, BITS_BIG_ENDIAN:
> 
>   In this case the code leading up to the "if" statement was:
> 
>     unsigned int unit = (MEM_P (str_rtx)) ? BITS_PER_UNIT : BITS_PER_WORD;
>     offset = bitnum / unit;
>     bitpos = bitnum % unit;
>     ...
>     /* 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));
>     ...
>     if (!MEM_P (op0) && ...)
>       {
>         ...set op0 to the word containing the field...
>         offset = 0;
>       }
> 
>   So:
> 
>     offset = 0
>     bitpos = bitnum % BITS_PER_WORD;
>     if (...original op0 was smaller than a word...)
>       bitpos += BITS_PER_WORD - <bits in op0>;
> 
>   The !MEM_P block narrows OP0s that are wider than a word to word_mode --
>   it never narrows more than that -- so this is equivalent to:
> 
>     offset = 0
>     bitpos = bitnum % BITS_PER_WORD;
>     if (...current op0 is smaller than a word...)
>       bitpos += BITS_PER_WORD - <bits in op0>;
> 
>   And thanks to the !MEM_P code, op0 is never _wider_ than a word at
>   this point, so we have:
> 
>     offset = 0
>     bitpos = bitnum % BITS_PER_WORD + BITS_PER_WORD - <bits in op0>;
> 
>   Then, inside the "if" statement we did:
> 
>     /* 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;
> 
>   where UNIT is still BITS_PER_WORD.  So we have:
> 
>     offset = 0
>     bitpos = (bitnum % BITS_PER_WORD + BITS_PER_WORD - <bits in op0>
>               + <bits in op_mode> - BITS_PER_WORD);
> 
>   which cancels to:
> 
>     offset = 0
>     bitpos = bitnum % BITS_PER_WORD + (<bits in op_mode> - <bits in op0>);
> 
>   As above, if the subreg code had updated BITNUM too, this would be
>   equivalent to:
> 
>     offset = 0
>     bitpos = bitnum + (<bits in op_mode> - <bits in op0>);
> 
>   but isn't as things stand.  The new code does update BITNUM:
> 
>     if (!MEM_P (op0) && ...)
>       {
>         ...set op0 to the word containing the field...
>         bitnum %= BITS_PER_WORD;
>       }
> 
>   and then calculates the final BITPOS directly:
> 
>     unsigned HOST_WIDE_INT bitpos = bitnum;
>     unsigned int unit = GET_MODE_BITSIZE (op_mode);
>     if (MEM_P (xop0))
>       ...
>     else
>       {
> 	/* Convert from counting within OP0 to counting in OP_MODE.  */
> 	if (BYTES_BIG_ENDIAN)
> 	  bitpos += unit - GET_MODE_BITSIZE (GET_MODE (op0));
>       }
> 
>   so both the following hold:
> 
>     offset = 0
>     bitpos = bitnum % BITS_PER_WORD + (<bits in op_mode> - <bits in op0>);
> 
>     offset = 0
>     bitpos = bitnum + (<bits in op_mode> - <bits in op0>);
> 
> 6) For REG, BYTES_BIG_ENDIAN, !BITS_BIG_ENDIAN:
> 
>   Like (5) but we also have:
> 
>     unit = GET_MODE_BITSIZE (op_mode);
>     if (BITS_BIG_ENDIAN != BYTES_BIG_ENDIAN)
>       xbitpos = unit - bitsize - xbitpos;
> 
>   This is the same as before, except that the UNIT assignment became
>   part of (5).
> 
> Hope I've got that right...
> 
> Of course, the idea is that the new code should make sense from first
> principles.  This was just trying to show that it isn't supposed to have
> changed the behaviour.

Thanks for the explanation (or rather the proof :-).  No objections by me.

-- 
Eric Botcazou

      reply	other threads:[~2012-10-23 21:39 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
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 [this message]

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=1760664.7SOE4dSe93@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).