llvm / llvm/llvm-project

[X86] failed to use vpmadd52luq if loop iteration count is const

Open
#222,952 1 comment 0 reactions 0 assignees View on GitHub
backend:X86 llvm:analysis missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

found from https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/vf_rotate.c#L255-L279
```c
#include

#define FFMIN(a,b) ((a) > (b) ? (b) : (a))

#define AV_RL16(x) \
((((const uint8_t*)(x))[1] << 8) | \
((const uint8_t*)(x))[0])

#define AV_WL16(p, val) do { \
uint16_t d = (val); \
((uint8_t*)(p))[0] = (d); \
((uint8_t*)(p))[1] = (d)>>8; \
} while(0)

#define av_clip(a, amin, amax) ((a) < (amin) ? (amin) : ((a) > (amax) ? (amax) : (a)))

uint8_t *interpolate_bilinear16(uint8_t *restrict dst_color,
const uint8_t *restrict src, int src_linesize, int src_linestep,
int x, int y, int max_x, int max_y)
{
//src_linestep = 64;
__builtin_assume(src_linestep > 0 && src_linestep % 64 == 0 && src_linestep <= 64);
int int_x = av_clip(x>>16, 0, max_x);
int int_y = av_clip(y>>16, 0, max_y);
int64_t frac_x = x&0xFFFF;
int64_t frac_y = y&0xFFFF;
int i;
int int_x1 = FFMIN(int_x+1, max_x);
int int_y1 = FFMIN(int_y+1, max_y);

for (i = 0; i < src_linestep; i+=2) {
int s00 = AV_RL16(&src[src_linestep * int_x + i + src_linesize * int_y ]);
int s01 = AV_RL16(&src[src_linestep * int_x1 + i + src_linesize * int_y ]);
int s10 = AV_RL16(&src[src_linestep * int_x + i + src_linesize * int_y1]);
int s11 = AV_RL16(&src[src_linestep * int_x1 + i + src_linesize * int_y1]);
int64_t s0 = (((1<<16) - frac_x)*s00 + frac_x*s01);
int64_t s1 = (((1<<16) - frac_x)*s10 + frac_x*s11);

AV_WL16(&dst_color[i], (((1<<16) - frac_y)*s0 + frac_y*s1) >> 32);
}

return dst_color;
}
```
```asm
interpolate_bilinear16:
mov rax, rdi
mov edi, dword ptr [rsp + 16]
mov r10d, dword ptr [rsp + 8]
{nf} sar r11d, r8d, 16
cmp r11d, r10d
cmovl r16d, r10d, r11d
xor r17d, r17d
test r11d, r11d
cmovs r16d, r17d
{nf} sar r11d, r9d, 16
cmp r11d, edi
cmovl r18d, edi, r11d
test r11d, r11d
cmovns r17d, r18d
movzx r8d, r8w
movzx r9d, r9w
{nf} inc r11d, r16d
cmp r11d, r10d
cmovl r10d, r11d
{nf} inc r11d, r17d
cmp r11d, edi
cmovl edi, r11d
imul r16d, ecx
imul r17d, edx
imul r10d, ecx
imul edx, edi
mov edi, 65536
{nf} sub r11, rdi, r8
sub rdi, r9
{nf} imul r18, r11, rdi
imul rdi, r8
imul r11, r9
imul r8, r9
movsxd r9, r16d
movsxd r16, r17d
movsxd r17, edx
movsxd r10, r10d
mov ecx, ecx
add rcx, -2
shr rcx
vpbroadcastq zmm0, r18
vpbroadcastq zmm1, rdi
vpbroadcastq zmm2, r11
vpbroadcastq zmm3, r8
{nf} add rdx, r10, r17
add rdx, rsi
{nf} add rdi, rsi, r16
add rdi, r10
lea r8, [rsi + r9]
add r8, r17
add r9, r16
add rsi, r9
mov r9, -1
.LBB0_1:
vpmovzxwq zmm4, xmmword ptr [rsi + 2*r9 + 18]
vpmovzxwq zmm5, xmmword ptr [rsi + 2*r9 + 2]
vpmovzxwq zmm6, xmmword ptr [rsi + 2*r9 + 50]
vpmovzxwq zmm7, xmmword ptr [rsi + 2*r9 + 34]
vpmovzxwq zmm8, xmmword ptr [rdi + 2*r9 + 34]
vpmovzxwq zmm9, xmmword ptr [rdi + 2*r9 + 50]
vpmovzxwq zmm10, xmmword ptr [rdi + 2*r9 + 2]
vpmovzxwq zmm11, xmmword ptr [rdi + 2*r9 + 18]
vpmovzxwq zmm12, xmmword ptr [r8 + 2*r9 + 18]
vpmovzxwq zmm13, xmmword ptr [r8 + 2*r9 + 2]
vpmovzxwq zmm14, xmmword ptr [r8 + 2*r9 + 50]
vpmovzxwq zmm15, xmmword ptr [r8 + 2*r9 + 34]
vpmovzxwq zmm16, xmmword ptr [rdx + 2*r9 + 34]
vpmovzxwq zmm17, xmmword ptr [rdx + 2*r9 + 50]
vpmovzxwq zmm18, xmmword ptr [rdx + 2*r9 + 2]
vpmovzxwq zmm19, xmmword ptr [rdx + 2*r9 + 18]
vpxord xmm20, xmm20, xmm20
vpmadd52luq zmm20, zmm0, zmm7
vpxor xmm7, xmm7, xmm7
vpmadd52luq zmm7, zmm0, zmm6
vpxor xmm6, xmm6, xmm6
vpmadd52luq zmm6, zmm0, zmm5
vpxor xmm5, xmm5, xmm5
vpmadd52luq zmm5, zmm0, zmm4
vpmadd52luq zmm5, zmm1, zmm11
vpmadd52luq zmm6, zmm1, zmm10
vpmadd52luq zmm7, zmm1, zmm9
vpmadd52luq zmm20, zmm1, zmm8
vpxor xmm4, xmm4, xmm4
vpmadd52luq zmm4, zmm2, zmm15
vpxor xmm8, xmm8, xmm8
vpmadd52luq zmm8, zmm2, zmm14
vpxor xmm9, xmm9, xmm9
vpmadd52luq zmm9, zmm2, zmm13
vpxor xmm10, xmm10, xmm10
vpmadd52luq zmm10, zmm2, zmm12
vpmadd52luq zmm10, zmm3, zmm19
vpaddq zmm5, zmm10, zmm5
vpmadd52luq zmm9, zmm3, zmm18
vpaddq zmm6, zmm9, zmm6
vpmadd52luq zmm8, zmm3, zmm17
vpaddq zmm7, zmm8, zmm7
vpmadd52luq zmm4, zmm3, zmm16
vpaddq zmm4, zmm4, zmm20
vpsrlq zmm5, zmm5, 32
vpsrlq zmm6, zmm6, 32
vpsrlq zmm7, zmm7, 32
vpsrlq zmm4, zmm4, 32
vpmovqw xmm4, zmm4
vpmovqw xmm7, zmm7
vinserti128 ymm4, ymm4, xmm7, 1
vpmovqw xmm6, zmm6
vpmovqw xmm5, zmm5
vinserti128 ymm5, ymm6, xmm5, 1
vinserti64x4 zmm4, zmm5, ymm4, 1
vmovdqu64 zmmword ptr [rax + 2*r9 + 2], zmm4
add r9, 32
cmp rcx, r9
jne .LBB0_1
vzeroupper
ret
```
If uncomment `src_linestep = 64`:
```asm
.LCPI0_0:
.quad 5
.quad 1
.quad 2
.quad 3
.LCPI0_2:
.short 16
.short 17
.short 18
.short 19
.short 2
.short 21
.short 22
.short 23
.short 0
.short 25
.short 26
.short 27
.short 2
.short 29
.short 30
.short 31
.LCPI0_3:
.quad 0
.quad 0
.quad 1
.quad 6
.LCPI0_1:
.quad 65536
.LCPI0_4:
.quad 1
.LCPI0_5:
.quad 2
.LCPI0_6:
.quad 3
interpolate_bilinear16:
mov rax, rdi
mov ecx, dword ptr [rsp + 16]
mov edi, dword ptr [rsp + 8]
{nf} sar r10d, r8d, 16
cmp r10d, edi
cmovl r11d, edi, r10d
xor r16d, r16d
test r10d, r10d
cmovs r11d, r16d
{nf} sar r10d, r9d, 16
cmp r10d, ecx
cmovl r17d, ecx, r10d
test r10d, r10d
cmovns r16d, r17d
{nf} inc r10d, r11d
cmp r10d, edi
cmovl edi, r10d
{nf} inc r10d, r16d
cmp r10d, ecx
cmovl ecx, r10d
movsxd r10, r11d
shl r10, 6
imul r16d, edx
movsxd rdi, edi
shl rdi, 6
imul ecx, edx
movsxd rdx, r16d
movsxd rcx, ecx
add rdx, rsi
add rcx, rsi
vmovd xmm0, r9d
vpinsrd xmm0, xmm0, r8d, 1
vpxor xmm1, xmm1, xmm1
vpblendw xmm1, xmm1, xmm0, 5
vpmovzxdq ymm1, xmm1
vmovdqa ymm2, ymmword ptr [rip + .LCPI0_0]
vpbroadcastq ymm3, qword ptr [rip + .LCPI0_1]
vpermt2q ymm3, ymm2, ymm1
vpxor xmm2, xmm2, xmm2
vmovdqa ymm4, ymmword ptr [rip + .LCPI0_2]
vpermi2w ymm4, ymm0, ymm2
vpsubq ymm0, ymm3, ymm4
vmovdqa ymm2, ymmword ptr [rip + .LCPI0_3]
vpermi2q ymm2, ymm1, ymm0
vpmuldq ymm0, ymm0, ymm2
vpbroadcastq zmm1, qword ptr [rip + .LCPI0_4]
vpermq zmm1, zmm1, zmm0
vpbroadcastq zmm2, qword ptr [rip + .LCPI0_5]
vpermq zmm2, zmm2, zmm0
vpbroadcastq zmm3, qword ptr [rip + .LCPI0_6]
vpermq zmm3, zmm3, zmm0
vpmovzxwq zmm4, xmmword ptr [r10 + rdx + 16]
vpmovzxwq zmm5, xmmword ptr [r10 + rdx]
vpmovzxwq zmm6, xmmword ptr [r10 + rdx + 48]
vpmovzxwq zmm7, xmmword ptr [r10 + rdx + 32]
vpmovzxwq zmm8, xmmword ptr [rdi + rdx + 16]
vpmovzxwq zmm9, xmmword ptr [rdi + rdx]
vpmovzxwq zmm10, xmmword ptr [rdi + rdx + 48]
vpmovzxwq zmm11, xmmword ptr [rdi + rdx + 32]
vpmovzxwq zmm12, xmmword ptr [r10 + rcx + 16]
vpmovzxwq zmm13, xmmword ptr [r10 + rcx]
vpmovzxwq zmm14, xmmword ptr [r10 + rcx + 48]
vpmovzxwq zmm15, xmmword ptr [r10 + rcx + 32]
vpmovzxwq zmm16, xmmword ptr [rdi + rcx + 16]
vpmovzxwq zmm17, xmmword ptr [rdi + rcx]
vpmovzxwq zmm18, xmmword ptr [rdi + rcx + 48]
vpmovzxwq zmm19, xmmword ptr [rdi + rcx + 32]
vpbroadcastq zmm0, xmm0
vpmullq zmm7, zmm3, zmm7
vpmullq zmm6, zmm3, zmm6
vpmullq zmm5, zmm3, zmm5
vpmullq zmm3, zmm3, zmm4
vpmullq zmm4, zmm2, zmm11
vpaddq zmm4, zmm4, zmm7
vpmullq zmm7, zmm2, zmm10
vpaddq zmm6, zmm7, zmm6
vpmullq zmm7, zmm2, zmm9
vpaddq zmm5, zmm7, zmm5
vpmullq zmm2, zmm2, zmm8
vpaddq zmm2, zmm2, zmm3
vpmullq zmm3, zmm1, zmm15
vpmullq zmm7, zmm1, zmm14
vpmullq zmm8, zmm1, zmm13
vpmullq zmm1, zmm1, zmm12
vpmullq zmm9, zmm0, zmm19
vpaddq zmm3, zmm9, zmm3
vpaddq zmm3, zmm3, zmm4
vpmullq zmm4, zmm0, zmm18
vpaddq zmm4, zmm4, zmm7
vpaddq zmm4, zmm4, zmm6
vpmullq zmm6, zmm0, zmm17
vpaddq zmm6, zmm6, zmm8
vpaddq zmm5, zmm6, zmm5
vpmullq zmm0, zmm0, zmm16
vpaddq zmm0, zmm0, zmm1
vpaddq zmm0, zmm0, zmm2
vpsrlq zmm0, zmm0, 32
vpsrlq zmm1, zmm5, 32
vpsrlq zmm2, zmm4, 32
vpsrlq zmm3, zmm3, 32
vpmovqw xmm3, zmm3
vpmovqw xmm2, zmm2
vinserti128 ymm2, ymm3, xmm2, 1
vpmovqw xmm1, zmm1
vpmovqw xmm0, zmm0
vinserti128 ymm0, ymm1, xmm0, 1
vinserti64x4 zmm0, zmm0, ymm2, 1
vmovdqu64 zmmword ptr [rax], zmm0
vzeroupper
ret
```
https://godbolt.org/z/d4Txahrxh

Contributor guide

Open the contributing guide

Research direction

Reproduce the constant and non-constant src_linestep cases from the Godbolt link, using the interpolate_bilinear16 example from libavfilter/vf_rotate.c. Compare the generated x86 assembly and trace the loop-vectorization or instruction-selection decision responsible for the missing vpmadd52luq. Done means the constant-iteration case emits the intended instruction while preserving correct output and existing behavior.

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
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.