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

    <tr>
        <th>Summary</th>
        <td>
            clang doesn't perform case lifting
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang
      </td>
    </tr>

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

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

<pre>
    Both gcc and msvc perform this optimization.

Compiler explorer link: https://godbolt.org/z/nxv9bTohe

```
#include <utility>

struct N
{
 int val;
    N* left;
    N* right;
};

enum class D
{
    here, pleft, left, pright, right
};

template <typename F> N* search( N* root, F&& dir )
{
    N* cur = root;
    N* best = nullptr;

    while( cur != nullptr ) {
        switch( std::forward<F>(dir)(cur->val) )
        {
 case D::here:
                return cur;
            case D::pleft:
                best = cur;
                [[fallthrough]];
 case D::left:
                cur = cur->left;
 break;
            case D::pright:
                best = cur;
 [[fallthrough]];
            case D::right:
                cur = cur->right;
                break;
            default:
 std::unreachable();
        }
    }

    return best;
}

N* find( N* root, int n )
{
    return search( root, [n]( int val ) {
        if ( n < val )
            return D::left;
        else if( n == val )
 return D::here;
        else
            return D::right;
 });
}
```

clang correctly determines that the lambda in `find` can only return 0, 2, or 4, and uses that to eliminate the pleft and pright cases from the switch, as well as realizing that nothing can mutate `best` and therefore if the loop exits normally that the result must be NULL.  But it doesn't take the next step and realize that the codepath from the `n < val` branch can only go to the `D::left` case, and so on.

In the compiler explorer link I have a manually fused version, and a version where I've manually performed inlining and the case lifting optimization.  Both of these clang does a fine job with (although gcc generates slightly better code).
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJyMVtGO2joTfhpzMyoKDoTlIhcsFKlS1av_fwAnmRC3jh3ZE1j69EfjJAR2tz0nQjh2xt9883nGtgpBny1iLjavYnNcqJ4a53N_U1YvClfd8ldHDZzLEpStoA2XEjr0tfMtUKMDuI50q38r0s4uRbIXyf7g2k4b9IBvnXEePRhtf4l0Dw1RF0S6F_Ik5OnsqsIZWjp_FvL0W8iTfbvsiv-5BgcgkSXjL9kLmWpbmr5CEOmhJ2003UT6dbAM5PuS4Af3tq8i2YO2BBdlRBp7APBDyD0YrOndkNfnZhwT2-P4kuzR9i2URoUAxxkVABr0KOQBuoglDzC13YAkDyPkMx5h2xlFkT3dOrSqRTiJ9OvAIqDyZSPky0jKuYh0EjITMoNKexBy90QkGpa9B5EehwnPgRUYKH6zvTEd-TsVtrg22iC7iwBy9WDHjmB2w0-4ahrYBap4_dJ97fxV-UqkBw5CyJdKe2YoX8refxHpVxafgSLrCWiELVVAOA5AUc90_2A0PR6p95YZzpFNzyPCsBKfQtw1-BQkMuK8f62VMdR4158bsTnyL_1A9M9epkUYI39IssKj-vUv7McE_I_0_873Dz7-4uId94dq-EDm81gqrFVvJvR7fvTWoyobVcQ04yx4msmlMfSGt7EzLjnHPZdk_BpTuta2-lAjXOn2Q3WMSHNdTeZi82pZMPky7RGfJLyugQ0sV-tk8i7u0cFTcjxCoAkIup5gjizyA9Lz9KEI3k__q8fHlWKVJoVHxR63zmRfGmXPUDrvsSRzgwoJfastBqBGEVCDYFRbVAq0BZElUeksgVJZcNbcJucJSyj5z3lYc8vHQh_uQA7Q6FZb3uoYNRZnNBoSPeZlgNq7Nn6ftpYDqABXNIZbj8ro39qeB1DrqOEOk2l7irtolsQkyZKITSxg7TwrPgTjXAf4pimAdb5VxtzmSD2G3hC0fSAoEH78__v3JcBrT6AJKofBCrklIPVriMHiG0Eg7KKvgRzOcKWrsFPUzEGJLLmnDlMsvLJlM4t5dizUaPmYQVHxgJOuwcH9VP1mR2efHa7wDRp1QVDQKtvHaOs-YAUX9EE7OwGqaQCurBh8E3J7wXnSeLRjBdoabVn0Ud5hPzG6Jh58OvUB4h3BReUDwpBsrCMoLlmEn66Aq6aGi0oZanjfineKM1r0ijBAMJwd5gYFEqGPogq5Wy6qPK126U4tMF9t0222k4nMFk1eV0mRYb3Ldtkqq5PdKklfdnJVq7IqXhCzhc5lIjfJSq6T9SpdZ0tZZpvNqi7TclvJdKvEOsFWabM05tLyLWShQ-gxX8m1lJuFUQWaEC9GUsaYhJR8R_I5T_hS9Ocg1onRgcIMQZoM5rMEQypNV6ZHERe9N_m7G5Gmpi-WpWuFPDHk2HzpvPuJJQl5ihSDkKeR5SWX_wQAAP__Dnffsg">