llvm / llvm/llvm-project

Simple mask operations with AVX512 degrade to scalar operations

Open
#206,722 4 comments 0 reactions 0 assignees View on GitHub
backend:X86 missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

I have two masks, 127 and one calculated using `_mm_cmpeq_epi8_mask`... If I try to compare them, Clang generates

```asm
mov ax, 127
kmovd k1, eax
vpcmpeqb k0 {k1}, xmm0, xmmword ptr [rip + .LCPI0_0]
kmovd ecx, k0
mov eax, -1
cmp cx, 127
je .LBB0_1
```

Which contains two moves across execution units, when GCC can avoid the second one. Masks like 127, which is essentially sequence of 1 bits should be able to be generated inside the mask register itself (NOT 0 = 65535, shift right by 9 bits = 127).

GCC generates:

```asm
mov eax, 127
kmovw k1, eax
vpcmpeqb k0, xmm0, XMMWORD PTR .LC1[rip]
kandw k0, k0, k1
kxorw k1, k0, k1
kortestw k1, k1
jne .L3
```

The relevant C code is:

```c
__mmask16 target_mask = (1U << (best_len + 1)) - 1;
__mmask16 match_mask = _mm_cmpeq_epi8_mask(scan_vec, cand_vec);
__mmask16 mask = _kand_mask16(match_mask, target_mask);
if (_kxor_mask16(mask, target_mask) == (__mmask16)0) {
...
}
```

Contributor guide

Open the contributing guide

Research direction

Start from the provided C mask operations and compare the emitted Clang and GCC AVX512 assembly. Investigate the compiler path handling mask comparisons and logical operations; done means Clang avoids the scalar moves and produces mask-register operations comparable to the GCC sequence.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.