Issue 124225
Summary clang doesn't perform case lifting
Labels clang
Assignees
Reporter ryani
    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).
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to