https://github.com/LucasChollet updated 
https://github.com/llvm/llvm-project/pull/206206

>From b48c09cf94866208b44961c66dca18f74c56d1cd Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Tue, 23 Jun 2026 11:30:36 +0200
Subject: [PATCH 1/8] [RISCV] Add support for vector registers with
 -fzero-call-used-regs

The implementation is quite straightforward. Compared to the FP or GP
register implementations, the main difference is that we need to
configure the vector registers before clearing them.

Now that the backend supports clearing all standard registers, this
patch makes the clang driver accept all -fzero-call-used-regs options.
---
 clang/lib/Driver/ToolChains/Clang.cpp         |   3 +-
 llvm/lib/Target/RISCV/RISCVCallingConv.cpp    |   7 +
 llvm/lib/Target/RISCV/RISCVCallingConv.h      |   1 +
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  |  17 ++
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp      |   2 +
 .../Target/RISCV/RISCVInstrInfoVPseudos.td    |   5 +
 llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp   |   3 +
 .../CodeGen/RISCV/zero-call-used-regs-v.ll    | 154 ++++++++++++++++++
 8 files changed, 190 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll

diff --git a/clang/lib/Driver/ToolChains/Clang.cpp 
b/clang/lib/Driver/ToolChains/Clang.cpp
index a30b01a675b99..663055ed68923 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7029,8 +7029,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction 
&JA,
     // The backend code needs to be changed to include the appropriate function
     // calls automatically.
     StringRef Value = A->getValue();
-    if (!Triple.isX86() && !Triple.isAArch64() &&
-        !(Triple.isRISCV() && (Value == "skip" || Value.contains("gpr"))))
+    if (!Triple.isX86() && !Triple.isAArch64() && !Triple.isRISCV())
       D.Diag(diag::err_drv_unsupported_opt_for_target)
           << A->getAsString(Args) << TripleStr;
   }
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp 
b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
index 76bc813d63c43..e98bcc780e1b0 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
@@ -205,6 +205,13 @@ ArrayRef<MCPhysReg> RISCV::getArgFPRs(const RISCVSubtarget 
&STI) {
   return ArrayRef(ArgFPR32s);
 }
 
