llvm / llvm/llvm-project

[X86] `movmsk(por(andn(bits,mask), andn(bits,mask)))` gets pessimized

Open
#205,663 4 comments 0 reactions 1 assignee Claimed by @RKSimon View on GitHub
backend:X86 missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

https://c.godbolt.org/z/7YYEz9r51

This code:

```c
#include
#include
int any_signaling_nan(double* src, uint64_t n) {
for (uint64_t i = 0; i < n; i += 2) {
__m128i a = _mm_loadu_si128((void*)(src + i*2));
__m128i b = _mm_loadu_si128((void*)(src + i*2 + 2));
__m128i a_nan = (__m128i)_mm_cmpunord_pd((__m128d)a, (__m128d)a);
__m128i b_nan = (__m128i)_mm_cmpunord_pd((__m128d)b, (__m128d)b);
__m128i a_bad = _mm_andnot_si128(_mm_slli_epi32(a, 12), a_nan);
__m128i b_bad = _mm_andnot_si128(_mm_slli_epi32(b, 12), b_nan);

__m128i any_bad = _mm_or_si128(a_bad, b_bad);
if (_mm_movemask_pd((__m128d)any_bad) != 0) return 1;
}
return 0;
}
```

on baseline x86, compiles to a core loop of:
```asm
.LBB0_5:
movupd xmm2, xmmword ptr [rdi - 16]
movupd xmm3, xmmword ptr [rdi]
movapd xmm4, xmm2
cmpunordpd xmm4, xmm0
movapd xmm5, xmm3
cmpunordpd xmm5, xmm0
pslld xmm2, 12
pslld xmm3, 12
pand xmm2, xmm4
pandn xmm4, xmm1
por xmm4, xmm2
pand xmm3, xmm5
pandn xmm5, xmm1
por xmm5, xmm3
pand xmm5, xmm4
movmskpd ecx, xmm5
cmp ecx, 3
jne .LBB0_6
add rax, 2
add rdi, 32
cmp rax, rsi
jb .LBB0_5
```
which is four more SIMD instructions than the literal translation (which gcc produces); seems the 2\*+`pandn`+`por` gets compiled to 2\*`pandn`+3\*`pand`+2\*`por`.

(for a slightly-more-reduced version, the `_mm_slli_epi32`s can be replaced with their first argument, so it's not the unusual element width transition)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.