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

    <tr>
        <th>Summary</th>
        <td>
            `if`-chain vs `switch` code generation
        </td>
    </tr>

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

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

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

<pre>
    All these code samples do the same and I would have expected them to generate essentially the same code but they are all different:

```cpp
int f0(const char c)
{
    if (c == ' ' || c == '\0')
        return 2;
    if (c == '|')
        return 1; 
    return 0;
}
```

```asm
f0(char):                                 # @f0(char)
        xor     ecx, ecx
        cmp     dil, 124
 sete    cl
        test    dil, -33
        mov     eax, 2
 cmovne  eax, ecx
        ret
```

The best code according to `llvm-mca`.

```cpp
int f1(const char c)
{
    switch (c) {
        case ' ':
        case '\0':
            return 2;
 case '|':
            return 1;
    }
    return 0;
}
```

```asm
f1(char):                                 # @f1(char)
        mov     eax, 2
        test    edi, edi
        je .LBB1_5
        cmp     edi, 32
        je      .LBB1_5
 cmp     edi, 124
        jne     .LBB1_4
        mov     eax, 1
 ret
.LBB1_4:
        xor     eax, eax
.LBB1_5:
 ret
```

Adds compares and branches.

```cpp
int f1a(const char c)
{
    switch (c) {
        case '|':
            return 1;        
        case ' ':
        case '\0':
            return 2;
    }
    return 0;
}
```

```asm
f1a(char): # @f1a(char)
        test    edi, edi
        je .LBB2_4
        cmp     edi, 124
        je      .LBB2_2
 cmp     edi, 32
        jne     .LBB2_5
.LBB2_4:
        mov eax, 2
        ret
.LBB2_2:
        mov     eax, 1
 ret
.LBB2_5:
        xor     eax, eax
 ret
```

Leads to different code than `f1()` since the order of the cases matters. I always thought that's why you should prefer a `switch` over an `if`-chain.

```cpp
int f2(const char c)
{
    switch (c) {
        case ' ':
        case '\0':
            return 2;
 }
    if (c == '|')
        return 1; 
    return 0;
}
```

```asm
f2(char):                                 # @f2(char)
        mov     eax, 2
        test    edi, -33
 jne     .LBB3_1
        ret
.LBB3_1:
        xor     eax, eax
 cmp     dil, 124
        sete    al
        ret
```

Not the same as `f0()` but better as `f1()`. I would not have expected that splitting up a `switch` leads to more efficient code.

GCC produces generally worse code but appears to be more consistent

https://godbolt.org/z/E7rso66n3

There's even more fun if such code is part of a bigger function. That's how I arrived at this. I had to extract that into a separate function and in some case change the code used in `f0()` to the one used in `f2()` to get better generated code. I have not yet been able to reduce those other cases yet but they are not in the scope of this ticket anyways.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMl01v2zgTxz8NfRnEkChbcg4-NMnjBwWKPfVejKiRxa5ECiRlx_vpF6RebDlv3iLFrpBEMYdD0uTvP5xBa-VeEW3Z-oGtnxbYuUqbbSkNHfFAi1wXp-2XugZXkSUQuiCw2LQ1WSi0b_UfCVAV8BWOuqsLqPBAQM8tCUeF79KA07AnRQYdAVlLykms69PZPwycd863nAANAdY1FLIsyZByLPnCoicWjX_TqP8Rbdu3SOWgjBjfCK2sA1GhAcH4_dA_e-j_AQCQJfh-wJInljwB41n_mz2y7BEu29n6MfKvcRgYHkOuMwo4S94d1o_4tnfMkgc4W4bWaBqTZU9XX_bVHUDb9C39t6_Q-AmTabY3H8YTYKto5jZb57M24U3imfHH8JrZRdOGdyFrb4_5arBbchQ61HMHR9ZdONwlydze6EM_IYYJ-WAVjT4omppfrMOQe2ejvlcEuZ84EIZCaFNItfdEsjSq60Nz1whkabS8AbD4JsDsUTpRBRoYv4eZLewLWhqxm8C-No7sXdtf52_y6pF7xymeQTtB9jkIxr-GYPwWgm8QccUTFTKAUci5_SfB8tvDQ_xj_Tq4g1_CX7iFZ-575XSmffRSdOG1evd7xIN1Ind0uj63SYID-vh82X997v--Br4UhQWhmxYN2RCqc4NKVGRvgh4_lfrbEJ0Q-d3K-Q0iwLkKJsrxLcxvBJlfY_Uhkxck8x_8dZJf4H8BMh_xH6e_3lMP9uvinLHtJ3_N9SNN8EvGP9DEBxr4RlhYH_WnnKK_EVyFyt8EIQj5k0kjsFIJCrmJNgUZ0GX44AGz0KBzZOwSvgLWRzxZcJXu9pVPXdAxnlk4Vic46Q5sFfKh1lBJBtBP06vET6IPvi3MLUuWRneiQqluEST_r95CMyH96_kQ_7XLiH_KZXRObi71lPyI31GJt95M-5vZ1_CMSRjW_yRb-kO7i5zeBmFEZ2H4BD0nz_9oPKtmOeX_SrsXNQA6sG0tnfO5V9dei6Ee1dloQ0BlKYUcJTqTxP8fH6E1uugE2aGk8HXEURt7UURg2xKaMGBO_ZheMNI6X0tcDFc511q_6XzH-G6vi1zXbqnNnvHdX4zv_pcZq9NUJVcppaEgdDqQ6ocvO-WJt52o-mVICy0a52MHQi73ezK-k3BSqyV8H0NFpY8-kBgjD1QA-t2XIbZUWPjl07MzKPrYAlI5DQiWWgyV1DheuNKlAqubPkr5wKD2fQgLq-kshR5X5-n6Ck6reQ8-67Gn6dDHGq7oDyYs80DhwE-hFynAvCbvZsgfkg-OlkC7iswQQEPPy0rPu0vVcyd0S328lRacFH-SA1QnH2eXi2KbFPfJPS5oG6f3q026WcXxotqu0iIiWos1iSzFMlqna7FZpSVuMrHBeLOQWx7xJLqP05iv0nW8zLI0wzKPcp6KeLNJ2CqiBmW99AWBP_-FtLajbZqus9WixpxqO5bIZhuqhrzbW7aKammdPbs56WrazmM6HOyc9nAkw15KrRadqbdXJEpXdflS6IbxnR98eN21Rv8k4RjfhQVaxndhjX8HAAD__w36KeI">