+ArrayRef<MCPhysReg> RISCV::getArgVRs(const RISCVSubtarget &STI) {
+  if (STI.hasStdExtV())
+    return ArrayRef(ArgVRs);
+
+  return {};
+}
+
 static ArrayRef<MCPhysReg> getArgGPR16s(const RISCVABI::ABI ABI) {
   // The GPRs used for passing arguments in the ILP32* and LP64* ABIs, except
   // the ILP32E ABI.
diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.h 
b/llvm/lib/Target/RISCV/RISCVCallingConv.h
index 42b115a68c1b6..f5b7773b6f384 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.h
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.h
@@ -27,6 +27,7 @@ namespace RISCV {
 
 ArrayRef<MCPhysReg> getArgGPRs(const RISCVSubtarget &STI);
 ArrayRef<MCPhysReg> getArgFPRs(const RISCVSubtarget &STI);
+ArrayRef<MCPhysReg> getArgVRs(const RISCVSubtarget &STI);
 
 } // end namespace RISCV
 
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index bbd1738cd5117..031491b3be3cc 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1500,6 +1500,8 @@ void RISCVFrameLowering::emitZeroCallUsedRegs(BitVector 
RegsToZero,
 
   BitVector FinalRegsToZero(TRI.getNumRegs());
 
+  bool HasVRegister = false;
+
   for (MCRegister Reg : RegsToZero.set_bits()) {
     if (TRI.isGeneralPurposeRegister(MF, Reg)) {
       FinalRegsToZero.set(getPhysicalGPR(TRI, Reg).id());
@@ -1511,9 +1513,24 @@ void RISCVFrameLowering::emitZeroCallUsedRegs(BitVector 
RegsToZero,
     } else if (TRI.isFPRegister(Reg)) {
       if (MCRegister MaybeReg = getLargestFPRegisterOrZero(STI, TRI, Reg))
         FinalRegsToZero.set(MaybeReg.id());
+    } else if (RISCV::VRRegClass.contains(Reg)) {
+      if (!STI.hasStdExtV())
+        continue;
+      HasVRegister = true;
+      FinalRegsToZero.set(Reg.id());
     }
   }
 
+  if (HasVRegister) {
+    RISCVVType::VLMUL VLMUL = RISCVVType::encodeLMUL(1, /*Fractional=*/false);
+    unsigned VTypeImm = RISCVVType::encodeVTYPE(
+        VLMUL, /*SEW=*/32, /*TailAgnostic=*/false, /*MaskAgnostic=*/false);
+
+    BuildMI(MBB, MBBI, DL, TII.get(RISCV::VSETVLI), RISCV::X5)
+        .addReg(RISCV::X0)
+        .addImm(VTypeImm);
+  }
+
   for (MCRegister Reg : FinalRegsToZero.set_bits())
     TII.buildClearRegister(Reg, MBB, MBBI, DL);
 }
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp 
b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 4de0a27790eca..4bbbb3193411b 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -3962,6 +3962,8 @@ void RISCVInstrInfo::buildClearRegister(Register Reg, 
MachineBasicBlock &MBB,
     BuildMI(MBB, Iter, DL, get(RISCV::PseudoClearFPR64), Reg);
   } else if (RISCV::FPR128RegClass.contains(Reg)) {
     BuildMI(MBB, Iter, DL, get(RISCV::PseudoClearFPR128), Reg);
+  } else if (RISCV::VRRegClass.contains(Reg)) {
+    BuildMI(MBB, Iter, DL, get(RISCV::PseudoClearVR), Reg);
   } else {
     llvm::reportFatalInternalError(
         "buildClearRegister is not implemented for vector registers");
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
index 077b8f8058932..4a39376aa0107 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
@@ -6069,6 +6069,11 @@ foreach lmul = MxList in {
   }
 }
 
+// Used by -fzero-call-used-regs to zero out registers.
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+def PseudoClearVR : Pseudo<(outs VR:$vd), (ins), []>,
+                    PseudoInstExpansion<(VMV_V_I VR:$vd, 0)>;
+
 
//===----------------------------------------------------------------------===//
 // 6. Configuration-Setting Instructions
 
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp 
b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 7dbdc881ea6c0..0b619d57d8a2c 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -835,6 +835,9 @@ bool RISCVRegisterInfo::isArgumentRegister(const 
MachineFunction &MF,
   if (TRI->isFPRegister(Reg))
     return llvm::is_contained(RISCV::getArgFPRs(STI), Reg);
 
+  if (RISCV::VRRegClass.contains(Reg))
+    return llvm::is_contained(RISCV::getArgVRs(STI), Reg);
+
   return false;
 }
 
diff --git a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll 
b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
new file mode 100644
index 0000000000000..c270bc9960f7e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
@@ -0,0 +1,154 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 6
+; RUN: llc < %s -verify-machineinstrs -mtriple=riscv64-unknown-unknown 
-mattr="+i,+m,+v" | FileCheck %s  --check-prefixes=CHECK
+
+define void @all() "zero-call-used-regs"="all" {
+; CHECK-LABEL: all:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v0, 0
+; CHECK-NEXT:    vmv.v.i v1, 0
+; CHECK-NEXT:    vmv.v.i v2, 0
+; CHECK-NEXT:    vmv.v.i v3, 0
+; CHECK-NEXT:    vmv.v.i v4, 0
+; CHECK-NEXT:    vmv.v.i v5, 0
+; CHECK-NEXT:    vmv.v.i v6, 0
+; CHECK-NEXT:    vmv.v.i v7, 0
+; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    vmv.v.i v11, 0
+; CHECK-NEXT:    vmv.v.i v12, 0
+; CHECK-NEXT:    vmv.v.i v13, 0
+; CHECK-NEXT:    vmv.v.i v14, 0
+; CHECK-NEXT:    vmv.v.i v15, 0
+; CHECK-NEXT:    vmv.v.i v16, 0
+; CHECK-NEXT:    vmv.v.i v17, 0
+; CHECK-NEXT:    vmv.v.i v18, 0
+; CHECK-NEXT:    vmv.v.i v19, 0
+; CHECK-NEXT:    vmv.v.i v20, 0
+; CHECK-NEXT:    vmv.v.i v21, 0
+; CHECK-NEXT:    vmv.v.i v22, 0
+; CHECK-NEXT:    vmv.v.i v23, 0
+; CHECK-NEXT:    vmv.v.i v24, 0
+; CHECK-NEXT:    vmv.v.i v25, 0
+; CHECK-NEXT:    vmv.v.i v26, 0
+; CHECK-NEXT:    vmv.v.i v27, 0
+; CHECK-NEXT:    vmv.v.i v28, 0
+; CHECK-NEXT:    vmv.v.i v29, 0
+; CHECK-NEXT:    vmv.v.i v30, 0
+; CHECK-NEXT:    vmv.v.i v31, 0
+; CHECK-NEXT:    li t0, 0
+; CHECK-NEXT:    li t1, 0
+; CHECK-NEXT:    li t2, 0
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    li a2, 0
+; CHECK-NEXT:    li a3, 0
+; CHECK-NEXT:    li a4, 0
+; CHECK-NEXT:    li a5, 0
+; CHECK-NEXT:    li a6, 0
+; CHECK-NEXT:    li a7, 0
+; CHECK-NEXT:    li t3, 0
+; CHECK-NEXT:    li t4, 0
+; CHECK-NEXT:    li t5, 0
+; CHECK-NEXT:    li t6, 0
+; CHECK-NEXT:    fmv.d.x ft0, zero
+; CHECK-NEXT:    fmv.d.x ft1, zero
+; CHECK-NEXT:    fmv.d.x ft2, zero
+; CHECK-NEXT:    fmv.d.x ft3, zero
+; CHECK-NEXT:    fmv.d.x ft4, zero
+; CHECK-NEXT:    fmv.d.x ft5, zero
+; CHECK-NEXT:    fmv.d.x ft6, zero
+; CHECK-NEXT:    fmv.d.x ft7, zero
+; CHECK-NEXT:    fmv.d.x fa0, zero
+; CHECK-NEXT:    fmv.d.x fa1, zero
+; CHECK-NEXT:    fmv.d.x fa2, zero
+; CHECK-NEXT:    fmv.d.x fa3, zero
+; CHECK-NEXT:    fmv.d.x fa4, zero
+; CHECK-NEXT:    fmv.d.x fa5, zero
+; CHECK-NEXT:    fmv.d.x fa6, zero
+; CHECK-NEXT:    fmv.d.x fa7, zero
+; CHECK-NEXT:    fmv.d.x ft8, zero
+; CHECK-NEXT:    fmv.d.x ft9, zero
+; CHECK-NEXT:    fmv.d.x ft10, zero
+; CHECK-NEXT:    fmv.d.x ft11, zero
+; CHECK-NEXT:    ret
+entry:
+  ret void
+}
+
+define void @all_arg() "zero-call-used-regs"="all-arg" {
+; CHECK-LABEL: all_arg:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    vmv.v.i v11, 0
+; CHECK-NEXT:    vmv.v.i v12, 0
+; CHECK-NEXT:    vmv.v.i v13, 0
+; CHECK-NEXT:    vmv.v.i v14, 0
+; CHECK-NEXT:    vmv.v.i v15, 0
+; CHECK-NEXT:    vmv.v.i v16, 0
+; CHECK-NEXT:    vmv.v.i v17, 0
+; CHECK-NEXT:    vmv.v.i v18, 0
+; CHECK-NEXT:    vmv.v.i v19, 0
+; CHECK-NEXT:    vmv.v.i v20, 0
+; CHECK-NEXT:    vmv.v.i v21, 0
+; CHECK-NEXT:    vmv.v.i v22, 0
+; CHECK-NEXT:    vmv.v.i v23, 0
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    li a2, 0
+; CHECK-NEXT:    li a3, 0
+; CHECK-NEXT:    li a4, 0
+; CHECK-NEXT:    li a5, 0
+; CHECK-NEXT:    li a6, 0
+; CHECK-NEXT:    li a7, 0
+; CHECK-NEXT:    fmv.d.x fa0, zero
+; CHECK-NEXT:    fmv.d.x fa1, zero
+; CHECK-NEXT:    fmv.d.x fa2, zero
+; CHECK-NEXT:    fmv.d.x fa3, zero
+; CHECK-NEXT:    fmv.d.x fa4, zero
+; CHECK-NEXT:    fmv.d.x fa5, zero
+; CHECK-NEXT:    fmv.d.x fa6, zero
+; CHECK-NEXT:    fmv.d.x fa7, zero
+; CHECK-NEXT:    ret
+entry:
+  ret void
+}
+
+define i32 @used(i32 %x) "zero-call-used-regs"="used" {
+; CHECK-LABEL: used:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vmv.s.x v8, zero
+; CHECK-NEXT:    vmv.v.x v9, a0
+; CHECK-NEXT:    vredsum.vs v8, v9, v8
+; CHECK-NEXT:    vmv.x.s a0, v8
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v8, 0
+; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    ret
+entry:
+    %tmp = insertelement <4 x i32> poison, i32 %x, i32 0
+    %vec = shufflevector <4 x i32> %tmp, <4 x i32> poison,
+                         <4 x i32> zeroinitializer
+
+    %sum = call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> %vec)
+    ret i32 %sum
+}
+
+define <4 x i32> @used_arg(<4 x i32> %a, <4 x i32> %b) 
"zero-call-used-regs"="used-arg" {
+; CHECK-LABEL: used_arg:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetivli zero, 4, e32, m1, ta, ma
+; CHECK-NEXT:    vadd.vv v8, v8, v9
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    ret
+entry:
+    %sum = add <4 x i32> %a, %b
+    ret <4 x i32> %sum
+}
+

>From eb0bf3ea45ab688bb31ef222b2248ca35b1e851f Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 12:49:44 +0200
Subject: [PATCH 2/8] Prefer hasVInstructions

---
 llvm/lib/Target/RISCV/RISCVCallingConv.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp 
b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
index e98bcc780e1b0..381ab62e2bd64 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
@@ -206,7 +206,7 @@ ArrayRef<MCPhysReg> RISCV::getArgFPRs(const RISCVSubtarget 
&STI) {
 }
 
 ArrayRef<MCPhysReg> RISCV::getArgVRs(const RISCVSubtarget &STI) {
-  if (STI.hasStdExtV())
+  if (STI.hasVInstructions())
     return ArrayRef(ArgVRs);
 
   return {};

>From 9b18817f04cc40ff76c2fd2c6c8d9eb9b6629824 Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 12:52:17 +0200
Subject: [PATCH 3/8] Remove stale error

---
 llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp 
b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 4bbbb3193411b..68f2c547b4e3e 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -3966,7 +3966,7 @@ void RISCVInstrInfo::buildClearRegister(Register Reg, 
MachineBasicBlock &MBB,
     BuildMI(MBB, Iter, DL, get(RISCV::PseudoClearVR), Reg);
   } else {
     llvm::reportFatalInternalError(
-        "buildClearRegister is not implemented for vector registers");
+        "buildClearRegister is not implemented for " + TRI.getRegAsmName(Reg));
   }
 }
 

