[llvm] 4cd2f4d - [X86] Coalesce redundant vector register clears in zero_call_used_regs (#212147)

via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 02:55:34 PDT 2026


Author: Akshay K
Date: 2026-09-23T10:55:26+01:00
New Revision: 4cd2f4d84b3682908be78bc5cd314507a3d80686

URL: https://github.com/llvm/llvm-project/commit/4cd2f4d84b3682908be78bc5cd314507a3d80686
DIFF: https://github.com/llvm/llvm-project/commit/4cd2f4d84b3682908be78bc5cd314507a3d80686.diff

LOG: [X86] Coalesce redundant vector register clears in zero_call_used_regs (#212147)

This pull request improves how the X86 backend implements
`-fzero-call-used-regs` for vector registers by coalescing aliasing
XMM/YMM/ZMM register views before emitting zeroing instructions. Each
physical vector register is now cleared exactly once, eliminating
redundant clears and avoiding unnecessary `vzeroupper` emission.

Vector register zeroing

- Updated `X86FrameLowering::emitZeroCallUsedRegs` to normalize aliasing
XMM/YMM/ZMM registers to a single representative before emitting clears,
mirroring the existing handling for general-purpose registers.
- Registers XMM0–15 are cleared with VEX-encoded zero idioms, while
XMM16–31 are cleared using EVEX-encoded instructions. Since writes to an
XMM destination also zero the upper bits of the enclosing YMM/ZMM
register, each physical vector register is cleared exactly once.
- Eliminates redundant AVX_SET0/AVX512_512_SET0 pseudos, preventing
unnecessary vzeroupper insertion while preserving the same architectural
zeroization.

AVX512F mask register clearing

- `X86InstrInfo::buildClearRegister` incorrectly gated k0–k7 clearing on
`hasVLX()`. `KSET0W` only requires `AVX512F`, so it fixes mask registers
clearing with `-mattr=+avx512f`.

Tests
- Updated `zero-call-used-regs-simd.ll` to reflect the reduced
instruction sequences across the AVX, AVX2, and AVX-512 code paths.
- Added `all_no_live_vec` to verify that `-fzero-call-used-regs=all`
clears each vector register only once and does not emit a spurious
vzeroupper.

Fixes #191911

Assisted-by: Codex

Added: 
    

Modified: 
    llvm/lib/Target/X86/X86FrameLowering.cpp
    llvm/lib/Target/X86/X86InstrInfo.cpp
    llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp
index fad665e31bbe5..a25aba6d0afe0 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/lib/Target/X86/X86InstrInfo.cpp b/llvm/lib/Target/X86/X86InstrInfo.cpp
index d8d4b8e8ecf31..6fb5a4866dc13 100644
--- a/llvm/lib/Target/X86/X86InstrInfo.cpp
+++ b/llvm/lib/Target/X86/X86InstrInfo.cpp
@@ -10971,7 +10971,7 @@ void X86InstrInfo::buildClearRegister(Register Reg, MachineBasicBlock &MBB,
   } else if (X86::VK1RegClass.contains(Reg) || X86::VK2RegClass.contains(Reg) ||
              X86::VK4RegClass.contains(Reg) || X86::VK8RegClass.contains(Reg) ||
              X86::VK16RegClass.contains(Reg)) {
-    if (!ST.hasVLX())
+    if (!ST.hasAVX512())
       return;
 
     unsigned Op = ST.hasBWI() ? X86::KSET0Q : X86::KSET0W;

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 d57b2f4cd2a10..65444333895a6 100644
--- a/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll
+++ b/llvm/test/CodeGen/X86/zero-call-used-regs-simd.ll
@@ -178,8 +178,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
 ;
@@ -190,10 +190,9 @@ define void @zero_k(<8 x i32> %arg, <8 x i1> %mask) #0 {
 ; AVX512F-NEXT:    vpsllq $63, %zmm1, %zmm1
 ; AVX512F-NEXT:    vptestmq %zmm1, %zmm1, %k1
 ; AVX512F-NEXT:    vmovdqu32 %zmm0, 0 {%k1}
-; AVX512F-NEXT:    vpxor %xmm1, %xmm1, %xmm1
-; AVX512F-NEXT:    vpxor %xmm0, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpxor %xmm0, %xmm0, %xmm0
 ; AVX512F-NEXT:    vpxor %xmm1, %xmm1, %xmm1
+; AVX512F-NEXT:    kxorw %k0, %k0, %k1
 ; AVX512F-NEXT:    vzeroupper
 ; AVX512F-NEXT:    retq
 ;
@@ -203,8 +202,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
@@ -214,8 +213,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
@@ -223,7 +222,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:
@@ -359,22 +358,6 @@ define void @all_no_live_vec() #1 {
 ; AVX512F-NEXT:    vxorps %xmm13, %xmm13, %xmm13
 ; AVX512F-NEXT:    vxorps %xmm14, %xmm14, %xmm14
 ; AVX512F-NEXT:    vxorps %xmm15, %xmm15, %xmm15
-; AVX512F-NEXT:    vxorps %xmm0, %xmm0, %xmm0
-; AVX512F-NEXT:    vxorps %xmm1, %xmm1, %xmm1
-; AVX512F-NEXT:    vxorps %xmm2, %xmm2, %xmm2
-; AVX512F-NEXT:    vxorps %xmm3, %xmm3, %xmm3
-; AVX512F-NEXT:    vxorps %xmm4, %xmm4, %xmm4
-; AVX512F-NEXT:    vxorps %xmm5, %xmm5, %xmm5
-; AVX512F-NEXT:    vxorps %xmm6, %xmm6, %xmm6
-; AVX512F-NEXT:    vxorps %xmm7, %xmm7, %xmm7
-; AVX512F-NEXT:    vxorps %xmm8, %xmm8, %xmm8
-; AVX512F-NEXT:    vxorps %xmm9, %xmm9, %xmm9
-; AVX512F-NEXT:    vxorps %xmm10, %xmm10, %xmm10
-; AVX512F-NEXT:    vxorps %xmm11, %xmm11, %xmm11
-; AVX512F-NEXT:    vxorps %xmm12, %xmm12, %xmm12
-; AVX512F-NEXT:    vxorps %xmm13, %xmm13, %xmm13
-; AVX512F-NEXT:    vxorps %xmm14, %xmm14, %xmm14
-; AVX512F-NEXT:    vxorps %xmm15, %xmm15, %xmm15
 ; AVX512F-NEXT:    vpxord %zmm16, %zmm16, %zmm16
 ; AVX512F-NEXT:    vpxord %zmm17, %zmm17, %zmm17
 ; AVX512F-NEXT:    vpxord %zmm18, %zmm18, %zmm18
@@ -391,6 +374,14 @@ define void @all_no_live_vec() #1 {
 ; AVX512F-NEXT:    vpxord %zmm29, %zmm29, %zmm29
 ; AVX512F-NEXT:    vpxord %zmm30, %zmm30, %zmm30
 ; AVX512F-NEXT:    vpxord %zmm31, %zmm31, %zmm31
+; AVX512F-NEXT:    kxorw %k0, %k0, %k0
+; AVX512F-NEXT:    kxorw %k0, %k0, %k1
+; AVX512F-NEXT:    kxorw %k0, %k0, %k2
+; AVX512F-NEXT:    kxorw %k0, %k0, %k3
+; AVX512F-NEXT:    kxorw %k0, %k0, %k4
+; AVX512F-NEXT:    kxorw %k0, %k0, %k5
+; AVX512F-NEXT:    kxorw %k0, %k0, %k6
+; AVX512F-NEXT:    kxorw %k0, %k0, %k7
 ; AVX512F-NEXT:    retq
 ;
 ; AVX512VL-LABEL: all_no_live_vec:
@@ -436,30 +427,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
@@ -476,6 +443,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:
@@ -521,30 +496,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
@@ -561,6 +512,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