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

    <tr>
        <th>Summary</th>
        <td>
            clang x86 missed optimization for 2 dimension array accessed through always zero enum class
        </td>
    </tr>

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

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

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

<pre>
    Given the following code [godbolt](https://godbolt.org/z/16fv1xzTr)
```cpp
enum class E {
 A = 0,
};

constexpr int t[1][1]{{1}};

int f1(E a) {
 return t[static_cast<int>(a)][static_cast<int>(a)];
}

int f2(E a, E b) {
    return t[static_cast<int>(a)][static_cast<int>(b)];
}
```

clang-trunk generates this assembly:
```asm
f1(E):                                # @f1(E)
        movsxd  rax, edi
        lea     rcx, [rip + t]
 lea     rcx, [rcx + 4*rax]
        mov     eax, dword ptr [rcx + 4*rax]
        ret
f2(E, E):                              # @f2(E, E)
        movsxd  rax, edi
        movsxd  rcx, esi
        lea rdx, [rip + t]
        lea     rax, [rdx + 4*rax]
        mov     eax, dword ptr [rax + 4*rcx]
        ret
t:
        .long   1 # 0x1
```

and this IR:
```asm
@_ZL1t = internal unnamed_addr constant [1 x [1 x i32]] [[1 x i32] [i32 1]], align 4, !dbg !0

define dso_local noundef i32 @_Z2f11E(i32 noundef %0) local_unnamed_addr #0 !dbg !23 {
  call void @llvm.dbg.value(metadata i32 %0, metadata !27, metadata !DIExpression()), !dbg !28
  %2 = sext i32 %0 to i64, !dbg !29
  %3 = getelementptr inbounds [1 x [1 x i32]], ptr @_ZL1t, i64 0, i64 %2, i64 %2, !dbg !29
  %4 = load i32, ptr %3, align 4, !dbg !29, !tbaa !30
  ret i32 %4, !dbg !34
}

define dso_local noundef i32 @_Z2f21ES_(i32 noundef %0, i32 noundef %1) local_unnamed_addr #0 !dbg !35 {
  call void @llvm.dbg.value(metadata i32 %0, metadata !39, metadata !DIExpression()), !dbg !41
  call void @llvm.dbg.value(metadata i32 %1, metadata !40, metadata !DIExpression()), !dbg !41
  %3 = sext i32 %0 to i64, !dbg !42
  %4 = sext i32 %1 to i64, !dbg !42
  %5 = getelementptr inbounds [1 x [1 x i32]], ptr @_ZL1t, i64 0, i64 %3, i64 %4, !dbg !42
  %6 = load i32, ptr %5, align 4, !dbg !42, !tbaa !30
  ret i32 %6, !dbg !43
}

declare void @llvm.dbg.value(metadata, metadata, metadata) #1

attributes #0 = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

```

While gcc-trunk generates just:
```asm
f1(E):
        mov     eax, 1
 ret
f2(E, E):
        mov     eax, 1
 ret
```

Interestingly using just a plain enum without static_cast's clang generates the optimal code [godbolt](https://godbolt.org/z/YWW53Pv8z). But with the static_cast's it still doesn't [godbolt](https://godbolt.org/z/o35nrx966).

Using `__builtin_unreachable()` to explicitly tell the compiler that `a` and `b` are `E::A` works for `f1()` but strangely not for `f2()` [godbolt](https://godbolt.org/z/zosco43EW).
But using `__builtin_assume(...)` works for both [godbolt](https://godbolt.org/z/WvzP99TET).
Declaring the storage type of enum class `E` to `unsigned short` or `unsigned char` also fixes the problem [godbolt](https://godbolt.org/z/cW6eKdxG4) same goes for casting to `unsigned short` or `unsigned char` [godbolt](https://godbolt.org/z/8h3T8qhco).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy0WN1u4zjSfRr6pmBDoixZvvBFHCeDxvctMNjpRbB7E1BUWeI0RWpJKpbz9AtStvyTn457Zw0jYsiqOsXDo1LJzFpRKcQVSdck3UxY52ptVnd_-4PGk0KX-9Vv4gUVuBphq6XUO6Eq4LpEIOm60mWhpSPphtC8dq61JLkj9JHQx8PSTJuK0MdXQh_jbPsS96_fDaFLEm1IdEeyaPjyth1mUHUNcMmshQcgi_UwC3dAkg1EhN4fHBcbkhwWh79cK-uwbw0I5cCRdB37rA6XxZos1rH3euPozbcxofkDMEKXZ6AGXWdUiGUdc4I_c2YdSe6FciR5IDT3DgPKTwxGyMXmDTY9Yt_DAxSXKQD8FVkUH2Zx5P-CSclUNXWmUz-gQoWGObTgamGBWYtNIff-kC8DMNsMMwOVHjAJ6X_2ITQBMo9OLuOm_afRL7YvAQzrPTdYist1iSxcDQ_rJF0b0QKhawh6HGzfMeJ9MJoTeudDj6Yn2HDFAbbcaVNC68xXfA26Awt02NI9fImKIxGXXjexMa4PG0X7Dlum_ISpa1bZaFv-F4SxM1_-CWFulNRxaSa1qgAgDuxEffyJZJkqB4F--_sn0iTz6Plf_x-7UEuEcmgUk9ApxRosn1lZGghVhCnnc4-hP15EQsMNtoFQJc_m_IRIKAzFZuMJYFJUyu_4HgiNy6Lyl4t0S9wKhVBa_Sw1ZxKU7lSJWx8TQpZ0G8f-zvUTx0VC08hXh-DyfJE2oUl0BubVdCohnEkJL1qUPrSUL82sLKrZC5MdEpo36FjJHBuwA8Q9jJM-2OJ6ZvPtoW8NWiu0IjT3UvXf8-3S_IhOaEoD4RZ7N4KA0yCyK45Okic0TYJThQ4lNqicF5RQhefCfnQ6PlwQ3uGg_f8im4fnRhj4ZK7HH-DPA77UrAzxj5Fpmnx4xiMJrmCBqCQ6BjQ47v3KKZm_-2T4ikRo_PDH87siuYerufhrwknSv1A4yfIXhDOPfw09vsaav8nnJvRRgT-X7Zy-kc25U_xzp_R_pPXkbPwZfvaR1tMPtT6nX9F6duWUfKB1LpnBnx_2-YlejpdeyfHFI8E5I4rOty6DyJON1zY0nXWt0ZUXAii9NYigtEHeGetHdq94uHN2QpWwE1IeGrAGG232hOZKK_SI3c6xQiIQShuhphIrJqcvyJ02050oXU0oJcmGUBoR6umgSk-dYW0rVDVt2JmBM36fwcY6xn9MW6PdEKnotls0UytecTTPD7aOmQrdlLfduNTn2dRr7Xx9i8x1Bu1oROia97lvpul621szjJqmHwbW4jigw6jPF8eYncILxNAiCh6Wj-d6SX48kq98BZIF4z9O1F8SblvknWQDs5-xf6Whd9uCp1pIhIrzN93sn511X2xiP2124tOrwgeN323u727jm29V0DqhKrmHzvoXML8BYNBKJhSEl6adcLXuHJy_A9CFhdDOXzTyCLp1omHy117j_vn0lCa_v-SvhC5nsO5cgA5xr7GFT0dICaVGqwhduJvRdJIq0y-zzKOds_KPwAPJoufnohPSCfXcKYOM1147hwKfhZKNfSsFF07uwaGUIVWum1ZINOBq5nwY5o19I0myqAhjg3784JNL7vzRwE6bHxa22viFIJIDSBGIN0xVKPegtBuN6Mno1q2_asv1PHl4Om3ds9293Tiztmv8nmez2QHslGqhXX0z9tPL6-_L5feH7yfsTSjTHns4am1YheD2LYLewtmLeyBtYJ5kUafCDwwl2Fob5-cHZsZ5XjMT-JZWw1b0B422RhcSm5sz508Z_l_Z_zb3VcKyBqHSODDhdRnyvy2xWzPI6-R7_u-aa8_dpFwl5TJZsgmu4myxnOeUpotJvWKYRozHNKJlvlzMM15GecmTPKf5YhGn6USsaESTKKE0jtIoXczYdhnxeLnNCzaPcJuQeYQNE3IWHpjaVBNhbYerLM7idCJZgdKGn3UoVbiDsOjLdrqZmJX3mRZdZf0DV1hnT1GccBJXQ93o8wwaYS2WQ9EQr8wJrQKdFErRoPL9FDBj2B4Y5xhsXW10V9XA5I7tLbyi0WcKmXRGrq5YFK7uihnXDaGPPpPDxT8J_0TuCH0M-VtCH8P-_hMAAP__iP5ODw">