>From 697216c84d21730ecf05ee5078663f634dec3863 Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 13:56:33 +0200
Subject: [PATCH 4/8] Support MMul > 1

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp  | 11 ++++--
 .../CodeGen/RISCV/zero-call-used-regs-v.ll    | 35 +++++++++++++++++++
 2 files changed, 43 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 031491b3be3cc..49418ad740389 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1513,11 +1513,16 @@ void RISCVFrameLowering::emitZeroCallUsedRegs(BitVector 
RegsToZero,
     } else if (TRI.isFPRegister(Reg)) {
       if (MCRegister MaybeReg = getLargestFPRegisterOrZero(STI, TRI, Reg))
         FinalRegsToZero.set(MaybeReg.id());
-    } else if (RISCV::VRRegClass.contains(Reg)) {
-      if (!STI.hasStdExtV())
+    } else if (RISCVRegisterInfo::isRVVRegClass(
+                   TRI.getMinimalPhysRegClass(Reg))) {
+      if (!STI.hasVInstructions())
         continue;
       HasVRegister = true;
-      FinalRegsToZero.set(Reg.id());
+
+      for (MCRegister SubReg : TRI.subregs_inclusive(Reg)) {
+        if (TRI.subregs(SubReg).empty())
+          FinalRegsToZero.set(SubReg.id());
+      }
     }
   }
 
