<div dir="ltr">At least in this test-case, the "bitfield" part of this seems to be a distraction. As Eli notes, Clang has lowered the function to LLVM IR containing consistent i16 operations. Despite that being a different choice from GCC, it should still be correct and consistent.<div><br></div><div>Of course that insight does mean it's quite easy to create a test-case with the exact same problematic store->load mismatch which doesn't use bit-fields at all. For example:</div><div>short f2(short *bfs) {<br>    *bfs &= ~0x1;<br>    g();<br>    return *bfs;<br>}<br><div><br></div><div>creates the same bad sequence:</div><div>        movq    %rdi, %rbx<br></div><div>        andb    $-2, (%rdi)</div><div>        callq   g()<br><div><div class="gmail_quote"><div dir="ltr" class="gmail_attr">        movzwl  (%rbx), %eax<br></div><div dir="ltr" class="gmail_attr"><br></div><div dir="ltr" class="gmail_attr">On Tue, May 26, 2020 at 9:30 PM John McCall via llvm-dev <<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><u></u>




<div>
<div style="font-family:sans-serif"><div style="white-space:normal">
<p dir="auto">On 26 May 2020, at 20:31, Arthur O'Dwyer wrote:</p>

</div>
<div style="white-space:normal"><blockquote style="border-left:2px solid rgb(119,119,119);color:rgb(119,119,119);margin:0px 0px 5px;padding-left:5px"><p dir="auto">On Tue, May 26, 2020 at 7:32 PM John McCall via cfe-dev <<br>
<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:<br>
</p>
<blockquote style="border-left:2px solid rgb(153,153,153);color:rgb(153,153,153);margin:0px 0px 5px;padding-left:5px"><p dir="auto">On 26 May 2020, at 18:28, Bill Wendling via llvm-dev wrote:</p>
<blockquote style="border-left:2px solid rgb(187,187,187);color:rgb(187,187,187);margin:0px 0px 5px;padding-left:5px"><p dir="auto">[...] The store is a byte:<br>
<br>
    orb    $0x1,0x4a(%rbx)<br>
<br>
while the read is a word:<br>
<br>
    movzwl 0x4a(%r12),%r15d<br>
<br>
The problem is that between the store and the load the value hasn't<br>
been retired / placed in the cache. One would expect store-to-load<br>
forwarding to kick in, but on x86 that doesn't happen because x86<br>
requires the store to be of equal or greater size than the load. So<br>
instead the load takes the slow path, causing unacceptable slowdowns.</p>
</blockquote><p dir="auto">[...]<br>
<br>
Clang used to generate narrower loads and stores for bit-fields, but a<br>
long time ago it was intentionally changed to generate wider loads<br>
and stores, IIRC by Chandler.  There are some cases where I think the<br>
“new” code goes overboard, but in this case I don’t particularly have<br>
an issue with the wider loads and stores.  I guess we could make a<br>
best-effort attempt to stick to the storage-unit size when the<br>
bit-fields break evenly on a boundary.  But mostly I think the frontend’s<br>
responsibility ends with it generating same-size accesses in both<br>
places, and if inconsistent access sizes trigger poor performance,<br>
the backend should be more careful about intentionally changing access<br>
sizes.<br>
</p>
</blockquote><p dir="auto">FWIW, when I was at Green Hills, I recall the rule being "Always use the<br>
declared type of the bitfield to govern the size of the read or write."<br>
(There was a similar rule for the meaning of `volatile`. I hope I'm not<br>
just getting confused between the two. Actually, since of the compilers on<br>
Godbolt, only MSVC follows this rule <<a href="https://godbolt.org/z/Aq_APH" style="color:rgb(119,119,119)" target="_blank">https://godbolt.org/z/Aq_APH</a>>, I'm<br>
*probably* wrong.)  That is, if the bitfield is declared `int16_t`, then<br>
use 16-bit loads and stores for it; if it's declared `int32_t`, then use<br>
32-bit loads and stores.</p>
</blockquote></div>
<div style="white-space:normal">

<p dir="auto">I’ve always liked MSVC’s bit-field rules as a coherent whole, but they are<br>
quite different from the standard Unix rules.  On Windows, <code style="background-color:rgb(247,247,247);border-radius:3px;margin:0px;padding:0px 0.4em" bgcolor="#F7F7F7">T x : 3</code><br>
literally allocates an entire <code style="background-color:rgb(247,247,247);border-radius:3px;margin:0px;padding:0px 0.4em" bgcolor="#F7F7F7">T</code> in the structure, and successive<br>
bit-fields get packed into that <code style="background-color:rgb(247,247,247);border-radius:3px;margin:0px;padding:0px 0.4em" bgcolor="#F7F7F7">T</code> only if their base type is of the<br>
same size (and they haven’t exhausted the original <code style="background-color:rgb(247,247,247);border-radius:3px;margin:0px;padding:0px 0.4em" bgcolor="#F7F7F7">T</code>).  So of course<br>
all accesses to that bit-field are basically of the full size of the <code style="background-color:rgb(247,247,247);border-radius:3px;margin:0px;padding:0px 0.4em" bgcolor="#F7F7F7">T</code>;<br>
there’s no overlap to be concerned with.  On Unix, bit-fields will typically<br>
get packed together regardless of the base type; the base type does have<br>
some influence, but it’s target-specific and somewhat odd.</p>

<p dir="auto">I’d prefer if we degraded to a Windows-like access behavior as much<br>
as we can, but it’s not always possible because of that packing.</p>

<p dir="auto">John.</p>
</div>
</div>
</div>

_______________________________________________<br>
LLVM Developers mailing list<br>
<a href="mailto:llvm-dev@lists.llvm.org" target="_blank">llvm-dev@lists.llvm.org</a><br>
<a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev</a><br>
</blockquote></div>
</div></div></div></div>