On 06/11/2018 01:40, Segher Boessenkool wrote:
> Hi Richard,
> 
> On Mon, Nov 05, 2018 at 10:09:30AM +0000, Richard Earnshaw (lists) wrote:
>>>>> Shouldn't you be able to do this per function at least?
>>>>
>>>> do what per function?  track speculation?
>>>
>>> disable shrink-wrapping only when any speculation was there
>>> (this is about __bultin_speculation_safe_value, no?)
>>
>> Only indirectly.  This is about the tracking code that tracks
>> conditional branches and propagates that information through call/return
>> sequences.  Shrink wrapping messes with the prologue/epilogue sequences
>> after the speculation tracking pass has run and unknowingly deletes some
>> of the additional code that was previously inserted by the tracking pass.
> 
> Do you have an example of this?  Shrink-wrapping does not generally
> delete any code.
> 

Well it generates new 'light-weight' prologue and epilogue sequences for
the 'shrunk' code path that lack the establishment of the tracker
register and doesn't know how to move the existing sequence to the new
entry sequence.

Consider this (trivial shrink-wrap case).

int f ();

int g (int a)
{
  if (a > 3)
    return f() + 4;
  return a;
}

Without speculation tracking we get (sorry, aarch64, hope you can follow
this):

g:
        cmp     w0, 3
        bgt     .L8     // a > 3
        ret
        .p2align 2
.L8:
        stp     x29, x30, [sp, -16]!
        mov     x29, sp
        bl      f               // f()
        add     w0, w0, 4       // + 4
        ldp     x29, x30, [sp], 16
        ret

With shrink-wrapping and speculation both enabled, we get the following
code:

g:
        cmp     sp, 0
        csetm   x15, ne  // Establish tracker - OK
        cmp     w0, 3
        bgt     .L8
        // tracker not updated, speculation state not re-encoded in SP
        ret
        .p2align 2
.L8:
        stp     x29, x30, [sp, -16]!
        csel    x15, x15, xzr, gt  // tracker updated for branch
        mov     x14, sp
        mov     x29, sp
        and     x14, x14, x15     // Encode speculation status in SP
        mov     sp, x14
        bl      f
        add     w0, w0, 4
        cmp     sp, 0            // extract speculation status from call
        ldp     x29, x30, [sp], 16
        csetm   x15, ne
        mov     x14, sp
        and     x14, x14, x15   // And re-encode it in return sp
        mov     sp, x14
        ret

So although this code executes correctly from an architectural
perspective, if the early return path is taken speclatively, the caller
receives incomplete information about the speculation that has taken place.

And if we disable shrink wrapping, then obviously things work as
originally intended:

g:
        cmp     sp, 0
        stp     x29, x30, [sp, -16]!
        csetm   x15, ne         // establish tracker
        mov     x29, sp
        cmp     w0, 3
        bgt     .L5
        ldp     x29, x30, [sp], 16
        csel    x15, x15, xzr, le  // Update tracker for branch
        mov     x14, sp
        and     x14, x14, x15
        mov     sp, x14         // tracking encoded into SP for return
        ret
        .p2align 2
.L5:
        csel    x15, x15, xzr, gt  // As above.
        mov     x14, sp
        and     x14, x14, x15
        mov     sp, x14
        bl      f
        add     w0, w0, 4
        cmp     sp, 0
        ldp     x29, x30, [sp], 16
        csetm   x15, ne
        mov     x14, sp
        and     x14, x14, x15
        mov     sp, x14
        ret

I'm not asking that shrink wrapping be updated to handle all this; in
fact, I'm not sure it's that easy to do as the branch patterns and
simple-return patterns aren't set up to handle this.

R.

> 
> Segher
> 

Reply via email to