diff --git a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll 
b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
index c270bc9960f7e..b3df824382595 100644
--- a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
+++ b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
@@ -152,3 +152,38 @@ entry:
     ret <4 x i32> %sum
 }
 
+define <8 x i32> @used_arg_lmul2(<8 x i32> %a, <8 x i32> %b) 
"zero-call-used-regs"="used-arg" {
+; CHECK-LABEL: used_arg_lmul2:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT:    vadd.vv v8, v8, v10
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    vmv.v.i v11, 0
+; CHECK-NEXT:    ret
+entry:
+    %sum = add <8 x i32> %a, %b
+    ret <8 x i32> %sum
+}
+
+define <32 x i32> @used_arg_lmul8(<32 x i32> %a, <32 x i32> %b) 
"zero-call-used-regs"="used-arg" {
+; CHECK-LABEL: used_arg_lmul8:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    li a0, 32
+; CHECK-NEXT:    vsetvli zero, a0, e32, m8, ta, ma
+; CHECK-NEXT:    vadd.vv v8, v8, v16
+; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v16, 0
+; CHECK-NEXT:    vmv.v.i v17, 0
+; CHECK-NEXT:    vmv.v.i v18, 0
+; CHECK-NEXT:    vmv.v.i v19, 0
+; CHECK-NEXT:    vmv.v.i v20, 0
+; CHECK-NEXT:    vmv.v.i v21, 0
+; CHECK-NEXT:    vmv.v.i v22, 0
+; CHECK-NEXT:    vmv.v.i v23, 0
+; CHECK-NEXT:    ret
+entry:
+    %sum = add <32 x i32> %a, %b
+    ret <32 x i32> %sum
+}
+

