<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/55084>55084</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Spectre-v1 safety: How to prevent merging of asm volatile
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          andyhhp
      </td>
    </tr>
</table>

<pre>
    Upstream patch/discussion: https://lore.kernel.org/xen-devel/20220425175603.21086-1-andrew.cooper3@citrix.com/
Godbolt example: https://godbolt.org/z/a3c94e61W

Xen has a construct called `evaluate_nospec()` for Spectre v1 safety, which does it's hardest to insert `lfence` instructions at the head of both basic blocks following a conditional jump.  This is attempted with:
```c
static always_inline bool barrier_nospec_true(void)
{
    asm volatile ("lfence" ::: "memory");
    return true;
}
static always_inline bool eval_nospec(bool cond)
{
    return cond ? barrier_nospec_true() : !barrier_nospec_true();
}
```
which is intended to be used with code such as:
```c
void test(int x)
{
    if ( eval_nospec(x) )
        asm volatile ("nop #nospec-if");
    else
        asm volatile ("nop #nospec-else");
}
```
to generate code such as:
```asm
test:                              # @test_good
        testl   %edi, %edi
        je      .LBB1_2
        lfence
        nop
        retq
.LBB1_2:
        lfence
        nop
        retq
```

However, this doesn't compile as expected under Clang.  Clang chooses to merge both sides of the ternary in `eval_nospec()` and hoist the the `lfence` up ahead of the `je`, resulting in:
```asm
test:                               # @test_bad
        lfence
        testl   %edi, %edi
        je      .LBB0_2
        nop
        retq
.LBB0_2:
        nop 
        retq
```
which is no longer Spectre-v1-safe.

After some experimentation, it turns out that putting different comments in the `asm volatile()`'s prevents the two sides being merged, which has intended safety property.  But this is also very fragile.

Is there a supported way of ensuring the two `asm volatile()`'s don't get merged, which isn't as hacky as depending on magic comments?  If not, can we discuss how to create a supported way of adding Spectre v1 safety which the optimiser won't interfere with?
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJylVk1z4zYM_TX2BWOPJH_EPviQbCa7O9Nb22lvGZqEJCYUqSUpf_TXF6BkJ06cpts6dkyTFPCABz5w69Rx83sbokfRQCuirEfFg9JBdiFoZ0ezW6hjbAMNaIHexnmcPqO3aKbOVzRzQDtRuEND4yIrimxeLPKbxTKbTYs8Wy0n-URY5XE_lc616GejeSZ19PpAEw1bze5H2e1Xp7bORMCDaFqD7z1X_YbB61_0ETO5nuMy_6O30P__Ey3UIoAA6SwF1skIUhiDCkbLDHfCdCLio3WhRTkqVqNiTfNQOg-_0gxlAnY5BFFiPI6KL7CvtaxBOQyg46i4CWTdKwwRogNtA_rIhk2JViJb0oNXSh-hoG01Qo1CgSth62INWxG0hK1x8jmQX2PcXtuqB6w0PycMPHVNOwX4rdbkl-1EbNpIQex1rDknfcjLrH_L_neIIpJtYfbiGB61NdoiOXWGnHqv0Q9xPxJCpOB3TitOQG_s5q4fAL1EaGDnDJkzCClNxRBiUQD7T29aKRpsnKdUFWxo9sqEx9h5C8nVaX50c_8ZUqbohZ40xYm5DnPwwRsI1cMHYdKz0KPNP9zwHuI5uf3PvhCYDhvRKqKCCmCL0IWBFUKhEEJHu0T4kCJOOUSqH3JLluBwPTBdctbfJOOQAjnth-F1hSrrWhrN-gcnurzCDpqAP2knPXJp6aNkUWoqtOjpqH2SFvI6PMI5mZ3RXH8RGCD94L2PlXPqMgKeNmnXApXm0zuMLnY9Yf89_eXuLn8sLheHIr-YoyxcTlDV_ehnTjZOYf1HM2-y1___5vYkq57DiCwDrEGWFIj0zDUtk0QyhwcWLarAjkrSwxcjbEW6kb5B1s4FEi5io0FfYa8_QZN8sRqxMkWScuGPVNQneXwnjaTeUDsdeinjz4XedS2Ik74Ni0-8wLg9hs5EVjdt_y_1F9xvhfo84T9fDtnbcviE-uwK9enM_Duez5JiHRhnKzz3oMkun3APmr4uiNuS2ILgGky0e92gZRmlPk2xaeKHtJCY7Zgp6jxtF1PulS5L9LSXC4efYQ07cfX61J85T32u9VR-vDnRvndD4WyRbaZ6Ui8NklvuWRj77kkGuN_HI9XjXcI09DITHFBhH6H0oiK3F0F-T_6oCwvSjLZ1PjU9ceTyQhs6z95PiP4Rv3L9aakwvoOrh5MkuJ3L5yMPFLYEn807Cw0hk-d8cWuB7yXxFNmGFBb2CMM9iQ7Hno-YpEtUvIpbqGT23f1iAMPRuDbqRtNtAvYDbM6mZ96Glv8wVpuZWs_WYhx1NLh5KZXTdYWO0Lcey8BdijtFVF7I-7jzZvPmekVOuu1wJTNmd_qaEItP5Ih-6hA6DDRYLLLVfFxvypkspJB0-PP5rMQyV_NynZUrtVrMc_obG7GlprEZLe64meAekgnuIYv7sd6crotFnq-L5ZRui6qQ-Xq1kCuxpoY5z7AR2kwZB9_7xn6TIG27KtCiIU0KL4uCrqyVRUzuyL7oYu38huTrWNftOLneJOh_A2ruUpU">