| 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