>From 8bc22359cca777aec36ee888bac7a96564cb7d7a Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 13:59:23 +0200
Subject: [PATCH 5/8] Also clear VSETVLI's used reg

---
 llvm/lib/Target/RISCV/RISCVFrameLowering.cpp     | 15 ++++++++++++++-
 llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll |  3 ++-
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 49418ad740389..c2ddb06212e97 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1531,7 +1531,20 @@ void RISCVFrameLowering::emitZeroCallUsedRegs(BitVector 
RegsToZero,
     unsigned VTypeImm = RISCVVType::encodeVTYPE(
         VLMUL, /*SEW=*/32, /*TailAgnostic=*/false, /*MaskAgnostic=*/false);
 
-    BuildMI(MBB, MBBI, DL, TII.get(RISCV::VSETVLI), RISCV::X5)
+    MCRegister TemporaryReg = RISCV::X5;
+    for (MCRegister Reg : FinalRegsToZero.set_bits()) {
+      if (TRI.isGeneralPurposeRegister(MF, Reg)) {
+        TemporaryReg = Reg;
+        break;
+      }
+    }
+    if (MBB.getParent()
+            ->getFunction()
+            .getFnAttribute("zero-call-used-regs")
+            .getValueAsString() == "used")
+      FinalRegsToZero.set(TemporaryReg);
+
+    BuildMI(MBB, MBBI, DL, TII.get(RISCV::VSETVLI), TemporaryReg)
         .addReg(RISCV::X0)
         .addImm(VTypeImm);
   }
