<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 13, 2014 at 9:31 PM, Justin Bogner <span dir="ltr"><<a href="mailto:mail@justinbogner.com" target="_blank">mail@justinbogner.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="">> On Wed, Aug 13, 2014 at 7:42 PM, Justin Bogner <<a href="mailto:mail@justinbogner.com">mail@justinbogner.com</a>> wrote:<br>

><br>
</div><div class="">>     This leads to bad code being generated in most of our 32 bit backends.<br>
><br>
</div><div class="">> Also, cite your source. I tested this on ARM and x86 when I changed bitfields<br>
> to work the way they did before your patch and we generated very good code.<br>
<br>
</div>I was looking into some poor code generation on something like this:<br>
<br>
    typedef struct<br>
    {<br>
      unsigned int lsb32   : 32;<br>
      unsigned int msb7    : 7;<br>
      unsigned int padding : 25;<br>
    } P;<br>
<br>
<br>
    void foo(P *p) {<br>
      p->lsb32 = 0x0000;<br>
    }<br>
<br>
On armv7, this was giving pretty poor code. At -O0:<br>
<br>
        push    {r4, lr}<br>
        sub     sp, sp, #8<br>
        mov     r1, r0<br>
        str     r0, [sp, #4]<br>
        ldrb    r2, [r0, #5]<br>
        mov     r3, r0<br>
        ldrb    r12, [r3, #4]!<br>
        ldrb    lr, [r3, #2]<br>
        ldrb    r4, [r3, #3]<br>
        strb    r4, [r3, #3]<br>
        strb    lr, [r3, #2]<br>
        strb    r2, [r0, #5]<br>
        mov     r2, #0<br>
        strb    r2, [r0, #3]<br>
        strb    r2, [r0, #2]<br>
        strb    r2, [r0, #1]<br>
        strb    r2, [r0]<br>
        strb    r12, [r3]<br>
        str     r1, [sp]                @ 4-byte Spill<br>
        add     sp, sp, #8<br>
        pop     {r4, pc}<br>
<br>
and at -O3:<br>
<br>
        push    {lr}<br>
        mov     r2, r0<br>
        ldrb    lr, [r0, #5]<br>
        ldrb    r12, [r2, #4]!<br>
        ldrb    r1, [r2, #3]<br>
        ldrb    r3, [r2, #2]<br>
        strb    r1, [r2, #3]<br>
        mov     r1, #0<br>
        strb    r3, [r2, #2]<br>
        strb    lr, [r0, #5]<br>
        strb    r1, [r0, #3]<br>
        strb    r1, [r0, #2]<br>
        strb    r1, [r0, #1]<br>
        strb    r1, [r0]<br>
        strb    r12, [r2]<br>
        pop     {lr}<br>
        bx      lr<br>
<br>
Where with the change I've made here, we have -O0:<br>
<br>
        sub     sp, sp, #8<br>
        mov     r1, r0<br>
        str     r0, [sp, #4]<br>
        mov     r2, #0<br>
        strb    r2, [r0, #3]<br>
        strb    r2, [r0, #2]<br>
        strb    r2, [r0, #1]<br>
        strb    r2, [r0]<br>
        str     r1, [sp]                @ 4-byte Spill<br>
        add     sp, sp, #8<br>
        bx      lr<br>
<br>
and -O3:<br>
<br>
        mov     r1, #0<br>
        strb    r1, [r0, #3]<br>
        strb    r1, [r0, #2]<br>
        strb    r1, [r0, #1]<br>
        strb    r1, [r0]<br>
        bx      lr<br>
<br>
The code that's being generated is pretty awful, and it just gets worse<br>
if you add more to the bitfield.<br>
<br>
I'd briefly looked at i386 as well where I saw some extra instructions<br>
at -O0 and thought things were the same. Looks like the -O3 code is<br>
identical there though, so my claim about most of our 32 bit backends<br>
was a mistake. Sorry about that.<br></blockquote><div><br></div><div>Yea, I checked x86 pretty carefully when making this change.</div><div><br></div><div>I actually had done some tests on ARM as well, but they were much more limited (no hardware) so I can completely believe I missed something in that backend.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
So I guess there are two ways to handle this. The change I've made,<br>
which adds a small amount of complexity to the frontend in order to<br>
avoid generating IR that does a lot of redundant work, or teaching the<br>
arm backend that a read-modify-write that masks out most of the bits<br>
should be optimized to a narrower store. I haven't looked into how hard<br>
that option is.<br>
<br>
Do you think the backend approach will be simpler (or perhaps valuable<br>
enough in other situations that it's worth its cost)? If so, I'll revert<br>
this and try that approach out.</blockquote><div><br></div><div>I think the backend approach is essential.</div><div><br></div><div>There are *tons* of cases where we have wide loads with only a narrow amount of data used or wide stores with only a narrow amount of data actually non-undef. For example, any case we combine away *part* of the aggregate's operations.  It is really valuable to be able to narrow the memory accesses in the backend.</div>
<div><br></div><div>I think narrowing the loads and stores really needs to happen very late to maximize the information about the semantic model of the program in the IR. Now, this is predicated on us being *able* to do that narrowing. It was very easy in x86 (like, one tiny bug to fix, almost all of it "just worked") so I'm optimistic this is actually easy in general. Let me know if not though. </div>
</div><br><br></div></div>