https://github.com/kito-cheng updated 
https://github.com/llvm/llvm-project/pull/237845

>From 4bcd25547374f73a1b042f2454f941435f3f5feb Mon Sep 17 00:00:00 2001
From: Kito Cheng <[email protected]>
Date: Tue, 13 Oct 2026 12:38:30 +0800
Subject: [PATCH 1/3] [Clang][RISCV] Record the LMUL in RVV fixed-length data
 vector kinds

A riscv_rvv_vector_bits typedef of a data type keeps only the element
type and count, and later stages re-derive the LMUL from VLEN. That
breaks once typedefs may be shorter than VLEN * LMUL.

Split VectorKind::RVVFixedLengthData into RVVFixedLengthData_MF8 to _M8
and read the LMUL from the kind. VecKind grows to 5 bits.

This patch prepares to let a riscv_rvv_vector_bits typedef be shorter
than VLEN * LMUL. It only records the LMUL and does not change any
behavior.

Assisted-by: Claude
---
 clang/include/clang/AST/TypeBase.h            | 95 ++++++++++++++++++-
 clang/lib/AST/ASTContext.cpp                  |  8 +-
 clang/lib/AST/ItaniumMangle.cpp               | 32 +++----
 clang/lib/AST/JSONNodeDumper.cpp              | 14 ++-
 clang/lib/AST/TextNodeDumper.cpp              | 11 ++-
 clang/lib/AST/TypePrinter.cpp                 | 16 +++-
 clang/lib/CodeGen/Targets/RISCV.cpp           | 79 +++++++++++----
 clang/lib/Sema/SemaExpr.cpp                   |  4 +-
 clang/lib/Sema/SemaRISCV.cpp                  |  2 +-
 clang/lib/Sema/SemaType.cpp                   | 10 +-
 ...t-dump-riscv-rvv-fixed-length-data-types.c | 40 ++++++++
 11 files changed, 258 insertions(+), 53 deletions(-)
 create mode 100644 clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c

diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index 6373794bb69f54..09b381b512d0d4 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2133,7 +2133,7 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
     /// The kind of vector, either a generic vector type or some
     /// target-specific vector type such as for AltiVec or Neon.
     LLVM_PREFERRED_TYPE(VectorKind)
-    unsigned VecKind : 4;
+    unsigned VecKind : 5;
     /// The number of elements in the vector.
     uint32_t NumElements;
   };
@@ -4255,7 +4255,13 @@ enum class VectorKind {
   SveFixedLengthPredicate,
 
   /// is RISC-V RVV fixed-length data vector
-  RVVFixedLengthData,
+  RVVFixedLengthData_MF8,
+  RVVFixedLengthData_MF4,
+  RVVFixedLengthData_MF2,
+  RVVFixedLengthData_M1,
+  RVVFixedLengthData_M2,
+  RVVFixedLengthData_M4,
+  RVVFixedLengthData_M8,
 
   /// is RISC-V RVV fixed-length mask vector
   RVVFixedLengthMask,
@@ -4265,6 +4271,91 @@ enum class VectorKind {
   RVVFixedLengthMask_4
 };
 
+/// True if \p VK is one of the RVV fixed-length data vector kinds, i.e. a
+/// riscv_rvv_vector_bits typedef of a data (non-mask) RVV type.
+inline bool isRVVFixedLengthDataVectorKind(VectorKind VK) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthData_MF8:
+  case VectorKind::RVVFixedLengthData_MF4:
+  case VectorKind::RVVFixedLengthData_MF2:
+  case VectorKind::RVVFixedLengthData_M1:
+  case VectorKind::RVVFixedLengthData_M2:
+  case VectorKind::RVVFixedLengthData_M4:
+  case VectorKind::RVVFixedLengthData_M8:
+    return true;
+  default:
+    return false;
+  }
+}
+
+/// Return log2 of the LMUL recorded in an RVV fixed-length data vector kind:
+/// MF8 -> -3, MF4 -> -2, MF2 -> -1, M1 -> 0, M2 -> 1, M4 -> 2, M8 -> 3.
+inline int getRVVFixedLengthDataLMulLog2(VectorKind VK) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthData_MF8:
+    return -3;
+  case VectorKind::RVVFixedLengthData_MF4:
+    return -2;
+  case VectorKind::RVVFixedLengthData_MF2:
+    return -1;
+  case VectorKind::RVVFixedLengthData_M1:
+    return 0;
+  case VectorKind::RVVFixedLengthData_M2:
+    return 1;
+  case VectorKind::RVVFixedLengthData_M4:
+    return 2;
+  case VectorKind::RVVFixedLengthData_M8:
+    return 3;
+  default:
+    llvm_unreachable("not an RVV fixed-length data vector kind");
+  }
+}
+
+/// Return the LMUL of an RVV fixed-length data vector kind as a string:
+/// "mf8" .. "m8" if \p MF is true, "1/8" .. "8" otherwise.
+inline StringRef getRVVFixedLengthDataLMulString(VectorKind VK, bool MF) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthData_MF8:
+    return MF ? "mf8" : "1/8";
+  case VectorKind::RVVFixedLengthData_MF4:
+    return MF ? "mf4" : "1/4";
+  case VectorKind::RVVFixedLengthData_MF2:
+    return MF ? "mf2" : "1/2";
+  case VectorKind::RVVFixedLengthData_M1:
+    return MF ? "m1" : "1";
+  case VectorKind::RVVFixedLengthData_M2:
+    return MF ? "m2" : "2";
+  case VectorKind::RVVFixedLengthData_M4:
+    return MF ? "m4" : "4";
+  case VectorKind::RVVFixedLengthData_M8:
+    return MF ? "m8" : "8";
+  default:
+    llvm_unreachable("not an RVV fixed-length data vector kind");
+  }
+}
+
+/// Inverse of getRVVFixedLengthDataLMulLog2().
+inline VectorKind getRVVFixedLengthDataVectorKind(int LMulLog2) {
+  switch (LMulLog2) {
+  case -3:
+    return VectorKind::RVVFixedLengthData_MF8;
+  case -2:
+    return VectorKind::RVVFixedLengthData_MF4;
+  case -1:
+    return VectorKind::RVVFixedLengthData_MF2;
+  case 0:
+    return VectorKind::RVVFixedLengthData_M1;
+  case 1:
+    return VectorKind::RVVFixedLengthData_M2;
+  case 2:
+    return VectorKind::RVVFixedLengthData_M4;
+  case 3:
+    return VectorKind::RVVFixedLengthData_M8;
+  default:
+    llvm_unreachable("LMUL out of range for an RVV type");
+  }
+}
+
 /// Represents a GCC generic vector type. This type is created using
 /// __attribute__((vector_size(n)), where "n" specifies the vector size in
 /// bytes; or from an Altivec __vector or vector declaration.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 01d71388cbc0e3..6afc80a2b908bb 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -2155,7 +2155,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const 
{
     else if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate)
       // Adjust the alignment for fixed-length SVE predicates.
       Align = 16;
-    else if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
+    else if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
              VT->getVectorKind() == VectorKind::RVVFixedLengthMask ||
              VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
              VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
@@ -10771,8 +10771,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType 
FirstVec,
       First->getVectorKind() != VectorKind::SveFixedLengthPredicate &&
       Second->getVectorKind() != VectorKind::SveFixedLengthData &&
       Second->getVectorKind() != VectorKind::SveFixedLengthPredicate &&
-      First->getVectorKind() != VectorKind::RVVFixedLengthData &&
-      Second->getVectorKind() != VectorKind::RVVFixedLengthData &&
+      !isRVVFixedLengthDataVectorKind(First->getVectorKind()) &&
+      !isRVVFixedLengthDataVectorKind(Second->getVectorKind()) &&
       First->getVectorKind() != VectorKind::RVVFixedLengthMask &&
       Second->getVectorKind() != VectorKind::RVVFixedLengthMask &&
       First->getVectorKind() != VectorKind::RVVFixedLengthMask_1 &&
@@ -10884,7 +10884,7 @@ bool ASTContext::areCompatibleRVVTypes(QualType 
FirstType,
                  Info.ElementType == BoolTy &&
                  getTypeSize(SecondType) == ((getRVVTypeSize(*this, BT)) * 2);
         }
-        if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
+        if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
             VT->getVectorKind() == VectorKind::Generic)
           return FirstType->isRVVVLSBuiltinType() &&
                  getTypeSize(SecondType) == getRVVTypeSize(*this, BT) &&
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 02f27cec53f699..8fd9059abcdf3d 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4316,7 +4316,7 @@ void CXXNameMangler::mangleAArch64FixedSveVectorType(
 }
 
 void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