diff --git a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll 
b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
index b3df824382595..0b6e914153c5b 100644
--- a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
+++ b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
@@ -80,7 +80,7 @@ entry:
 define void @all_arg() "zero-call-used-regs"="all-arg" {
 ; CHECK-LABEL: all_arg:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, tu, mu
 ; CHECK-NEXT:    vmv.v.i v8, 0
 ; CHECK-NEXT:    vmv.v.i v9, 0
 ; CHECK-NEXT:    vmv.v.i v10, 0
@@ -129,6 +129,7 @@ define i32 @used(i32 %x) "zero-call-used-regs"="used" {
 ; CHECK-NEXT:    vsetvli t0, zero, e32, m1, tu, mu
 ; CHECK-NEXT:    vmv.v.i v8, 0
 ; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    li t0, 0
 ; CHECK-NEXT:    ret
 entry:
     %tmp = insertelement <4 x i32> poison, i32 %x, i32 0

>From c55da31edb3e49dfdcc0fb0d039736aedf664a6b Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 14:16:06 +0200
Subject: [PATCH 6/8] Add a test for unaligned segmented load

---
 .../CodeGen/RISCV/zero-call-used-regs-v.ll    | 25 +++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll 
b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
index 0b6e914153c5b..e6f34e4e0761a 100644
--- a/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
+++ b/llvm/test/CodeGen/RISCV/zero-call-used-regs-v.ll
@@ -188,3 +188,28 @@ entry:
     ret <32 x i32> %sum
 }
 
+define <8 x i8> @load_segmented(ptr %base, ptr %out, <8 x i8> %use_v8) 
"zero-call-used-regs"="used" {
+; CHECK-LABEL: load_segmented:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    vsetivli zero, 0, e8, m1, ta, ma
+; CHECK-NEXT:    vlseg2e8.v v9, (a0)
+; CHECK-NEXT:    vs1r.v v9, (a1)
+; CHECK-NEXT:    vsetvli a0, zero, e32, m1, tu, mu
+; CHECK-NEXT:    vmv.v.i v9, 0
+; CHECK-NEXT:    vmv.v.i v10, 0
+; CHECK-NEXT:    li a0, 0
+; CHECK-NEXT:    li a1, 0
+; CHECK-NEXT:    ret
+entry:
+  %tuple = call target("riscv.vector.tuple", <vscale x 8 x i8>, 2)
+      @llvm.riscv.vlseg2.triscv.vector.tuple_nxv8i8_2t.i64(
+          target("riscv.vector.tuple", <vscale x 8 x i8>, 2) poison,
+          ptr %base,
+          i64 0,
+          i64 3)
+
+  %v0 = call <vscale x 8 x i8> 
@llvm.riscv.tuple.extract.nxv8i8.triscv.vector.tuple_nxv8i8_2t(
+          target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %tuple, i32 0)
+  store <vscale x 8 x i8> %v0, ptr %out
+  ret <8 x i8> %use_v8
+}

>From b29608fe4fd0569fd3ebcc6ef4b9dcae024ed4d7 Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Wed, 8 Jul 2026 16:31:06 +0200
Subject: [PATCH 7/8] Uses = [VL, VTYPE]

---
 llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
index 4a39376aa0107..c2bd8b82b2272 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td
@@ -6070,7 +6070,7 @@ foreach lmul = MxList in {
 }
 
 // Used by -fzero-call-used-regs to zero out registers.
-let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in
+let hasSideEffects = 0, mayLoad = 0, mayStore = 0, Uses = [VL, VTYPE] in
 def PseudoClearVR : Pseudo<(outs VR:$vd), (ins), []>,
                     PseudoInstExpansion<(VMV_V_I VR:$vd, 0)>;
 

>From 897c49cf40af9fdfce71b853e21be8f11ce3b949 Mon Sep 17 00:00:00 2001
From: Lucas Chollet <[email protected]>
Date: Fri, 10 Jul 2026 08:20:35 +0200
Subject: [PATCH 8/8] Update release notes

---
 clang/docs/ReleaseNotes.md | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 449a3792eb4ba..4bad3f0a84782 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -448,9 +448,7 @@ latest release, please see the [Clang Web 
Site](https://clang.llvm.org) or the
 - The `-mno-outline` and `-moutline` compiler flags are now allowed on RISC-V 
and X86, which both support the machine outliner.
 - The `-mno-outline` flag will now add the `nooutline` IR attribute, so that
   `-mno-outline` and `-moutline` objects can be mixed correctly during LTO.
-- The `-fzero-call-used-regs` compiler flag is now allowed on RISC-V, only the
-  "skip", "used-gpr", "used-gpr-arg", "all-gpr" and "all-gpr-arg" options are
-  supported for the moment.
+- The `-fzero-call-used-regs` compiler flag is now allowed on RISC-V.
 - Slightly changed hash id generation to get the unique linkage symbols names
   by `-unique-internal-linkage-names` option. Now it uses a path that
   normalized in favor of the target system (same as the preprocessor does

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to