[llvm] [X86] Coalesce redundant vector register clears in zero_call_used_regs (PR #212147)
Akshay K via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 14 21:09:13 PDT 2026
https://github.com/kumarak updated https://github.com/llvm/llvm-project/pull/212147
>From ee41e5f8cf4fed08a542625a3b7fff379965d370 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Sat, 25 Jul 2026 18:00:02 -0400
Subject: [PATCH] [X86] Coalesce redundant vector register clears in
zero_call_used_regs
Map the aliasing XMM/YMM/ZMM views of each vector register to a single clear
per lane, mirroring the existing GPR handling. This removes the duplicate
XMM0-15 zeroing and the spurious VZEROUPPER emitted for -fzero-call-used-regs,
reducing both code size and latency.
Fixes #191911
---
llvm/lib/Target/X86/X86FrameLowering.cpp | 34 ++++++++-
.../CodeGen/X86/zero-call-used-regs-simd.ll | 72 ++++++-------------
2 files changed, 53 insertions(+), 53 deletions(-)
diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index 7b9f03c87ecdc..e143da425538c 100644
--- a/llvm/lib/Target/X86/X86FrameLowering.cpp
+++ b/llvm/lib/Target/X86/X86FrameLowering.cpp
@@ -688,7 +688,39 @@ void X86FrameLowering::emitZeroCallUsedRegs(BitVector RegsToZero,
for (MCRegister Reg : GPRsToZero.set_bits())
TII.buildClearRegister(Reg, MBB, MBBI, DL);
- // Zero out the remaining registers.
+ // Coalesce the aliasing XMM/YMM/ZMM views of each vector register so a lane
+ // is cleared only once, mirroring the GPR handling above.
+ auto getVectorClearReg = [&](MCRegister Reg) -> MCRegister {
+ if (!X86::VR128RegClass.contains(Reg) &&
+ !X86::VR128XRegClass.contains(Reg) &&
+ !X86::VR256RegClass.contains(Reg) &&
+ !X86::VR256XRegClass.contains(Reg) && !X86::VR512RegClass.contains(Reg))
+ return MCRegister();
+
+ // Clearing the XMM zeroes the whole lane. XMM0-15 use the compact VEX form;
+ // XMM16-31 are EVEX-only, reachable only via the ZMM form.
+ MCRegister Xmm = TRI->getSubReg(Reg, X86::sub_xmm);
+ if (!Xmm)
+ Xmm = Reg;
+ if (X86::VR128RegClass.contains(Xmm))
+ return Xmm;
+ MCRegister Zmm =
+ TRI->getMatchingSuperReg(Xmm, X86::sub_xmm, &X86::VR512RegClass);
+ assert(Zmm && "XMM16-31 must have an enclosing ZMM to clear through");
+ return Zmm;
+ };
+
+ BitVector VecRegsToZero(TRI->getNumRegs());
+ for (MCRegister Reg : RegsToZero.set_bits())
+ if (MCRegister Clear = getVectorClearReg(Reg)) {
+ VecRegsToZero.set(Clear.id());
+ RegsToZero.reset(Reg);
+ }
+
+ for (MCRegister Reg : VecRegsToZero.set_bits())
+ TII.buildClearRegister(Reg, MBB, MBBI, DL);
+
+ // Zero out the remaining registers (e.g. mask registers).
for (MCRegister Reg : RegsToZero.set_bits())
TII.buildClearRegister(Reg, MBB, MBBI, DL);
}
diff --git a/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll b/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll
index 1d5aa24e81f8c..15af5b333874d 100644
--- a/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll
+++ b/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll
@@ -177,8 +177,8 @@ define void @zero_k(<8 x i32> %arg, <8 x i1> %mask) #0 {
; AVX2-NEXT: vpmovzxwd {{.*#+}} ymm1 = xmm1[0],zero,xmm1[1],zero,xmm1[2],zero,xmm1[3],zero,xmm1[4],zero,xmm1[5],zero,xmm1[6],zero,xmm1[7],zero
; AVX2-NEXT: vpslld $31, %ymm1, %ymm1
; AVX2-NEXT: vpmaskmovd %ymm0, %ymm1, 0
-; AVX2-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX2-NEXT: vpxor %xmm0, %xmm0, %xmm0
+; AVX2-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX2-NEXT: vzeroupper
; AVX2-NEXT: retq
;
@@ -188,8 +188,8 @@ define void @zero_k(<8 x i32> %arg, <8 x i1> %mask) #0 {
; AVX512VL-NEXT: vpslld $31, %ymm1, %ymm1
; AVX512VL-NEXT: vptestmd %ymm1, %ymm1, %k1
; AVX512VL-NEXT: vmovdqa32 %ymm0, 0 {%k1}
-; AVX512VL-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX512VL-NEXT: vpxor %xmm0, %xmm0, %xmm0
+; AVX512VL-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX512VL-NEXT: kxorw %k0, %k0, %k1
; AVX512VL-NEXT: vzeroupper
; AVX512VL-NEXT: retq
@@ -199,8 +199,8 @@ define void @zero_k(<8 x i32> %arg, <8 x i1> %mask) #0 {
; AVX512BW-NEXT: vpsllw $15, %xmm1, %xmm1
; AVX512BW-NEXT: vpmovw2m %xmm1, %k1
; AVX512BW-NEXT: vmovdqa32 %ymm0, 0 {%k1}
-; AVX512BW-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX512BW-NEXT: vpxor %xmm0, %xmm0, %xmm0
+; AVX512BW-NEXT: vpxor %xmm1, %xmm1, %xmm1
; AVX512BW-NEXT: kxorq %k0, %k0, %k1
; AVX512BW-NEXT: vzeroupper
; AVX512BW-NEXT: retq
@@ -208,7 +208,7 @@ define void @zero_k(<8 x i32> %arg, <8 x i1> %mask) #0 {
ret void
}
-; FIXME: Under "all", each vector lane is cleared once (not once per XMM/YMM/ZMM view),
+; Under "all", each vector lane is cleared once (not once per XMM/YMM/ZMM view),
; and no spurious VZEROUPPER is emitted.
define void @all_no_live_vec() #1 {
; SSE-LABEL: all_no_live_vec:
@@ -344,30 +344,6 @@ define void @all_no_live_vec() #1 {
; AVX512VL-NEXT: vxorps %xmm13, %xmm13, %xmm13
; AVX512VL-NEXT: vxorps %xmm14, %xmm14, %xmm14
; AVX512VL-NEXT: vxorps %xmm15, %xmm15, %xmm15
-; AVX512VL-NEXT: kxorw %k0, %k0, %k0
-; AVX512VL-NEXT: kxorw %k0, %k0, %k1
-; AVX512VL-NEXT: kxorw %k0, %k0, %k2
-; AVX512VL-NEXT: kxorw %k0, %k0, %k3
-; AVX512VL-NEXT: kxorw %k0, %k0, %k4
-; AVX512VL-NEXT: kxorw %k0, %k0, %k5
-; AVX512VL-NEXT: kxorw %k0, %k0, %k6
-; AVX512VL-NEXT: kxorw %k0, %k0, %k7
-; AVX512VL-NEXT: vxorps %xmm0, %xmm0, %xmm0
-; AVX512VL-NEXT: vxorps %xmm1, %xmm1, %xmm1
-; AVX512VL-NEXT: vxorps %xmm2, %xmm2, %xmm2
-; AVX512VL-NEXT: vxorps %xmm3, %xmm3, %xmm3
-; AVX512VL-NEXT: vxorps %xmm4, %xmm4, %xmm4
-; AVX512VL-NEXT: vxorps %xmm5, %xmm5, %xmm5
-; AVX512VL-NEXT: vxorps %xmm6, %xmm6, %xmm6
-; AVX512VL-NEXT: vxorps %xmm7, %xmm7, %xmm7
-; AVX512VL-NEXT: vxorps %xmm8, %xmm8, %xmm8
-; AVX512VL-NEXT: vxorps %xmm9, %xmm9, %xmm9
-; AVX512VL-NEXT: vxorps %xmm10, %xmm10, %xmm10
-; AVX512VL-NEXT: vxorps %xmm11, %xmm11, %xmm11
-; AVX512VL-NEXT: vxorps %xmm12, %xmm12, %xmm12
-; AVX512VL-NEXT: vxorps %xmm13, %xmm13, %xmm13
-; AVX512VL-NEXT: vxorps %xmm14, %xmm14, %xmm14
-; AVX512VL-NEXT: vxorps %xmm15, %xmm15, %xmm15
; AVX512VL-NEXT: vpxord %xmm16, %xmm16, %xmm16
; AVX512VL-NEXT: vpxord %xmm17, %xmm17, %xmm17
; AVX512VL-NEXT: vpxord %xmm18, %xmm18, %xmm18
@@ -384,6 +360,14 @@ define void @all_no_live_vec() #1 {
; AVX512VL-NEXT: vpxord %xmm29, %xmm29, %xmm29
; AVX512VL-NEXT: vpxord %xmm30, %xmm30, %xmm30
; AVX512VL-NEXT: vpxord %xmm31, %xmm31, %xmm31
+; AVX512VL-NEXT: kxorw %k0, %k0, %k0
+; AVX512VL-NEXT: kxorw %k0, %k0, %k1
+; AVX512VL-NEXT: kxorw %k0, %k0, %k2
+; AVX512VL-NEXT: kxorw %k0, %k0, %k3
+; AVX512VL-NEXT: kxorw %k0, %k0, %k4
+; AVX512VL-NEXT: kxorw %k0, %k0, %k5
+; AVX512VL-NEXT: kxorw %k0, %k0, %k6
+; AVX512VL-NEXT: kxorw %k0, %k0, %k7
; AVX512VL-NEXT: retq
;
; AVX512BW-LABEL: all_no_live_vec:
@@ -429,30 +413,6 @@ define void @all_no_live_vec() #1 {
; AVX512BW-NEXT: vxorps %xmm13, %xmm13, %xmm13
; AVX512BW-NEXT: vxorps %xmm14, %xmm14, %xmm14
; AVX512BW-NEXT: vxorps %xmm15, %xmm15, %xmm15
-; AVX512BW-NEXT: kxorq %k0, %k0, %k0
-; AVX512BW-NEXT: kxorq %k0, %k0, %k1
-; AVX512BW-NEXT: kxorq %k0, %k0, %k2
-; AVX512BW-NEXT: kxorq %k0, %k0, %k3
-; AVX512BW-NEXT: kxorq %k0, %k0, %k4
-; AVX512BW-NEXT: kxorq %k0, %k0, %k5
-; AVX512BW-NEXT: kxorq %k0, %k0, %k6
-; AVX512BW-NEXT: kxorq %k0, %k0, %k7
-; AVX512BW-NEXT: vxorps %xmm0, %xmm0, %xmm0
-; AVX512BW-NEXT: vxorps %xmm1, %xmm1, %xmm1
-; AVX512BW-NEXT: vxorps %xmm2, %xmm2, %xmm2
-; AVX512BW-NEXT: vxorps %xmm3, %xmm3, %xmm3
-; AVX512BW-NEXT: vxorps %xmm4, %xmm4, %xmm4
-; AVX512BW-NEXT: vxorps %xmm5, %xmm5, %xmm5
-; AVX512BW-NEXT: vxorps %xmm6, %xmm6, %xmm6
-; AVX512BW-NEXT: vxorps %xmm7, %xmm7, %xmm7
-; AVX512BW-NEXT: vxorps %xmm8, %xmm8, %xmm8
-; AVX512BW-NEXT: vxorps %xmm9, %xmm9, %xmm9
-; AVX512BW-NEXT: vxorps %xmm10, %xmm10, %xmm10
-; AVX512BW-NEXT: vxorps %xmm11, %xmm11, %xmm11
-; AVX512BW-NEXT: vxorps %xmm12, %xmm12, %xmm12
-; AVX512BW-NEXT: vxorps %xmm13, %xmm13, %xmm13
-; AVX512BW-NEXT: vxorps %xmm14, %xmm14, %xmm14
-; AVX512BW-NEXT: vxorps %xmm15, %xmm15, %xmm15
; AVX512BW-NEXT: vpxord %xmm16, %xmm16, %xmm16
; AVX512BW-NEXT: vpxord %xmm17, %xmm17, %xmm17
; AVX512BW-NEXT: vpxord %xmm18, %xmm18, %xmm18
@@ -469,6 +429,14 @@ define void @all_no_live_vec() #1 {
; AVX512BW-NEXT: vpxord %xmm29, %xmm29, %xmm29
; AVX512BW-NEXT: vpxord %xmm30, %xmm30, %xmm30
; AVX512BW-NEXT: vpxord %xmm31, %xmm31, %xmm31
+; AVX512BW-NEXT: kxorq %k0, %k0, %k0
+; AVX512BW-NEXT: kxorq %k0, %k0, %k1
+; AVX512BW-NEXT: kxorq %k0, %k0, %k2
+; AVX512BW-NEXT: kxorq %k0, %k0, %k3
+; AVX512BW-NEXT: kxorq %k0, %k0, %k4
+; AVX512BW-NEXT: kxorq %k0, %k0, %k5
+; AVX512BW-NEXT: kxorq %k0, %k0, %k6
+; AVX512BW-NEXT: kxorq %k0, %k0, %k7
; AVX512BW-NEXT: retq
ret void
}
More information about the llvm-commits
mailing list