https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86909
Bug ID: 86909 Summary: Missing common subexpression elimination for types other than int Product: gcc Version: 9.0 Status: UNCONFIRMED Keywords: missed-optimization Severity: normal Priority: P3 Component: middle-end Assignee: unassigned at gcc dot gnu.org Reporter: antoshkka at gmail dot com Target Milestone: --- Consider the following minimized example of the std::variant visitation: using size_t = unsigned long long; struct A {}; static const size_t variant_npos = -1; struct variant { A a; using __index_type = unsigned char; // !!!! __index_type _M_index; size_t index() const noexcept { return (_M_index == __index_type(variant_npos) ? variant_npos : _M_index); } }; template<size_t _Np> static A* get_if(variant* __ptr) noexcept { return (__ptr->index() == _Np ? &__ptr->a : nullptr); } A* foo(variant& in) { int i = in.index(); if (i==0) return get_if<0>(&in); if (i==1) return get_if<1>(&in); if (i==2) return get_if<2>(&in); if (i==3) return get_if<3>(&in); if (i==4) return get_if<4>(&in); if (i==5) return get_if<5>(&in); if (i==6) return get_if<6>(&in); return get_if<7>(&in); } GCC generates assembly with multiple comparisons: foo(variant&): <...> cmp ecx, 1 je .L4 cmp ecx, 2 je .L4 cmp ecx, 3 je .L4 cmp ecx, 4 je .L4 cmp ecx, 5 je .L4 cmp ecx, 6 je .L4 cmp dl, 7 je .L4 Clang eliminates the subexpressions: foo(variant&): # @foo(variant&) movzx ecx, byte ptr [rdi + 1] cmp cl, -1 mov edx, -1 cmovne edx, ecx cmp edx, 7 jb .LBB0_2 mov dl, 7 .LBB0_2: xor eax, eax cmp cl, dl cmove rax, rdi ret Note that if we change `__index_type` to `int` then GCC generates great assembly: foo(variant&): mov edx, DWORD PTR [rdi+4] xor eax, eax cmp edx, -1 je .L1 cmp edx, 7 cmovbe rax, rdi .L1: ret