-  assert((T->getVectorKind() == VectorKind::RVVFixedLengthData ||
+  assert((isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
           T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
           T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
           T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
@@ -4335,7 +4335,7 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const 
VectorType *T) {
     TypeNameOS << "int8";
     break;
   case BuiltinType::UChar:
-    if (T->getVectorKind() == VectorKind::RVVFixedLengthData)
+    if (isRVVFixedLengthDataVectorKind(T->getVectorKind()))
       TypeNameOS << "uint8";
     else
       TypeNameOS << "bool";
@@ -4392,19 +4392,19 @@ void 
CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
     break;
   }
 
-  // Apend the LMUL suffix.
-  auto VScale = getASTContext().getTargetInfo().getVScaleRange(
-      getASTContext().getLangOpts(),
-      TargetInfo::ArmStreamingKind::NotStreaming);
-  unsigned VLen = VScale->first * llvm::RISCV::RVVBitsPerBlock;
-
-  if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
-    TypeNameOS << 'm';
-    if (VecSizeInBits >= VLen)
-      TypeNameOS << (VecSizeInBits / VLen);
-    else
-      TypeNameOS << 'f' << (VLen / VecSizeInBits);
+  // Append the LMUL suffix. For data types the LMUL is recorded in the vector
+  // kind, so the mangled name names the type the typedef was written against
+  // even when the typedef is shorter than VLEN * LMUL, and does not depend on
+  // VLEN at all. Mask types are still tied to a fixed VLEN, so their ratio is
+  // derived from it.
+  if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
+    TypeNameOS << getRVVFixedLengthDataLMulString(T->getVectorKind(),
+                                                  /*MF=*/true);
   } else {
+    auto VScale = getASTContext().getTargetInfo().getVScaleRange(
+        getASTContext().getLangOpts(),
+        TargetInfo::ArmStreamingKind::NotStreaming);
+    unsigned VLen = VScale->first * llvm::RISCV::RVVBitsPerBlock;
     TypeNameOS << (VLen / VecSizeInBits);
   }
   TypeNameOS << "_t";
@@ -4445,7 +4445,7 @@ void CXXNameMangler::mangleType(const VectorType *T) {
              T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
     mangleAArch64FixedSveVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData ||
+  } else if (isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
              T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
              T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
              T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
@@ -4478,7 +4478,7 @@ void CXXNameMangler::mangleType(const DependentVectorType 
*T) {
              T->getVectorKind() == VectorKind::SveFixedLengthPredicate) {
     mangleAArch64FixedSveVectorType(T);
     return;
-  } else if (T->getVectorKind() == VectorKind::RVVFixedLengthData) {
+  } else if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
     mangleRISCVFixedRVVVectorType(T);
     return;
   }
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 75abc4777f717f..2555c3658df02f 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -750,8 +750,18 @@ void JSONNodeDumper::VisitVectorType(const VectorType *VT) 
{
   case VectorKind::SveFixedLengthPredicate:
     JOS.attribute("vectorKind", "fixed-length sve predicate vector");
     break;
-  case VectorKind::RVVFixedLengthData:
-    JOS.attribute("vectorKind", "fixed-length rvv data vector");
+  case VectorKind::RVVFixedLengthData_MF8:
+  case VectorKind::RVVFixedLengthData_MF4:
+  case VectorKind::RVVFixedLengthData_MF2:
+  case VectorKind::RVVFixedLengthData_M1:
+  case VectorKind::RVVFixedLengthData_M2:
+  case VectorKind::RVVFixedLengthData_M4:
+  case VectorKind::RVVFixedLengthData_M8:
+    JOS.attribute("vectorKind",
+                  "fixed-length rvv data vector lmul " +
+                      getRVVFixedLengthDataLMulString(VT->getVectorKind(),
+                                                      /*MF=*/false)
+                          .str());
     break;
   case VectorKind::RVVFixedLengthMask:
   case VectorKind::RVVFixedLengthMask_1:
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 497fca228e428d..f1b216d970c731 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2168,8 +2168,15 @@ void TextNodeDumper::VisitVectorType(const VectorType 
*T) {
   case VectorKind::SveFixedLengthPredicate:
     OS << " fixed-length sve predicate vector";
     break;
-  case VectorKind::RVVFixedLengthData:
-    OS << " fixed-length rvv data vector";
+  case VectorKind::RVVFixedLengthData_MF8:
+  case VectorKind::RVVFixedLengthData_MF4:
+  case VectorKind::RVVFixedLengthData_MF2:
+  case VectorKind::RVVFixedLengthData_M1:
+  case VectorKind::RVVFixedLengthData_M2:
+  case VectorKind::RVVFixedLengthData_M4:
+  case VectorKind::RVVFixedLengthData_M8:
+    OS << " fixed-length rvv data vector lmul "
+       << getRVVFixedLengthDataLMulString(T->getVectorKind(), /*MF=*/false);
     break;
   case VectorKind::RVVFixedLengthMask:
   case VectorKind::RVVFixedLengthMask_1:
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 13929f6fe08005..12cce9ccc32a55 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -718,7 +718,13 @@ void TypePrinter::printVectorBefore(const VectorType *T, 
raw_ostream &OS) {
     OS << ") * 8))) ";
     printBefore(T->getElementType(), OS);
     break;
-  case VectorKind::RVVFixedLengthData:
+  case VectorKind::RVVFixedLengthData_MF8:
+  case VectorKind::RVVFixedLengthData_MF4:
+  case VectorKind::RVVFixedLengthData_MF2:
+  case VectorKind::RVVFixedLengthData_M1:
+  case VectorKind::RVVFixedLengthData_M2:
+  case VectorKind::RVVFixedLengthData_M4:
+  case VectorKind::RVVFixedLengthData_M8:
   case VectorKind::RVVFixedLengthMask:
   case VectorKind::RVVFixedLengthMask_1:
   case VectorKind::RVVFixedLengthMask_2:
@@ -813,7 +819,13 @@ void TypePrinter::printDependentVectorBefore(
     OS << "))) ";
     printBefore(T->getElementType(), OS);
     break;
-  case VectorKind::RVVFixedLengthData:
+  case VectorKind::RVVFixedLengthData_MF8:
+  case VectorKind::RVVFixedLengthData_MF4:
+  case VectorKind::RVVFixedLengthData_MF2:
+  case VectorKind::RVVFixedLengthData_M1:
+  case VectorKind::RVVFixedLengthData_M2:
+  case VectorKind::RVVFixedLengthData_M4:
+  case VectorKind::RVVFixedLengthData_M8:
   case VectorKind::RVVFixedLengthMask:
   case VectorKind::RVVFixedLengthMask_1:
   case VectorKind::RVVFixedLengthMask_2:
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp 
b/clang/lib/CodeGen/Targets/RISCV.cpp
index 4bac5711a2dd66..c84a4f00f4bc7f 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -40,6 +40,8 @@ class RISCVABIInfo : public DefaultABIInfo {
 
   llvm::Type *detectHomogeneousRVVFixedLengthStruct(QualType Ty) const;
 
+  unsigned getRVVFixedLengthMinElts(const VectorType *VT) const;
+
 public:
   RISCVABIInfo(CodeGen::CodeGenTypes &CGT, unsigned XLen, unsigned FLen,
                bool EABI)
@@ -410,6 +412,35 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
   return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType);
 }
 
+/// Minimum element count of the scalable vector an RVV fixed-length *data*
+/// vector is coerced to, i.e. the N in <vscale x N x T>. The LMUL comes from
+/// the vector kind - the type the typedef was written against - rather than
+/// from VLEN and the element count.
+static unsigned getRVVFixedLengthDataMinElts(VectorKind VK,
+                                             unsigned EltSizeInBits) {
+  // The underlying scalable type holds LMUL * RVVBitsPerBlock bits at
+  // vscale=1.
+  int LMulLog2 = getRVVFixedLengthDataLMulLog2(VK);
+  unsigned SizeAtVScale1 = LMulLog2 >= 0
+                               ? llvm::RISCV::RVVBitsPerBlock << LMulLog2
+                               : llvm::RISCV::RVVBitsPerBlock >> -LMulLog2;
+  assert(SizeAtVScale1 >= EltSizeInBits && "LMUL too small for element type");
+  return SizeAtVScale1 / EltSizeInBits;
+}
+
+/// Minimum element count of the scalable vector \p VT is coerced to, in units
+/// of \p VT's own Clang element type. Masks are modelled as i8 vectors and are
+/// exactly VLEN * LMUL wide, so their LMUL is recovered from VLEN.
+unsigned RISCVABIInfo::getRVVFixedLengthMinElts(const VectorType *VT) const {
+  unsigned EltSizeInBits = getContext().getTypeSize(VT->getElementType());
+  if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()))
+    return getRVVFixedLengthDataMinElts(VT->getVectorKind(), EltSizeInBits);
+
+  auto VScale = getContext().getTargetInfo().getVScaleRange(
+      getContext().getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming);
+  return llvm::divideCeil(VT->getNumElements(), VScale->first);
+}
+
 llvm::Type *RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty,
                                                     unsigned ABIVLen) const {
   // No riscv_vls_cc attribute.
@@ -556,8 +587,9 @@ 
RISCVABIInfo::detectHomogeneousRVVFixedLengthStruct(QualType Ty) const {
     return nullptr;
 
   auto IsFixedLengthRVVVector = [](const VectorType *VT) {
+    if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()))
+      return true;
     switch (VT->getVectorKind()) {
-    case VectorKind::RVVFixedLengthData:
     case VectorKind::RVVFixedLengthMask:
     case VectorKind::RVVFixedLengthMask_1:
     case VectorKind::RVVFixedLengthMask_2:
@@ -607,24 +639,21 @@ 
RISCVABIInfo::detectHomogeneousRVVFixedLengthStruct(QualType Ty) const {
 
   const auto *VT = CommonTy->castAs<VectorType>();
   llvm::Type *EltType = CGT.ConvertType(VT->getElementType());
-  auto VScale = getContext().getTargetInfo().getVScaleRange(
-      getContext().getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming);
-
-  // Ensure total register usage does not exceed 8.
-  if (Count > 1 &&
-      Count * llvm::divideCeil((uint64_t)VT->getNumElements() *
-                                   EltType->getScalarSizeInBits(),
-                               VScale->first * llvm::RISCV::RVVBitsPerBlock) >
-          8)
+  unsigned MinElts = getRVVFixedLengthMinElts(VT);
+
+  // Ensure total register usage does not exceed 8. Each vector occupies
+  // max(1, LMUL) registers.
+  uint64_t RegsPerVec =
+      llvm::divideCeil((uint64_t)MinElts * EltType->getScalarSizeInBits(),
+                       llvm::RISCV::RVVBitsPerBlock);
+  if (Count > 1 && Count * RegsPerVec > 8)
     return nullptr;
 
-  unsigned MinElts = llvm::divideCeil(VT->getNumElements(), VScale->first);
   if (Count == 1)
     return llvm::ScalableVectorType::get(EltType, MinElts);
 
-  unsigned I8EltCount = llvm::divideCeil((uint64_t)VT->getNumElements() *
-                                             EltType->getScalarSizeInBits(),
-                                         VScale->first * 8);
+  unsigned I8EltCount =
+      llvm::divideCeil((uint64_t)MinElts * EltType->getScalarSizeInBits(), 8);
   auto *I8Vec = llvm::ScalableVectorType::get(
       llvm::Type::getInt8Ty(getVMContext()), I8EltCount);
   return llvm::TargetExtType::get(getVMContext(), "riscv.vector.tuple", I8Vec,
@@ -675,7 +704,7 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, 
unsigned ABIVLen) const {
     break;
   default:
     assert((VT->getVectorKind() == VectorKind::Generic ||
-            VT->getVectorKind() == VectorKind::RVVFixedLengthData) &&
+            isRVVFixedLengthDataVectorKind(VT->getVectorKind())) &&
            "Unexpected vector kind");
     EltType = CGT.ConvertType(VT->getElementType());
   }
@@ -683,11 +712,19 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, 
unsigned ABIVLen) const {
   llvm::ScalableVectorType *ResType;
 
   if (ABIVLen == 0) {
-    // The MinNumElts is simplified from equation:
-    // NumElts / VScale =
-    //  (EltSize * NumElts / (VScale * RVVBitsPerBlock))
-    //    * (RVVBitsPerBlock / EltSize)
-    ResType = llvm::ScalableVectorType::get(EltType, NumElts / VScale->first);
+    unsigned MinScalableElts;
+    if (isRVVFixedLengthDataVectorKind(VT->getVectorKind())) {
+      // Use the LMUL of the type the typedef was written against.
+      MinScalableElts = getRVVFixedLengthDataMinElts(
+          VT->getVectorKind(), EltType->getScalarSizeInBits());
+    } else {
+      // The MinNumElts is simplified from equation:
+      // NumElts / VScale =
+      //  (EltSize * NumElts / (VScale * RVVBitsPerBlock))
+      //    * (RVVBitsPerBlock / EltSize)
+      MinScalableElts = NumElts / VScale->first;
+    }
+    ResType = llvm::ScalableVectorType::get(EltType, MinScalableElts);
   } else {
     // Check registers needed <= 8.
     if ((EltType->getScalarSizeInBits() * NumElts / ABIVLen) > 8)
@@ -824,7 +861,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, 
bool IsFixed,
   // https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/419
   if (const VectorType *VT = Ty->getAs<VectorType>();
       VT && !VT->getElementType()->isBitIntType()) {
-    if (VT->getVectorKind() == VectorKind::RVVFixedLengthData ||
+    if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
         VT->getVectorKind() == VectorKind::RVVFixedLengthMask ||
         VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
         VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 00dd8acf1f68dd..9a11c859997eb6 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11061,7 +11061,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, 
ExprResult &RHS,
       if (VecType->getVectorKind() == VectorKind::SveFixedLengthData ||
           VecType->getVectorKind() == VectorKind::SveFixedLengthPredicate)
         return true;
-      if (VecType->getVectorKind() == VectorKind::RVVFixedLengthData ||
+      if (isRVVFixedLengthDataVectorKind(VecType->getVectorKind()) ||
           VecType->getVectorKind() == VectorKind::RVVFixedLengthMask ||
           VecType->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
           VecType->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
@@ -11096,7 +11096,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, 
ExprResult &RHS,
             SecondVecType->getVectorKind() ==
                 VectorKind::SveFixedLengthPredicate)
           return true;
-        if (SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthData ||
+        if (isRVVFixedLengthDataVectorKind(SecondVecType->getVectorKind()) ||
             SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthMask ||
             SecondVecType->getVectorKind() ==
                 VectorKind::RVVFixedLengthMask_1 ||
diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp
index a1ba3b3934daa6..907123cd6379c0 100644
--- a/clang/lib/Sema/SemaRISCV.cpp
+++ b/clang/lib/Sema/SemaRISCV.cpp
@@ -1634,7 +1634,7 @@ bool SemaRISCV::isValidRVVBitcast(QualType srcTy, 
QualType destTy) {
       return false;
 
     const auto *VecTy = SecondType->getAs<VectorType>();
-    return VecTy && VecTy->getVectorKind() == VectorKind::RVVFixedLengthData;
+    return VecTy && isRVVFixedLengthDataVectorKind(VecTy->getVectorKind());
   };
 
   return ValidScalableConversion(srcTy, destTy) ||
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index f55c78b138d9ad..9c299b9e55da8d 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -46,6 +46,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
 #include <bitset>
 #include <optional>
 
@@ -8870,7 +8871,7 @@ static void HandleRISCVRVVVectorBitsTypeAttr(QualType 
&CurType,
       S.Context.getBuiltinVectorTypeInfo(CurType->castAs<BuiltinType>());
   unsigned MinElts = Info.EC.getKnownMinValue();
 
-  VectorKind VecKind = VectorKind::RVVFixedLengthData;
+  VectorKind VecKind = VectorKind::RVVFixedLengthMask;
   unsigned ExpectedSize = VScale->first * MinElts;
   QualType EltType = CurType->getRVVEltType(S.Context);
   unsigned EltSize = S.Context.getTypeSize(EltType);
@@ -8895,6 +8896,13 @@ static void HandleRISCVRVVVectorBitsTypeAttr(QualType 
&CurType,
   } else {
     ExpectedSize *= EltSize;
     NumElts = VecSize / EltSize;
+
+    // Record the LMUL of the sizeless type in the vector kind, so that later
+    // stages do not have to re-derive it from VLEN and the element count.
+    //   LMUL = MinElts * EltSize / RVVBitsPerBlock
+    VecKind = getRVVFixedLengthDataVectorKind(
+        int(llvm::Log2_32(MinElts * EltSize)) -
+        int(llvm::Log2_32(llvm::RISCV::RVVBitsPerBlock)));
   }
 
   // The attribute vector size must match -mrvv-vector-bits.
diff --git a/clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c 
b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c
new file mode 100644
index 00000000000000..4ba0ea48ba4240
--- /dev/null
+++ b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c
@@ -0,0 +1,40 @@
+// Verify that a riscv_rvv_vector_bits typedef of a data type records the LMUL
+// of the sizeless type it was written against.
+
+// RUN: %clang_cc1 -triple riscv64-none-linux-gnu -target-feature +zve64d \
+// RUN:   -mvscale-min=2 -mvscale-max=2 -ast-dump %s | FileCheck %s
+// RUN: %clang_cc1 -triple riscv64-none-linux-gnu -target-feature +zve64d \
+// RUN:   -mvscale-min=2 -mvscale-max=2 -ast-dump=json %s \
+// RUN:   | FileCheck %s --check-prefix=JSON
+
+// VLEN=128.
+typedef __rvv_int8mf8_t fixed_i8mf8 __attribute__((riscv_rvv_vector_bits(16)));
+typedef __rvv_int16mf4_t fixed_i16mf4 
__attribute__((riscv_rvv_vector_bits(32)));
+typedef __rvv_int32mf2_t fixed_i32mf2 
__attribute__((riscv_rvv_vector_bits(64)));
+typedef __rvv_int32m1_t fixed_i32m1 
__attribute__((riscv_rvv_vector_bits(128)));
+typedef __rvv_int32m2_t fixed_i32m2 
__attribute__((riscv_rvv_vector_bits(256)));
+typedef __rvv_int64m4_t fixed_i64m4 
__attribute__((riscv_rvv_vector_bits(512)));
+typedef __rvv_int8m8_t fixed_i8m8 __attribute__((riscv_rvv_vector_bits(1024)));
+
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i8mf8
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/8 2
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i16mf4
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/4 2
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i32mf2
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/2 2
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i32m1
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1 4
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i32m2
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 2 8
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i64m4
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 4 8
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_i8m8
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 8 128
+
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/8"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/4"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/2"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 1"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 2"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 4"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul 8"

>From b403710c1b536f5736a8a597941b83cb88196a3b Mon Sep 17 00:00:00 2001
From: Kito Cheng <[email protected]>
Date: Tue, 3 Nov 2026 09:23:59 +0800
Subject: [PATCH 2/3] fixup! [Clang][RISCV] Record the LMUL in RVV fixed-length
 data vector kinds

Record the ratio in RVV fixed-length mask vector kinds too. Replace
RVVFixedLengthMask{,_1,_2,_4} with RVVFixedLengthMaskRatio<R> and
RVVFixedLengthMaskRatio<R>_{1,2,4}, and read R from the kind instead of
re-deriving it from VLEN. VecKind grows to 6 bits.

Assisted-by: Claude
---
 clang/include/clang/AST/TypeBase.h            | 217 +++++++++++++++++-
 clang/lib/AST/ASTContext.cpp                  |  44 +---
 clang/lib/AST/ItaniumMangle.cpp               |  45 +---
 clang/lib/AST/JSONNodeDumper.cpp              |  33 ++-
 clang/lib/AST/TextNodeDumper.cpp              |  25 +-
 clang/lib/AST/TypePrinter.cpp                 |  73 ++----
 clang/lib/CodeGen/Targets/RISCV.cpp           |  61 ++---
 clang/lib/Sema/SemaExpr.cpp                   |  13 +-
 clang/lib/Sema/SemaType.cpp                   |  26 +--
 ...ump-riscv-rvv-fixed-length-vector-kinds.c} |  20 +-
 10 files changed, 335 insertions(+), 222 deletions(-)
 rename clang/test/AST/{ast-dump-riscv-rvv-fixed-length-data-types.c => 
ast-dump-riscv-rvv-fixed-length-vector-kinds.c} (64%)

diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index 09b381b512d0d4..4f4f4b8a22d63c 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -2133,7 +2133,7 @@ class alignas(TypeAlignment) Type : public 
ExtQualsTypeCommonBase {
     /// The kind of vector, either a generic vector type or some
     /// target-specific vector type such as for AltiVec or Neon.
     LLVM_PREFERRED_TYPE(VectorKind)
-    unsigned VecKind : 5;
+    unsigned VecKind : 6;
     /// The number of elements in the vector.
     uint32_t NumElements;
   };
@@ -4263,12 +4263,36 @@ enum class VectorKind {
   RVVFixedLengthData_M4,
   RVVFixedLengthData_M8,
 
-  /// is RISC-V RVV fixed-length mask vector
-  RVVFixedLengthMask,
-
-  RVVFixedLengthMask_1,
-  RVVFixedLengthMask_2,
-  RVVFixedLengthMask_4
+  /// is RISC-V RVV fixed-length mask vector of vbool<R>_t; the _<L> kinds
+  /// have only L lanes in a single byte
+  RVVFixedLengthMaskRatio1,
+  RVVFixedLengthMaskRatio1_1,
+  RVVFixedLengthMaskRatio1_2,
+  RVVFixedLengthMaskRatio1_4,
+  RVVFixedLengthMaskRatio2,
+  RVVFixedLengthMaskRatio2_1,
+  RVVFixedLengthMaskRatio2_2,
+  RVVFixedLengthMaskRatio2_4,
+  RVVFixedLengthMaskRatio4,
+  RVVFixedLengthMaskRatio4_1,
+  RVVFixedLengthMaskRatio4_2,
+  RVVFixedLengthMaskRatio4_4,
+  RVVFixedLengthMaskRatio8,
+  RVVFixedLengthMaskRatio8_1,
+  RVVFixedLengthMaskRatio8_2,
+  RVVFixedLengthMaskRatio8_4,
+  RVVFixedLengthMaskRatio16,
+  RVVFixedLengthMaskRatio16_1,
+  RVVFixedLengthMaskRatio16_2,
+  RVVFixedLengthMaskRatio16_4,
+  RVVFixedLengthMaskRatio32,
+  RVVFixedLengthMaskRatio32_1,
+  RVVFixedLengthMaskRatio32_2,
+  RVVFixedLengthMaskRatio32_4,
+  RVVFixedLengthMaskRatio64,
+  RVVFixedLengthMaskRatio64_1,
+  RVVFixedLengthMaskRatio64_2,
+  RVVFixedLengthMaskRatio64_4
 };
 
 /// True if \p VK is one of the RVV fixed-length data vector kinds, i.e. a
@@ -4356,6 +4380,178 @@ inline VectorKind getRVVFixedLengthDataVectorKind(int 
LMulLog2) {
   }
 }
 
+/// True if \p VK is one of the RVV fixed-length mask vector kinds, i.e. a
+/// riscv_rvv_vector_bits typedef of a vbool<R>_t type.
+inline bool isRVVFixedLengthMaskVectorKind(VectorKind VK) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthMaskRatio1:
+  case VectorKind::RVVFixedLengthMaskRatio1_1:
+  case VectorKind::RVVFixedLengthMaskRatio1_2:
+  case VectorKind::RVVFixedLengthMaskRatio1_4:
+  case VectorKind::RVVFixedLengthMaskRatio2:
+  case VectorKind::RVVFixedLengthMaskRatio2_1:
+  case VectorKind::RVVFixedLengthMaskRatio2_2:
+  case VectorKind::RVVFixedLengthMaskRatio2_4:
+  case VectorKind::RVVFixedLengthMaskRatio4:
+  case VectorKind::RVVFixedLengthMaskRatio4_1:
+  case VectorKind::RVVFixedLengthMaskRatio4_2:
+  case VectorKind::RVVFixedLengthMaskRatio4_4:
+  case VectorKind::RVVFixedLengthMaskRatio8:
+  case VectorKind::RVVFixedLengthMaskRatio8_1:
+  case VectorKind::RVVFixedLengthMaskRatio8_2:
+  case VectorKind::RVVFixedLengthMaskRatio8_4:
+  case VectorKind::RVVFixedLengthMaskRatio16:
+  case VectorKind::RVVFixedLengthMaskRatio16_1:
+  case VectorKind::RVVFixedLengthMaskRatio16_2:
+  case VectorKind::RVVFixedLengthMaskRatio16_4:
+  case VectorKind::RVVFixedLengthMaskRatio32:
+  case VectorKind::RVVFixedLengthMaskRatio32_1:
+  case VectorKind::RVVFixedLengthMaskRatio32_2:
+  case VectorKind::RVVFixedLengthMaskRatio32_4:
+  case VectorKind::RVVFixedLengthMaskRatio64:
+  case VectorKind::RVVFixedLengthMaskRatio64_1:
+  case VectorKind::RVVFixedLengthMaskRatio64_2:
+  case VectorKind::RVVFixedLengthMaskRatio64_4:
+    return true;
+  default:
+    return false;
+  }
+}
+
+/// Return log2 of the R of the vbool<R>_t type recorded in an RVV fixed-length
+/// mask vector kind: Ratio1 -> 0, Ratio2 -> 1, ..., Ratio64 -> 6.
+inline unsigned getRVVFixedLengthMaskRatioLog2(VectorKind VK) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthMaskRatio1:
+  case VectorKind::RVVFixedLengthMaskRatio1_1:
+  case VectorKind::RVVFixedLengthMaskRatio1_2:
+  case VectorKind::RVVFixedLengthMaskRatio1_4:
+    return 0;
+  case VectorKind::RVVFixedLengthMaskRatio2:
+  case VectorKind::RVVFixedLengthMaskRatio2_1:
+  case VectorKind::RVVFixedLengthMaskRatio2_2:
+  case VectorKind::RVVFixedLengthMaskRatio2_4:
+    return 1;
+  case VectorKind::RVVFixedLengthMaskRatio4:
+  case VectorKind::RVVFixedLengthMaskRatio4_1:
+  case VectorKind::RVVFixedLengthMaskRatio4_2:
+  case VectorKind::RVVFixedLengthMaskRatio4_4:
+    return 2;
+  case VectorKind::RVVFixedLengthMaskRatio8:
+  case VectorKind::RVVFixedLengthMaskRatio8_1:
+  case VectorKind::RVVFixedLengthMaskRatio8_2:
+  case VectorKind::RVVFixedLengthMaskRatio8_4:
+    return 3;
+  case VectorKind::RVVFixedLengthMaskRatio16:
+  case VectorKind::RVVFixedLengthMaskRatio16_1:
+  case VectorKind::RVVFixedLengthMaskRatio16_2:
+  case VectorKind::RVVFixedLengthMaskRatio16_4:
+    return 4;
+  case VectorKind::RVVFixedLengthMaskRatio32:
+  case VectorKind::RVVFixedLengthMaskRatio32_1:
+  case VectorKind::RVVFixedLengthMaskRatio32_2:
+  case VectorKind::RVVFixedLengthMaskRatio32_4:
+    return 5;
+  case VectorKind::RVVFixedLengthMaskRatio64:
+  case VectorKind::RVVFixedLengthMaskRatio64_1:
+  case VectorKind::RVVFixedLengthMaskRatio64_2:
+  case VectorKind::RVVFixedLengthMaskRatio64_4:
+    return 6;
+  default:
+    llvm_unreachable("not an RVV fixed-length mask vector kind");
+  }
+}
+
+/// Return the number of lanes (1, 2 or 4) of an RVV fixed-length mask vector
+/// kind that fits in less than one byte, or 0 if its lanes fill whole bytes.
+inline unsigned getRVVFixedLengthMaskSubByteLanes(VectorKind VK) {
+  switch (VK) {
+  case VectorKind::RVVFixedLengthMaskRatio1:
+  case VectorKind::RVVFixedLengthMaskRatio2:
+  case VectorKind::RVVFixedLengthMaskRatio4:
+  case VectorKind::RVVFixedLengthMaskRatio8:
+  case VectorKind::RVVFixedLengthMaskRatio16:
+  case VectorKind::RVVFixedLengthMaskRatio32:
+  case VectorKind::RVVFixedLengthMaskRatio64:
+    return 0;
+  case VectorKind::RVVFixedLengthMaskRatio1_1:
+  case VectorKind::RVVFixedLengthMaskRatio2_1:
+  case VectorKind::RVVFixedLengthMaskRatio4_1:
+  case VectorKind::RVVFixedLengthMaskRatio8_1:
+  case VectorKind::RVVFixedLengthMaskRatio16_1:
+  case VectorKind::RVVFixedLengthMaskRatio32_1:
+  case VectorKind::RVVFixedLengthMaskRatio64_1:
+    return 1;
+  case VectorKind::RVVFixedLengthMaskRatio1_2:
+  case VectorKind::RVVFixedLengthMaskRatio2_2:
+  case VectorKind::RVVFixedLengthMaskRatio4_2:
+  case VectorKind::RVVFixedLengthMaskRatio8_2:
+  case VectorKind::RVVFixedLengthMaskRatio16_2:
+  case VectorKind::RVVFixedLengthMaskRatio32_2:
+  case VectorKind::RVVFixedLengthMaskRatio64_2:
+    return 2;
+  case VectorKind::RVVFixedLengthMaskRatio1_4:
+  case VectorKind::RVVFixedLengthMaskRatio2_4:
+  case VectorKind::RVVFixedLengthMaskRatio4_4:
+  case VectorKind::RVVFixedLengthMaskRatio8_4:
+  case VectorKind::RVVFixedLengthMaskRatio16_4:
+  case VectorKind::RVVFixedLengthMaskRatio32_4:
+  case VectorKind::RVVFixedLengthMaskRatio64_4:
+    return 4;
+  default:
+    llvm_unreachable("not an RVV fixed-length mask vector kind");
+  }
+}
+
+/// Inverse of getRVVFixedLengthMaskRatioLog2() and
+/// getRVVFixedLengthMaskSubByteLanes().
+inline VectorKind getRVVFixedLengthMaskVectorKind(unsigned RatioLog2,
+                                                  unsigned SubByteLanes) {
+  static constexpr VectorKind Kinds[7][4] = {
+      {VectorKind::RVVFixedLengthMaskRatio1,
+       VectorKind::RVVFixedLengthMaskRatio1_1,
+       VectorKind::RVVFixedLengthMaskRatio1_2,
+       VectorKind::RVVFixedLengthMaskRatio1_4},
+      {VectorKind::RVVFixedLengthMaskRatio2,
+       VectorKind::RVVFixedLengthMaskRatio2_1,
+       VectorKind::RVVFixedLengthMaskRatio2_2,
+       VectorKind::RVVFixedLengthMaskRatio2_4},
+      {VectorKind::RVVFixedLengthMaskRatio4,
+       VectorKind::RVVFixedLengthMaskRatio4_1,
+       VectorKind::RVVFixedLengthMaskRatio4_2,
+       VectorKind::RVVFixedLengthMaskRatio4_4},
+      {VectorKind::RVVFixedLengthMaskRatio8,
+       VectorKind::RVVFixedLengthMaskRatio8_1,
+       VectorKind::RVVFixedLengthMaskRatio8_2,
+       VectorKind::RVVFixedLengthMaskRatio8_4},
+      {VectorKind::RVVFixedLengthMaskRatio16,
+       VectorKind::RVVFixedLengthMaskRatio16_1,
+       VectorKind::RVVFixedLengthMaskRatio16_2,
+       VectorKind::RVVFixedLengthMaskRatio16_4},
+      {VectorKind::RVVFixedLengthMaskRatio32,
+       VectorKind::RVVFixedLengthMaskRatio32_1,
+       VectorKind::RVVFixedLengthMaskRatio32_2,
+       VectorKind::RVVFixedLengthMaskRatio32_4},
+      {VectorKind::RVVFixedLengthMaskRatio64,
+       VectorKind::RVVFixedLengthMaskRatio64_1,
+       VectorKind::RVVFixedLengthMaskRatio64_2,
+       VectorKind::RVVFixedLengthMaskRatio64_4},
+  };
+  assert(RatioLog2 < 7 && "ratio out of range for an RVV mask type");
+  switch (SubByteLanes) {
+  case 0:
+    return Kinds[RatioLog2][0];
+  case 1:
+    return Kinds[RatioLog2][1];
+  case 2:
+    return Kinds[RatioLog2][2];
+  case 4:
+    return Kinds[RatioLog2][3];
+  default:
+    llvm_unreachable("unexpected sub-byte lane count");
+  }
+}
+
 /// Represents a GCC generic vector type. This type is created using
 /// __attribute__((vector_size(n)), where "n" specifies the vector size in
 /// bytes; or from an Altivec __vector or vector declaration.
@@ -4385,6 +4581,13 @@ class VectorType : public Type, public 
llvm::FoldingSetNode {
     return VectorKind(VectorTypeBits.VecKind);
   }
 
+  /// Return the number of lanes of an RVV fixed-length mask vector. Its
+  /// elements are bytes, but each lane is a single bit.
+  unsigned getRVVFixedLengthMaskLanes() const {
+    unsigned SubByteLanes = getRVVFixedLengthMaskSubByteLanes(getVectorKind());
+    return SubByteLanes ? SubByteLanes : getNumElements() * 8;
+  }
+
   void Profile(llvm::FoldingSetNodeID &ID) {
     Profile(ID, getElementType(), getNumElements(),
             getTypeClass(), getVectorKind());
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 6afc80a2b908bb..4a2bb929be42eb 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -91,6 +91,7 @@
 #include "llvm/Support/SipHash.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/TargetParser/AArch64TargetParser.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 #include <algorithm>
 #include <cassert>
@@ -2156,10 +2157,7 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) 
const {
       // Adjust the alignment for fixed-length SVE predicates.
       Align = 16;
     else if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
-             VT->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-             VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-             VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-             VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4)
+             isRVVFixedLengthMaskVectorKind(VT->getVectorKind()))
       // Adjust the alignment for fixed-length RVV vectors.
       Align = std::min<unsigned>(64, Width);
     // Vector types have their natural alignment resist reduction by
@@ -10773,14 +10771,8 @@ bool ASTContext::areCompatibleVectorTypes(QualType 
FirstVec,
       Second->getVectorKind() != VectorKind::SveFixedLengthPredicate &&
       !isRVVFixedLengthDataVectorKind(First->getVectorKind()) &&
       !isRVVFixedLengthDataVectorKind(Second->getVectorKind()) &&
-      First->getVectorKind() != VectorKind::RVVFixedLengthMask &&
-      Second->getVectorKind() != VectorKind::RVVFixedLengthMask &&
-      First->getVectorKind() != VectorKind::RVVFixedLengthMask_1 &&
-      Second->getVectorKind() != VectorKind::RVVFixedLengthMask_1 &&
-      First->getVectorKind() != VectorKind::RVVFixedLengthMask_2 &&
-      Second->getVectorKind() != VectorKind::RVVFixedLengthMask_2 &&
-      First->getVectorKind() != VectorKind::RVVFixedLengthMask_4 &&
-      Second->getVectorKind() != VectorKind::RVVFixedLengthMask_4)
+      !isRVVFixedLengthMaskVectorKind(First->getVectorKind()) &&
+      !isRVVFixedLengthMaskVectorKind(Second->getVectorKind()))
     return true;
 
   // In OpenCL, treat half and _Float16 vector types as compatible.
@@ -10860,29 +10852,17 @@ bool ASTContext::areCompatibleRVVTypes(QualType 
FirstType,
   auto IsValidCast = [this](QualType FirstType, QualType SecondType) {
     if (const auto *BT = FirstType->getAs<BuiltinType>()) {
       if (const auto *VT = SecondType->getAs<VectorType>()) {
-        if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask) {
+        if (isRVVFixedLengthMaskVectorKind(VT->getVectorKind())) {
           BuiltinVectorTypeInfo Info = getBuiltinVectorTypeInfo(BT);
+          // A mask typedef converts to and from the vbool<R>_t type it was
+          // written against: vbool<R>_t has RVVBitsPerBlock / R lanes at
+          // vscale=1.
           return FirstType->isRVVVLSBuiltinType() &&
                  Info.ElementType == BoolTy &&
-                 getTypeSize(SecondType) == ((getRVVTypeSize(*this, BT)));
-        }
-        if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1) {
-          BuiltinVectorTypeInfo Info = getBuiltinVectorTypeInfo(BT);
-          return FirstType->isRVVVLSBuiltinType() &&
-                 Info.ElementType == BoolTy &&
-                 getTypeSize(SecondType) == ((getRVVTypeSize(*this, BT) * 8));
-        }
-        if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2) {
-          BuiltinVectorTypeInfo Info = getBuiltinVectorTypeInfo(BT);
-          return FirstType->isRVVVLSBuiltinType() &&
-                 Info.ElementType == BoolTy &&
-                 getTypeSize(SecondType) == ((getRVVTypeSize(*this, BT)) * 4);
-        }
-        if (VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4) {
-          BuiltinVectorTypeInfo Info = getBuiltinVectorTypeInfo(BT);
-          return FirstType->isRVVVLSBuiltinType() &&
-                 Info.ElementType == BoolTy &&
-                 getTypeSize(SecondType) == ((getRVVTypeSize(*this, BT)) * 2);
+                 (llvm::RISCV::RVVBitsPerBlock >>
+                  getRVVFixedLengthMaskRatioLog2(VT->getVectorKind())) ==
+                     Info.EC.getKnownMinValue() &&
+                 VT->getRVVFixedLengthMaskLanes() == getRVVTypeSize(*this, BT);
         }
         if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
             VT->getVectorKind() == VectorKind::Generic)
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 8fd9059abcdf3d..6f24eb0a829aec 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -35,7 +35,6 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/TargetParser/RISCVTargetParser.h"
 #include <optional>
 
 using namespace clang;
@@ -4317,10 +4316,7 @@ void CXXNameMangler::mangleAArch64FixedSveVectorType(
 
 void CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
   assert((isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
-          T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-          T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-          T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-          T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) &&
+          isRVVFixedLengthMaskVectorKind(T->getVectorKind())) &&
          "expected fixed-length RVV vector!");
 
   QualType EltType = T->getElementType();
@@ -4376,36 +4372,20 @@ void 
CXXNameMangler::mangleRISCVFixedRVVVectorType(const VectorType *T) {
     llvm_unreachable("unexpected element type for fixed-length RVV vector!");
   }
 
-  unsigned VecSizeInBits;
-  switch (T->getVectorKind()) {
-  case VectorKind::RVVFixedLengthMask_1:
-    VecSizeInBits = 1;
-    break;
-  case VectorKind::RVVFixedLengthMask_2:
-    VecSizeInBits = 2;
-    break;
-  case VectorKind::RVVFixedLengthMask_4:
-    VecSizeInBits = 4;
-    break;
-  default:
-    VecSizeInBits = getASTContext().getTypeInfo(T).Width;
-    break;
-  }
+  // A mask typedef is mangled with its lane count, which is less than its
+  // size in bits when it fits in a single byte.
+  unsigned VecSizeInBits = isRVVFixedLengthMaskVectorKind(T->getVectorKind())
+                               ? T->getRVVFixedLengthMaskLanes()
+                               : getASTContext().getTypeInfo(T).Width;
 
-  // Append the LMUL suffix. For data types the LMUL is recorded in the vector
-  // kind, so the mangled name names the type the typedef was written against
-  // even when the typedef is shorter than VLEN * LMUL, and does not depend on
-  // VLEN at all. Mask types are still tied to a fixed VLEN, so their ratio is
-  // derived from it.
+  // Append the LMUL suffix of a data type, or the ratio of a mask type. Both
+  // are recorded in the vector kind, so the mangled name names the type the
+  // typedef was written against and does not depend on VLEN.
   if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
     TypeNameOS << getRVVFixedLengthDataLMulString(T->getVectorKind(),
                                                   /*MF=*/true);
   } else {
-    auto VScale = getASTContext().getTargetInfo().getVScaleRange(
-        getASTContext().getLangOpts(),
-        TargetInfo::ArmStreamingKind::NotStreaming);
-    unsigned VLen = VScale->first * llvm::RISCV::RVVBitsPerBlock;
-    TypeNameOS << (VLen / VecSizeInBits);
+    TypeNameOS << (1u << getRVVFixedLengthMaskRatioLog2(T->getVectorKind()));
   }
   TypeNameOS << "_t";
 
@@ -4446,10 +4426,7 @@ void CXXNameMangler::mangleType(const VectorType *T) {
     mangleAArch64FixedSveVectorType(T);
     return;
   } else if (isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-             T->getVectorKind() == VectorKind::RVVFixedLengthMask_4) {
+             isRVVFixedLengthMaskVectorKind(T->getVectorKind())) {
     mangleRISCVFixedRVVVectorType(T);
     return;
   }
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index 2555c3658df02f..c7015feeb6e3ff 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -750,24 +750,21 @@ void JSONNodeDumper::VisitVectorType(const VectorType 
*VT) {
   case VectorKind::SveFixedLengthPredicate:
     JOS.attribute("vectorKind", "fixed-length sve predicate vector");
     break;
-  case VectorKind::RVVFixedLengthData_MF8:
-  case VectorKind::RVVFixedLengthData_MF4:
-  case VectorKind::RVVFixedLengthData_MF2:
-  case VectorKind::RVVFixedLengthData_M1:
-  case VectorKind::RVVFixedLengthData_M2:
-  case VectorKind::RVVFixedLengthData_M4:
-  case VectorKind::RVVFixedLengthData_M8:
-    JOS.attribute("vectorKind",
-                  "fixed-length rvv data vector lmul " +
-                      getRVVFixedLengthDataLMulString(VT->getVectorKind(),
-                                                      /*MF=*/false)
-                          .str());
-    break;
-  case VectorKind::RVVFixedLengthMask:
-  case VectorKind::RVVFixedLengthMask_1:
-  case VectorKind::RVVFixedLengthMask_2:
-  case VectorKind::RVVFixedLengthMask_4:
-    JOS.attribute("vectorKind", "fixed-length rvv mask vector");
+  default:
+    if (isRVVFixedLengthDataVectorKind(VT->getVectorKind())) {
+      JOS.attribute("vectorKind",
+                    "fixed-length rvv data vector lmul " +
+                        getRVVFixedLengthDataLMulString(VT->getVectorKind(),
+                                                        /*MF=*/false)
+                            .str());
+    } else {
+      assert(isRVVFixedLengthMaskVectorKind(VT->getVectorKind()) &&
+             "unexpected vector kind");
+      JOS.attribute("vectorKind",
+                    "fixed-length rvv mask vector ratio " +
+                        std::to_string(1u << getRVVFixedLengthMaskRatioLog2(
+                                           VT->getVectorKind())));
+    }
     break;
   }
 }
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index f1b216d970c731..48c4043ad5cafa 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2168,21 +2168,16 @@ void TextNodeDumper::VisitVectorType(const VectorType 
*T) {
   case VectorKind::SveFixedLengthPredicate:
     OS << " fixed-length sve predicate vector";
     break;
-  case VectorKind::RVVFixedLengthData_MF8:
-  case VectorKind::RVVFixedLengthData_MF4:
-  case VectorKind::RVVFixedLengthData_MF2:
-  case VectorKind::RVVFixedLengthData_M1:
-  case VectorKind::RVVFixedLengthData_M2:
-  case VectorKind::RVVFixedLengthData_M4:
-  case VectorKind::RVVFixedLengthData_M8:
-    OS << " fixed-length rvv data vector lmul "
-       << getRVVFixedLengthDataLMulString(T->getVectorKind(), /*MF=*/false);
-    break;
-  case VectorKind::RVVFixedLengthMask:
-  case VectorKind::RVVFixedLengthMask_1:
-  case VectorKind::RVVFixedLengthMask_2:
-  case VectorKind::RVVFixedLengthMask_4:
-    OS << " fixed-length rvv mask vector";
+  default:
+    if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
+      OS << " fixed-length rvv data vector lmul "
+         << getRVVFixedLengthDataLMulString(T->getVectorKind(), /*MF=*/false);
+    } else {
+      assert(isRVVFixedLengthMaskVectorKind(T->getVectorKind()) &&
+             "unexpected vector kind");
+      OS << " fixed-length rvv mask vector ratio "
+         << (1u << getRVVFixedLengthMaskRatioLog2(T->getVectorKind()));
+    }
     break;
   }
   OS << " " << T->getNumElements();
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 12cce9ccc32a55..b438b41b3f8f73 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -718,37 +718,23 @@ void TypePrinter::printVectorBefore(const VectorType *T, 
raw_ostream &OS) {
     OS << ") * 8))) ";
     printBefore(T->getElementType(), OS);
     break;
-  case VectorKind::RVVFixedLengthData_MF8:
-  case VectorKind::RVVFixedLengthData_MF4:
-  case VectorKind::RVVFixedLengthData_MF2:
-  case VectorKind::RVVFixedLengthData_M1:
-  case VectorKind::RVVFixedLengthData_M2:
-  case VectorKind::RVVFixedLengthData_M4:
-  case VectorKind::RVVFixedLengthData_M8:
-  case VectorKind::RVVFixedLengthMask:
-  case VectorKind::RVVFixedLengthMask_1:
-  case VectorKind::RVVFixedLengthMask_2:
-  case VectorKind::RVVFixedLengthMask_4:
+  default:
+    // The RVV fixed-length data and mask kinds.
+    assert((isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
+            isRVVFixedLengthMaskVectorKind(T->getVectorKind())) &&
+           "unexpected vector kind");
     // FIXME: We prefer to print the size directly here, but have no way
     // to get the size of the type.
     OS << "__attribute__((__riscv_rvv_vector_bits__(";
-    switch (T->getVectorKind()) {
-    case VectorKind::RVVFixedLengthMask_1:
-      OS << '1';
-      break;
-    case VectorKind::RVVFixedLengthMask_2:
-      OS << '2';
-      break;
-    case VectorKind::RVVFixedLengthMask_4:
-      OS << '4';
-      break;
-    default:
+    if (isRVVFixedLengthMaskVectorKind(T->getVectorKind()) &&
+        getRVVFixedLengthMaskSubByteLanes(T->getVectorKind())) {
+      OS << getRVVFixedLengthMaskSubByteLanes(T->getVectorKind());
+    } else {
       OS << T->getNumElements();
       OS << " * sizeof(";
       print(T->getElementType(), OS, StringRef());
       // Multiply by 8 for the number of bits.
       OS << ") * 8";
-      break;
     }
     OS << "))) ";
     printBefore(T->getElementType(), OS);
@@ -819,39 +805,20 @@ void TypePrinter::printDependentVectorBefore(
     OS << "))) ";
     printBefore(T->getElementType(), OS);
     break;
-  case VectorKind::RVVFixedLengthData_MF8:
-  case VectorKind::RVVFixedLengthData_MF4:
-  case VectorKind::RVVFixedLengthData_MF2:
-  case VectorKind::RVVFixedLengthData_M1:
-  case VectorKind::RVVFixedLengthData_M2:
-  case VectorKind::RVVFixedLengthData_M4:
-  case VectorKind::RVVFixedLengthData_M8:
-  case VectorKind::RVVFixedLengthMask:
-  case VectorKind::RVVFixedLengthMask_1:
-  case VectorKind::RVVFixedLengthMask_2:
-  case VectorKind::RVVFixedLengthMask_4:
+  default:
+    // The RVV fixed-length data and mask kinds.
+    assert((isRVVFixedLengthDataVectorKind(T->getVectorKind()) ||
+            isRVVFixedLengthMaskVectorKind(T->getVectorKind())) &&
+           "unexpected vector kind");
     // FIXME: We prefer to print the size directly here, but have no way
     // to get the size of the type.
     OS << "__attribute__((__riscv_rvv_vector_bits__(";
-    switch (T->getVectorKind()) {
-    case VectorKind::RVVFixedLengthMask_1:
-      OS << '1';
-      break;
-    case VectorKind::RVVFixedLengthMask_2:
-      OS << '2';
-      break;
-    case VectorKind::RVVFixedLengthMask_4:
-      OS << '4';
-      break;
-    default:
-      if (T->getSizeExpr()) {
-        T->getSizeExpr()->printPretty(OS, nullptr, Policy);
-        OS << " * sizeof(";
-        print(T->getElementType(), OS, StringRef());
-        // Multiply by 8 for the number of bits.
-        OS << ") * 8";
-      }
-      break;
+    if (T->getSizeExpr()) {
+      T->getSizeExpr()->printPretty(OS, nullptr, Policy);
+      OS << " * sizeof(";
+      print(T->getElementType(), OS, StringRef());
+      // Multiply by 8 for the number of bits.
+      OS << ") * 8";
     }
     OS << "))) ";
     printBefore(T->getElementType(), OS);
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp 
b/clang/lib/CodeGen/Targets/RISCV.cpp
index c84a4f00f4bc7f..fb539e87591b67 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -428,17 +428,23 @@ static unsigned getRVVFixedLengthDataMinElts(VectorKind 
VK,
   return SizeAtVScale1 / EltSizeInBits;
 }
 
+/// Minimum element count of the scalable vector a vbool<R>_t mask is coerced
+/// to, i.e. the N in <vscale x N x i1>.
+static unsigned getRVVFixedLengthMaskMinElts(VectorKind VK) {
+  return llvm::RISCV::RVVBitsPerBlock >> getRVVFixedLengthMaskRatioLog2(VK);
+}
+
 /// Minimum element count of the scalable vector \p VT is coerced to, in units
-/// of \p VT's own Clang element type. Masks are modelled as i8 vectors and are
-/// exactly VLEN * LMUL wide, so their LMUL is recovered from VLEN.
+/// of \p VT's own Clang element type. Masks are modelled as i8 vectors, so
+/// their i1 lane count is rounded up to whole bytes.
 unsigned RISCVABIInfo::getRVVFixedLengthMinElts(const VectorType *VT) const {
   unsigned EltSizeInBits = getContext().getTypeSize(VT->getElementType());
   if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()))
     return getRVVFixedLengthDataMinElts(VT->getVectorKind(), EltSizeInBits);
-
-  auto VScale = getContext().getTargetInfo().getVScaleRange(
-      getContext().getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming);
-  return llvm::divideCeil(VT->getNumElements(), VScale->first);
+  assert(isRVVFixedLengthMaskVectorKind(VT->getVectorKind()) &&
+         "not an RVV fixed-length vector");
+  return llvm::divideCeil(getRVVFixedLengthMaskMinElts(VT->getVectorKind()),
+                          EltSizeInBits);
 }
 
 llvm::Type *RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty,
@@ -587,17 +593,8 @@ 
RISCVABIInfo::detectHomogeneousRVVFixedLengthStruct(QualType Ty) const {
     return nullptr;
 
   auto IsFixedLengthRVVVector = [](const VectorType *VT) {
-    if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()))
-      return true;
-    switch (VT->getVectorKind()) {
-    case VectorKind::RVVFixedLengthMask:
-    case VectorKind::RVVFixedLengthMask_1:
-    case VectorKind::RVVFixedLengthMask_2:
-    case VectorKind::RVVFixedLengthMask_4:
-      return true;
-    default:
-      return false;
-    }
+    return isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
+           isRVVFixedLengthMaskVectorKind(VT->getVectorKind());
   };
 
   QualType CommonTy;
@@ -688,24 +685,16 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, 
unsigned ABIVLen) const {
   auto VScale = getContext().getTargetInfo().getVScaleRange(
       getContext().getLangOpts(), TargetInfo::ArmStreamingKind::NotStreaming);
 
-  unsigned NumElts = VT->getNumElements();
-  llvm::Type *EltType = llvm::Type::getInt1Ty(getVMContext());
-  switch (VT->getVectorKind()) {
-  case VectorKind::RVVFixedLengthMask_1:
-    break;
-  case VectorKind::RVVFixedLengthMask_2:
-    NumElts *= 2;
-    break;
-  case VectorKind::RVVFixedLengthMask_4:
-    NumElts *= 4;
-    break;
-  case VectorKind::RVVFixedLengthMask:
-    NumElts *= 8;
-    break;
-  default:
+  unsigned NumElts;
+  llvm::Type *EltType;
+  if (isRVVFixedLengthMaskVectorKind(VT->getVectorKind())) {
+    NumElts = VT->getRVVFixedLengthMaskLanes();
+    EltType = llvm::Type::getInt1Ty(getVMContext());
+  } else {
     assert((VT->getVectorKind() == VectorKind::Generic ||
             isRVVFixedLengthDataVectorKind(VT->getVectorKind())) &&
            "Unexpected vector kind");
+    NumElts = VT->getNumElements();
     EltType = CGT.ConvertType(VT->getElementType());
   }
 
@@ -717,6 +706,9 @@ ABIArgInfo RISCVABIInfo::coerceVLSVector(QualType Ty, 
unsigned ABIVLen) const {
       // Use the LMUL of the type the typedef was written against.
       MinScalableElts = getRVVFixedLengthDataMinElts(
           VT->getVectorKind(), EltType->getScalarSizeInBits());
+    } else if (isRVVFixedLengthMaskVectorKind(VT->getVectorKind())) {
+      // Use the ratio of the vbool<R>_t type the typedef was written against.
+      MinScalableElts = getRVVFixedLengthMaskMinElts(VT->getVectorKind());
     } else {
       // The MinNumElts is simplified from equation:
       // NumElts / VScale =
@@ -862,10 +854,7 @@ ABIArgInfo RISCVABIInfo::classifyArgumentType(QualType Ty, 
bool IsFixed,
   if (const VectorType *VT = Ty->getAs<VectorType>();
       VT && !VT->getElementType()->isBitIntType()) {
     if (isRVVFixedLengthDataVectorKind(VT->getVectorKind()) ||
-        VT->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-        VT->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-        VT->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-        VT->getVectorKind() == VectorKind::RVVFixedLengthMask_4)
+        isRVVFixedLengthMaskVectorKind(VT->getVectorKind()))
       return coerceVLSVector(Ty);
     if (VT->getVectorKind() == VectorKind::Generic && ABIVLen != 0)
       // Generic vector without riscv_vls_cc should fall through and pass by
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 9a11c859997eb6..00a2e23497aa87 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -11062,10 +11062,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, 
ExprResult &RHS,
           VecType->getVectorKind() == VectorKind::SveFixedLengthPredicate)
         return true;
       if (isRVVFixedLengthDataVectorKind(VecType->getVectorKind()) ||
-          VecType->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-          VecType->getVectorKind() == VectorKind::RVVFixedLengthMask_1 ||
-          VecType->getVectorKind() == VectorKind::RVVFixedLengthMask_2 ||
-          VecType->getVectorKind() == VectorKind::RVVFixedLengthMask_4) {
+          isRVVFixedLengthMaskVectorKind(VecType->getVectorKind())) {
         SVEorRVV = 1;
         return true;
       }
@@ -11097,13 +11094,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, 
ExprResult &RHS,
                 VectorKind::SveFixedLengthPredicate)
           return true;
         if (isRVVFixedLengthDataVectorKind(SecondVecType->getVectorKind()) ||
-            SecondVecType->getVectorKind() == VectorKind::RVVFixedLengthMask ||
-            SecondVecType->getVectorKind() ==
-                VectorKind::RVVFixedLengthMask_1 ||
-            SecondVecType->getVectorKind() ==
-                VectorKind::RVVFixedLengthMask_2 ||
-            SecondVecType->getVectorKind() ==
-                VectorKind::RVVFixedLengthMask_4) {
+            isRVVFixedLengthMaskVectorKind(SecondVecType->getVectorKind())) {
           SVEorRVV = 1;
           return true;
         }
diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 9c299b9e55da8d..e16630ce9cd844 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -8871,28 +8871,26 @@ static void HandleRISCVRVVVectorBitsTypeAttr(QualType 
&CurType,
       S.Context.getBuiltinVectorTypeInfo(CurType->castAs<BuiltinType>());
   unsigned MinElts = Info.EC.getKnownMinValue();
 
-  VectorKind VecKind = VectorKind::RVVFixedLengthMask;
+  VectorKind VecKind;
   unsigned ExpectedSize = VScale->first * MinElts;
   QualType EltType = CurType->getRVVEltType(S.Context);
   unsigned EltSize = S.Context.getTypeSize(EltType);
   unsigned NumElts;
   if (Info.ElementType == S.Context.BoolTy) {
+    // A mask is stored in bytes. One with fewer than 8 lanes takes a single
+    // byte, and its lane count is recorded in the vector kind.
     NumElts = VecSize / S.Context.getCharWidth();
+    unsigned SubByteLanes = 0;
     if (!NumElts) {
       NumElts = 1;
-      switch (VecSize) {
-      case 1:
-        VecKind = VectorKind::RVVFixedLengthMask_1;
-        break;
-      case 2:
-        VecKind = VectorKind::RVVFixedLengthMask_2;
-        break;
-      case 4:
-        VecKind = VectorKind::RVVFixedLengthMask_4;
-        break;
-      }
-    } else
-      VecKind = VectorKind::RVVFixedLengthMask;
+      if (VecSize == 1 || VecSize == 2 || VecSize == 4)
+        SubByteLanes = VecSize;
+    }
+    // Record the ratio of the vbool<R>_t type in the vector kind, so that
+    // later stages do not have to re-derive it from VLEN and the lane count.
+    // vbool<R>_t has RVVBitsPerBlock / R lanes at vscale=1.
+    VecKind = getRVVFixedLengthMaskVectorKind(
+        llvm::Log2_32(llvm::RISCV::RVVBitsPerBlock / MinElts), SubByteLanes);
   } else {
     ExpectedSize *= EltSize;
     NumElts = VecSize / EltSize;
diff --git a/clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c 
b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
similarity index 64%
rename from clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c
rename to clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
index 4ba0ea48ba4240..e2ce3ac4d611e6 100644
--- a/clang/test/AST/ast-dump-riscv-rvv-fixed-length-data-types.c
+++ b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
@@ -1,5 +1,5 @@
-// Verify that a riscv_rvv_vector_bits typedef of a data type records the LMUL
-// of the sizeless type it was written against.
+// Verify that a riscv_rvv_vector_bits typedef records the LMUL of the sizeless
+// data type, or the ratio of the sizeless mask type, it was written against.
 
 // RUN: %clang_cc1 -triple riscv64-none-linux-gnu -target-feature +zve64d \
 // RUN:   -mvscale-min=2 -mvscale-max=2 -ast-dump %s | FileCheck %s
@@ -15,6 +15,10 @@ typedef __rvv_int32m1_t fixed_i32m1 
__attribute__((riscv_rvv_vector_bits(128)));
 typedef __rvv_int32m2_t fixed_i32m2 
__attribute__((riscv_rvv_vector_bits(256)));
 typedef __rvv_int64m4_t fixed_i64m4 
__attribute__((riscv_rvv_vector_bits(512)));
 typedef __rvv_int8m8_t fixed_i8m8 __attribute__((riscv_rvv_vector_bits(1024)));
+typedef __rvv_bool1_t fixed_b1 __attribute__((riscv_rvv_vector_bits(128)));
+typedef __rvv_bool8_t fixed_b8 __attribute__((riscv_rvv_vector_bits(16)));
+typedef __rvv_bool32_t fixed_b32 __attribute__((riscv_rvv_vector_bits(4)));
+typedef __rvv_bool64_t fixed_b64 __attribute__((riscv_rvv_vector_bits(2)));
 
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i8mf8
 // CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/8 2
@@ -30,6 +34,14 @@ typedef __rvv_int8m8_t fixed_i8m8 
__attribute__((riscv_rvv_vector_bits(1024)));
 // CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 4 8
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i8m8
 // CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 8 128
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_b1
+// CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 1 16
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_b8
+// CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 8 2
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_b32
+// CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 32 1
+// CHECK-LABEL: TypedefDecl {{.*}} fixed_b64
+// CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 64 1
 
 // JSON: "vectorKind": "fixed-length rvv data vector lmul 1/8"
 // JSON: "vectorKind": "fixed-length rvv data vector lmul 1/4"
@@ -38,3 +50,7 @@ typedef __rvv_int8m8_t fixed_i8m8 
__attribute__((riscv_rvv_vector_bits(1024)));
 // JSON: "vectorKind": "fixed-length rvv data vector lmul 2"
 // JSON: "vectorKind": "fixed-length rvv data vector lmul 4"
 // JSON: "vectorKind": "fixed-length rvv data vector lmul 8"
+// JSON: "vectorKind": "fixed-length rvv mask vector ratio 1"
+// JSON: "vectorKind": "fixed-length rvv mask vector ratio 8"
+// JSON: "vectorKind": "fixed-length rvv mask vector ratio 32"
+// JSON: "vectorKind": "fixed-length rvv mask vector ratio 64"

>From 9dc58094ef772cd8b8842f5597076c2c9f1a9bda Mon Sep 17 00:00:00 2001
From: Kito Cheng <[email protected]>
Date: Tue, 3 Nov 2026 13:43:56 +0800
Subject: [PATCH 3/3] fixup! [Clang][RISCV] Record the LMUL in RVV fixed-length
 data vector kinds

---
 clang/include/clang/AST/TypeBase.h            | 20 ++++++-------
 clang/lib/AST/ItaniumMangle.cpp               |  3 +-
 clang/lib/AST/JSONNodeDumper.cpp              |  9 +++---
 clang/lib/AST/TextNodeDumper.cpp              |  2 +-
 ...dump-riscv-rvv-fixed-length-vector-kinds.c | 28 +++++++++----------
 5 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/clang/include/clang/AST/TypeBase.h 
b/clang/include/clang/AST/TypeBase.h
index 4f4f4b8a22d63c..c9e64040aeefe1 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -4335,24 +4335,24 @@ inline int getRVVFixedLengthDataLMulLog2(VectorKind VK) 
{
   }
 }
 
-/// Return the LMUL of an RVV fixed-length data vector kind as a string:
-/// "mf8" .. "m8" if \p MF is true, "1/8" .. "8" otherwise.
-inline StringRef getRVVFixedLengthDataLMulString(VectorKind VK, bool MF) {
+/// Return the LMUL of an RVV fixed-length data vector kind as a string,
+/// "mf8" .. "m8".
+inline StringRef getRVVFixedLengthDataLMulString(VectorKind VK) {
   switch (VK) {
   case VectorKind::RVVFixedLengthData_MF8:
-    return MF ? "mf8" : "1/8";
+    return "mf8";
   case VectorKind::RVVFixedLengthData_MF4:
-    return MF ? "mf4" : "1/4";
+    return "mf4";
   case VectorKind::RVVFixedLengthData_MF2:
-    return MF ? "mf2" : "1/2";
+    return "mf2";
   case VectorKind::RVVFixedLengthData_M1:
-    return MF ? "m1" : "1";
+    return "m1";
   case VectorKind::RVVFixedLengthData_M2:
-    return MF ? "m2" : "2";
+    return "m2";
   case VectorKind::RVVFixedLengthData_M4:
-    return MF ? "m4" : "4";
+    return "m4";
   case VectorKind::RVVFixedLengthData_M8:
-    return MF ? "m8" : "8";
+    return "m8";
   default:
     llvm_unreachable("not an RVV fixed-length data vector kind");
   }
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 6f24eb0a829aec..edb7ca8e33d1e1 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -4382,8 +4382,7 @@ void CXXNameMangler::mangleRISCVFixedRVVVectorType(const 
VectorType *T) {
   // are recorded in the vector kind, so the mangled name names the type the
   // typedef was written against and does not depend on VLEN.
   if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
-    TypeNameOS << getRVVFixedLengthDataLMulString(T->getVectorKind(),
-                                                  /*MF=*/true);
+    TypeNameOS << getRVVFixedLengthDataLMulString(T->getVectorKind());
   } else {
     TypeNameOS << (1u << getRVVFixedLengthMaskRatioLog2(T->getVectorKind()));
   }
diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp
index c7015feeb6e3ff..cb0d8a6d3f4ea9 100644
--- a/clang/lib/AST/JSONNodeDumper.cpp
+++ b/clang/lib/AST/JSONNodeDumper.cpp
@@ -752,11 +752,10 @@ void JSONNodeDumper::VisitVectorType(const VectorType 
*VT) {
     break;
   default:
     if (isRVVFixedLengthDataVectorKind(VT->getVectorKind())) {
-      JOS.attribute("vectorKind",
-                    "fixed-length rvv data vector lmul " +
-                        getRVVFixedLengthDataLMulString(VT->getVectorKind(),
-                                                        /*MF=*/false)
-                            .str());
+      JOS.attribute(
+          "vectorKind",
+          "fixed-length rvv data vector lmul " +
+              getRVVFixedLengthDataLMulString(VT->getVectorKind()).str());
     } else {
       assert(isRVVFixedLengthMaskVectorKind(VT->getVectorKind()) &&
              "unexpected vector kind");
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 48c4043ad5cafa..7812bf16986195 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2171,7 +2171,7 @@ void TextNodeDumper::VisitVectorType(const VectorType *T) 
{
   default:
     if (isRVVFixedLengthDataVectorKind(T->getVectorKind())) {
       OS << " fixed-length rvv data vector lmul "
-         << getRVVFixedLengthDataLMulString(T->getVectorKind(), /*MF=*/false);
+         << getRVVFixedLengthDataLMulString(T->getVectorKind());
     } else {
       assert(isRVVFixedLengthMaskVectorKind(T->getVectorKind()) &&
              "unexpected vector kind");
diff --git a/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c 
b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
index e2ce3ac4d611e6..aa48f3d8487b11 100644
--- a/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
+++ b/clang/test/AST/ast-dump-riscv-rvv-fixed-length-vector-kinds.c
@@ -21,19 +21,19 @@ typedef __rvv_bool32_t fixed_b32 
__attribute__((riscv_rvv_vector_bits(4)));
 typedef __rvv_bool64_t fixed_b64 __attribute__((riscv_rvv_vector_bits(2)));
 
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i8mf8
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/8 2
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul mf8 2
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i16mf4
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/4 2
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul mf4 2
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i32mf2
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1/2 2
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul mf2 2
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i32m1
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 1 4
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul m1 4
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i32m2
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 2 8
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul m2 8
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i64m4
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 4 8
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul m4 8
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_i8m8
-// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul 8 128
+// CHECK:       VectorType {{.*}} fixed-length rvv data vector lmul m8 128
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_b1
 // CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 1 16
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_b8
@@ -43,13 +43,13 @@ typedef __rvv_bool64_t fixed_b64 
__attribute__((riscv_rvv_vector_bits(2)));
 // CHECK-LABEL: TypedefDecl {{.*}} fixed_b64
 // CHECK:       VectorType {{.*}} fixed-length rvv mask vector ratio 64 1
 
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/8"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/4"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 1/2"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 1"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 2"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 4"
-// JSON: "vectorKind": "fixed-length rvv data vector lmul 8"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul mf8"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul mf4"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul mf2"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul m1"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul m2"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul m4"
+// JSON: "vectorKind": "fixed-length rvv data vector lmul m8"
 // JSON: "vectorKind": "fixed-length rvv mask vector ratio 1"
 // JSON: "vectorKind": "fixed-length rvv mask vector ratio 8"
 // JSON: "vectorKind": "fixed-length rvv mask vector ratio 32"

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

Reply via email to