[llvm] e04b7ce - [X86] Remove TuningFastVariableCrossLaneShuffle from X86_64V4Tuning (#212178)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 00:01:22 PDT 2026
Author: Rohan Shenoy
Date: 2026-08-25T12:31:16+05:30
New Revision: e04b7cec1ea54c908f2c9c576464f366b7858bba
URL: https://github.com/llvm/llvm-project/commit/e04b7cec1ea54c908f2c9c576464f366b7858bba
DIFF: https://github.com/llvm/llvm-project/commit/e04b7cec1ea54c908f2c9c576464f366b7858bba.diff
LOG: [X86] Remove TuningFastVariableCrossLaneShuffle from X86_64V4Tuning (#212178)
## 1. Background
This flag pushes the compiler toward a shuffle variant that pulls its
permutation pattern from memory, even when that pattern is a
compile-time constant that could just be baked straight into the
instruction. Skipping the load shows gains whenever the pattern is fixed
like that.
We propose dropping it from the `x86-64-v4` tuning list as both SPEC and
the microbenchmark below show a real improvement in runtime in both
Intel and AMD machines.
## 2. SPEC impact
We ran SPEC CPU2017 `base` tuning, `refrate`. No regressions observed in
any of the other benchmarks in the suite, and **noticable gains were
observed in 557.xz_r**
**Config:** clang `23.0.0git`, two builds from the same upstream tree
(baseline vs. `TuningFastVariableCrossLaneShuffle` removed). `-O3 -flto
-march=x86-64-v4`.
#### 557.xz_r results
| Machine | Copies | Iterations | Patched vs Baseline score difference |
| ---------------------------------- | ------ | ---------- | --------- |
| Rocket Lake (Intel Core i5-11600K) | 10 | 3 | **+1.3%** |
| Granite Rapids (Intel Xeon 6980P) | 256 | 3 | **+1.5%** |
| Genoa (AMD EPYC 9654, Zen4) | 256 | 3 | **+3.9%** |
| Turin (AMD EPYC 9755, Zen5) | 512 | 3 | **+2.9%** |
## 3. Microbenchmark impact
**Microkernel** (derived from
`llvm/test/CodeGen/X86/pr77459.ll`:`reverse_cmp_v8i1`, which was
modified in this commit.)
_Created with the help of Claude Code._
```c
#include <immintrin.h>
#include <stdint.h>
#include <stdio.h>
#include <time.h>
__attribute__((noinline))
uint8_t reverse_cmp_v8i1(__m128i a0, __m128i a1) {
__mmask8 m = _mm_cmpeq_epi16_mask(a0, a1);
return __builtin_bitreverse8((uint8_t)m);
}
static double now_ns(void) {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (double)ts.tv_sec * 1e9 + (double)ts.tv_nsec;
}
/* Precomputed OUTSIDE the timed region: 64 genuinely distinct inputs,
* padded to 96 so the inner 32 reads never need a wraparound check. */
#define ARR_SIZE 64
static __m128i inputs[ARR_SIZE + 32];
int main(void) {
__m128i a1 = _mm_set_epi16(1, 2, 3, 0, 5, 6, 7, 8);
volatile uint8_t sink = 0;
long N = 40000000L;
for (int j = 0; j < ARR_SIZE + 32; j++) {
int k = j % ARR_SIZE;
inputs[j] = _mm_set_epi16(k, k+1, k+2, k+3, k+4, k+5, k+6, k+7);
}
reverse_cmp_v8i1(inputs[0], a1); /* warm up */
size_t idx = 0;
double t0 = now_ns();
for (long i = 0; i < N; i++) {
__m128i *p = &inputs[idx];
uint8_t r0 = reverse_cmp_v8i1(p[0], a1);
uint8_t r1 = reverse_cmp_v8i1(p[1], a1);
uint8_t r2 = reverse_cmp_v8i1(p[2], a1);
uint8_t r3 = reverse_cmp_v8i1(p[3], a1);
uint8_t r4 = reverse_cmp_v8i1(p[4], a1);
uint8_t r5 = reverse_cmp_v8i1(p[5], a1);
uint8_t r6 = reverse_cmp_v8i1(p[6], a1);
uint8_t r7 = reverse_cmp_v8i1(p[7], a1);
uint8_t r8 = reverse_cmp_v8i1(p[8], a1);
uint8_t r9 = reverse_cmp_v8i1(p[9], a1);
uint8_t r10 = reverse_cmp_v8i1(p[10], a1);
uint8_t r11 = reverse_cmp_v8i1(p[11], a1);
uint8_t r12 = reverse_cmp_v8i1(p[12], a1);
uint8_t r13 = reverse_cmp_v8i1(p[13], a1);
uint8_t r14 = reverse_cmp_v8i1(p[14], a1);
uint8_t r15 = reverse_cmp_v8i1(p[15], a1);
uint8_t r16 = reverse_cmp_v8i1(p[16], a1);
uint8_t r17 = reverse_cmp_v8i1(p[17], a1);
uint8_t r18 = reverse_cmp_v8i1(p[18], a1);
uint8_t r19 = reverse_cmp_v8i1(p[19], a1);
uint8_t r20 = reverse_cmp_v8i1(p[20], a1);
uint8_t r21 = reverse_cmp_v8i1(p[21], a1);
uint8_t r22 = reverse_cmp_v8i1(p[22], a1);
uint8_t r23 = reverse_cmp_v8i1(p[23], a1);
uint8_t r24 = reverse_cmp_v8i1(p[24], a1);
uint8_t r25 = reverse_cmp_v8i1(p[25], a1);
uint8_t r26 = reverse_cmp_v8i1(p[26], a1);
uint8_t r27 = reverse_cmp_v8i1(p[27], a1);
uint8_t r28 = reverse_cmp_v8i1(p[28], a1);
uint8_t r29 = reverse_cmp_v8i1(p[29], a1);
uint8_t r30 = reverse_cmp_v8i1(p[30], a1);
uint8_t r31 = reverse_cmp_v8i1(p[31], a1);
sink = r0^r1^r2^r3^r4^r5^r6^r7^r8^r9^r10^r11^r12^r13^r14^r15
^r16^r17^r18^r19^r20^r21^r22^r23^r24^r25^r26^r27^r28^r29^r30^r31;
idx += 1;
if (idx >= ARR_SIZE) idx = 0;
}
double t1 = now_ns();
printf("reverse_cmp_v8i1: %.4f ns/call (sink=%u)\n",
(t1 - t0) / (N * 32), (unsigned)sink);
return 0;
}
```
**Config:** same two clang `23.0.0git` builds, compiled using `-O3
-march=x86-64-v4`
| Machine | Baseline | Patched | Speedup |
| --------------------------- | -------- | -------- | ---------- |
| Rocket Lake (i5-11600K) | 1.318 ns | 0.866 ns | **+34.3%** |
| Ice Lake (Xeon 8380) | 1.901 ns | 1.248 ns | **+34.4%** |
| Sapphire Rapids (8490H) | 1.828 ns | 1.307 ns | **+28.5%** |
| Emerald Rapids (8592+) | 2.205 ns | 1.533 ns | **+30.5%** |
| Granite Rapids (Xeon 6980P) | 1.200 ns | 0.867 ns | **+27.8%** |
| Genoa (EPYC 9654, Zen4) | 1.475 ns | 1.196 ns | **+18.9%** |
| Turin (EPYC 9755, Zen5) | 0.981 ns | 0.981 ns | ~0% |
**Codegen change**:
```asm
; baseline
vpcmpeqw %xmm1, %xmm0, %k0
vpmovm2d %k0, %ymm0
vmovdqa .LCPI0_0(%rip), %ymm1 # ymm1 = [7,6,5,4,3,2,1,0]
vpermd %ymm0, %ymm1, %ymm0
vmovmskps %ymm0, %eax
; patched
vpcmpeqw %xmm1, %xmm0, %k0
vpmovm2d %k0, %ymm0
vpshufd $27, %ymm0, %ymm0
vpermq $78, %ymm0, %ymm0
vmovmskps %ymm0, %eax
```
Added:
Modified:
llvm/lib/Target/X86/X86.td
llvm/test/CodeGen/X86/pr77459.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td
index 5a36549a61bc4..991370e736c29 100644
--- a/llvm/lib/Target/X86/X86.td
+++ b/llvm/lib/Target/X86/X86.td
@@ -1012,7 +1012,6 @@ def ProcessorFeatures {
TuningFastScalarFSQRT,
TuningFastVectorFSQRT,
TuningFast15ByteNOP,
- TuningFastVariableCrossLaneShuffle,
TuningFastVariablePerLaneShuffle,
TuningPrefer256Bit,
TuningFastGather,
diff --git a/llvm/test/CodeGen/X86/pr77459.ll b/llvm/test/CodeGen/X86/pr77459.ll
index 5fdc71cf43071..be1ab64c33c6e 100644
--- a/llvm/test/CodeGen/X86/pr77459.ll
+++ b/llvm/test/CodeGen/X86/pr77459.ll
@@ -98,8 +98,8 @@ define i8 @reverse_cmp_v8i1(<8 x i16> %a0, <8 x i16> %a1) {
; AVX512: # %bb.0:
; AVX512-NEXT: vpcmpeqw %xmm1, %xmm0, %k0
; AVX512-NEXT: vpmovm2d %k0, %ymm0
-; AVX512-NEXT: vmovdqa {{.*#+}} ymm1 = [7,6,5,4,3,2,1,0]
-; AVX512-NEXT: vpermd %ymm0, %ymm1, %ymm0
+; AVX512-NEXT: vpshufd {{.*#+}} ymm0 = ymm0[3,2,1,0,7,6,5,4]
+; AVX512-NEXT: vpermq {{.*#+}} ymm0 = ymm0[2,3,0,1]
; AVX512-NEXT: vmovmskps %ymm0, %eax
; AVX512-NEXT: # kill: def $al killed $al killed $eax
; AVX512-NEXT: vzeroupper
More information about the llvm-commits
mailing list