Skip to content

[RISCV] Correct type lowering of struct of fixed-vector array in VLS #147173

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 9, 2025

Conversation

4vtomat
Copy link
Member

@4vtomat 4vtomat commented Jul 6, 2025

Currently, struct of fixed-vector array is flattened and lowered to
scalable vector. However only struct of 1-element-fixed-vector array
should be lowered that way, struct of fixed-vector array of length >1
should be lowered to vector tuple type.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418/files#diff-3a934f00cffdb3e509722753126a2cf6082a7648ab3b9ca8cbb0e84f8a6a12edR555-R558

Currently, struct of fixed-vector array is flattened and lowered to
scalable vector. However only struct of 1-element-fixed-vector array
should be lowered that way, struct of fixed-vector array of length >1
should be lowered to vector tuple type.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418/files#diff-3a934f00cffdb3e509722753126a2cf6082a7648ab3b9ca8cbb0e84f8a6a12edR555-R558
@llvmbot llvmbot added clang Clang issues not falling into any other category backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. labels Jul 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 6, 2025

@llvm/pr-subscribers-clang-codegen

@llvm/pr-subscribers-backend-risc-v

Author: Brandon Wu (4vtomat)

Changes

Currently, struct of fixed-vector array is flattened and lowered to
scalable vector. However only struct of 1-element-fixed-vector array
should be lowered that way, struct of fixed-vector array of length >1
should be lowered to vector tuple type.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418/files#diff-3a934f00cffdb3e509722753126a2cf6082a7648ab3b9ca8cbb0e84f8a6a12edR555-R558


Full diff: https://github.com/llvm/llvm-project/pull/147173.diff

3 Files Affected:

  • (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+60-84)
  • (modified) clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c (+4-4)
  • (modified) clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp (+4-4)
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index cc3d487da83b5..e1603d3095a04 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -441,98 +441,74 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen,
   //     __attribute__((vector_size(64))) int d;
   //   }
   //
-  // Struct of 1 fixed-length vector is passed as a scalable vector.
-  // Struct of >1 fixed-length vectors are passed as vector tuple.
-  // Struct of 1 array of fixed-length vectors is passed as a scalable vector.
-  // Otherwise, pass the struct indirectly.
-
-  if (llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty))) {
-    unsigned NumElts = STy->getStructNumElements();
-    if (NumElts > 8)
-      return false;
+  // 1. Struct of 1 fixed-length vector is passed as a scalable vector.
+  // 2. Struct of >1 fixed-length vectors are passed as vector tuple.
+  // 3. Struct of an array with 1 element of fixed-length vectors is passed as a
+  //    scalable vector.
+  // 4. Struct of an array with >1 elements of fixed-length vectors is passed as
+  //    vector tuple.
+  // 5. Otherwise, pass the struct indirectly.
+
+  llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
+  if (!STy)
+    return false;
 
-    auto *FirstEltTy = STy->getElementType(0);
-    if (!STy->containsHomogeneousTypes())
-      return false;
+  unsigned NumElts = STy->getStructNumElements();
+  if (NumElts > 8)
+    return false;
 
-    // Check structure of fixed-length vectors and turn them into vector tuple
-    // type if legal.
-    if (auto *FixedVecTy = dyn_cast<llvm::FixedVectorType>(FirstEltTy)) {
-      if (NumElts == 1) {
-        // Handle single fixed-length vector.
-        VLSType = llvm::ScalableVectorType::get(
-            FixedVecTy->getElementType(),
-            llvm::divideCeil(FixedVecTy->getNumElements() *
-                                 llvm::RISCV::RVVBitsPerBlock,
-                             ABIVLen));
-        // Check registers needed <= 8.
-        return llvm::divideCeil(
-                   FixedVecTy->getNumElements() *
-                       FixedVecTy->getElementType()->getScalarSizeInBits(),
-                   ABIVLen) <= 8;
-      }
-      // LMUL
-      // = fixed-length vector size / ABIVLen
-      // = 8 * I8EltCount / RVVBitsPerBlock
-      // =>
-      // I8EltCount
-      // = (fixed-length vector size * RVVBitsPerBlock) / (ABIVLen * 8)
-      unsigned I8EltCount = llvm::divideCeil(
-          FixedVecTy->getNumElements() *
-              FixedVecTy->getElementType()->getScalarSizeInBits() *
-              llvm::RISCV::RVVBitsPerBlock,
-          ABIVLen * 8);
-      VLSType = llvm::TargetExtType::get(
-          getVMContext(), "riscv.vector.tuple",
-          llvm::ScalableVectorType::get(llvm::Type::getInt8Ty(getVMContext()),
-                                        I8EltCount),
-          NumElts);
-      // Check registers needed <= 8.
-      return NumElts *
-                 llvm::divideCeil(
-                     FixedVecTy->getNumElements() *
-                         FixedVecTy->getElementType()->getScalarSizeInBits(),
-                     ABIVLen) <=
-             8;
-    }
+  auto *FirstEltTy = STy->getElementType(0);
+  if (!STy->containsHomogeneousTypes())
+    return false;
 
-    // If elements are not fixed-length vectors, it should be an array.
+  if (auto *ArrayTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) {
+    // Only struct of single array is accepted
     if (NumElts != 1)
       return false;
+    FirstEltTy = ArrayTy->getArrayElementType();
+    NumElts = ArrayTy->getNumElements();
+  }
 
-    // Check array of fixed-length vector and turn it into scalable vector type
-    // if legal.
-    if (auto *ArrTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) {
-      unsigned NumArrElt = ArrTy->getNumElements();
-      if (NumArrElt > 8)
-        return false;
-
-      auto *ArrEltTy = dyn_cast<llvm::FixedVectorType>(ArrTy->getElementType());
-      if (!ArrEltTy)
-        return false;
+  auto *FixedVecTy = dyn_cast<llvm::FixedVectorType>(FirstEltTy);
+  if (!FixedVecTy)
+    return false;
 
-      // LMUL
-      // = NumArrElt * fixed-length vector size / ABIVLen
-      // = fixed-length vector elt size * ScalVecNumElts / RVVBitsPerBlock
-      // =>
-      // ScalVecNumElts
-      // = (NumArrElt * fixed-length vector size * RVVBitsPerBlock) /
-      //   (ABIVLen * fixed-length vector elt size)
-      // = NumArrElt * num fixed-length vector elt * RVVBitsPerBlock /
-      //   ABIVLen
-      unsigned ScalVecNumElts = llvm::divideCeil(
-          NumArrElt * ArrEltTy->getNumElements() * llvm::RISCV::RVVBitsPerBlock,
-          ABIVLen);
-      VLSType = llvm::ScalableVectorType::get(ArrEltTy->getElementType(),
-                                              ScalVecNumElts);
-      // Check registers needed <= 8.
-      return llvm::divideCeil(
-                 ScalVecNumElts *
-                     ArrEltTy->getElementType()->getScalarSizeInBits(),
-                 llvm::RISCV::RVVBitsPerBlock) <= 8;
-    }
+  // Turn them into scalable vector type or vector tuple type if legal.
+  if (NumElts == 1) {
+    // Handle single fixed-length vector.
+    VLSType = llvm::ScalableVectorType::get(
+        FixedVecTy->getElementType(),
+        llvm::divideCeil(FixedVecTy->getNumElements() *
+                             llvm::RISCV::RVVBitsPerBlock,
+                         ABIVLen));
+    // Check registers needed <= 8.
+    return llvm::divideCeil(
+               FixedVecTy->getNumElements() *
+                   FixedVecTy->getElementType()->getScalarSizeInBits(),
+               ABIVLen) <= 8;
   }
-  return false;
+  // LMUL
+  // = fixed-length vector size / ABIVLen
+  // = 8 * I8EltCount / RVVBitsPerBlock
+  // =>
+  // I8EltCount
+  // = (fixed-length vector size * RVVBitsPerBlock) / (ABIVLen * 8)
+  unsigned I8EltCount =
+      llvm::divideCeil(FixedVecTy->getNumElements() *
+                           FixedVecTy->getElementType()->getScalarSizeInBits() *
+                           llvm::RISCV::RVVBitsPerBlock,
+                       ABIVLen * 8);
+  VLSType = llvm::TargetExtType::get(
+      getVMContext(), "riscv.vector.tuple",
+      llvm::ScalableVectorType::get(llvm::Type::getInt8Ty(getVMContext()),
+                                    I8EltCount),
+      NumElts);
+  // Check registers needed <= 8.
+  return NumElts * llvm::divideCeil(
+                       FixedVecTy->getNumElements() *
+                           FixedVecTy->getElementType()->getScalarSizeInBits(),
+                       ABIVLen) <=
+         8;
 }
 
 // Fixed-length RVV vectors are represented as scalable vectors in function
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
index 3044d91f1c31c..82e43fff0c3aa 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
@@ -153,14 +153,14 @@ void __attribute__((riscv_vls_cc)) test_st_i32x4_arr1(struct st_i32x4_arr1 arg)
 // CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr1_256(<vscale x 1 x i32> %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 8 x i8>, 4) %arg)
 void __attribute__((riscv_vls_cc)) test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256(<vscale x 4 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 4) %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8(<vscale x 16 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg)
 void __attribute__((riscv_vls_cc)) test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {}
 
 // CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg)
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
index 594bfe159b28c..5f6539796c20d 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
@@ -133,14 +133,14 @@ typedef int __attribute__((vector_size(256))) int32x64_t;
 // CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1(<vscale x 1 x i32> %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 8 x i8>, 4) %arg)
 [[riscv::vls_cc]] void test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4(<vscale x 4 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 4 x i8>, 4) %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8(<vscale x 16 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg)
 [[riscv::vls_cc]] void test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {}
 
 // CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg)

@llvmbot
Copy link
Member

llvmbot commented Jul 6, 2025

@llvm/pr-subscribers-clang

Author: Brandon Wu (4vtomat)

Changes

Currently, struct of fixed-vector array is flattened and lowered to
scalable vector. However only struct of 1-element-fixed-vector array
should be lowered that way, struct of fixed-vector array of length >1
should be lowered to vector tuple type.
https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/418/files#diff-3a934f00cffdb3e509722753126a2cf6082a7648ab3b9ca8cbb0e84f8a6a12edR555-R558


Full diff: https://github.com/llvm/llvm-project/pull/147173.diff

3 Files Affected:

  • (modified) clang/lib/CodeGen/Targets/RISCV.cpp (+60-84)
  • (modified) clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c (+4-4)
  • (modified) clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp (+4-4)
diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp
index cc3d487da83b5..e1603d3095a04 100644
--- a/clang/lib/CodeGen/Targets/RISCV.cpp
+++ b/clang/lib/CodeGen/Targets/RISCV.cpp
@@ -441,98 +441,74 @@ bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen,
   //     __attribute__((vector_size(64))) int d;
   //   }
   //
-  // Struct of 1 fixed-length vector is passed as a scalable vector.
-  // Struct of >1 fixed-length vectors are passed as vector tuple.
-  // Struct of 1 array of fixed-length vectors is passed as a scalable vector.
-  // Otherwise, pass the struct indirectly.
-
-  if (llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty))) {
-    unsigned NumElts = STy->getStructNumElements();
-    if (NumElts > 8)
-      return false;
+  // 1. Struct of 1 fixed-length vector is passed as a scalable vector.
+  // 2. Struct of >1 fixed-length vectors are passed as vector tuple.
+  // 3. Struct of an array with 1 element of fixed-length vectors is passed as a
+  //    scalable vector.
+  // 4. Struct of an array with >1 elements of fixed-length vectors is passed as
+  //    vector tuple.
+  // 5. Otherwise, pass the struct indirectly.
+
+  llvm::StructType *STy = dyn_cast<llvm::StructType>(CGT.ConvertType(Ty));
+  if (!STy)
+    return false;
 
-    auto *FirstEltTy = STy->getElementType(0);
-    if (!STy->containsHomogeneousTypes())
-      return false;
+  unsigned NumElts = STy->getStructNumElements();
+  if (NumElts > 8)
+    return false;
 
-    // Check structure of fixed-length vectors and turn them into vector tuple
-    // type if legal.
-    if (auto *FixedVecTy = dyn_cast<llvm::FixedVectorType>(FirstEltTy)) {
-      if (NumElts == 1) {
-        // Handle single fixed-length vector.
-        VLSType = llvm::ScalableVectorType::get(
-            FixedVecTy->getElementType(),
-            llvm::divideCeil(FixedVecTy->getNumElements() *
-                                 llvm::RISCV::RVVBitsPerBlock,
-                             ABIVLen));
-        // Check registers needed <= 8.
-        return llvm::divideCeil(
-                   FixedVecTy->getNumElements() *
-                       FixedVecTy->getElementType()->getScalarSizeInBits(),
-                   ABIVLen) <= 8;
-      }
-      // LMUL
-      // = fixed-length vector size / ABIVLen
-      // = 8 * I8EltCount / RVVBitsPerBlock
-      // =>
-      // I8EltCount
-      // = (fixed-length vector size * RVVBitsPerBlock) / (ABIVLen * 8)
-      unsigned I8EltCount = llvm::divideCeil(
-          FixedVecTy->getNumElements() *
-              FixedVecTy->getElementType()->getScalarSizeInBits() *
-              llvm::RISCV::RVVBitsPerBlock,
-          ABIVLen * 8);
-      VLSType = llvm::TargetExtType::get(
-          getVMContext(), "riscv.vector.tuple",
-          llvm::ScalableVectorType::get(llvm::Type::getInt8Ty(getVMContext()),
-                                        I8EltCount),
-          NumElts);
-      // Check registers needed <= 8.
-      return NumElts *
-                 llvm::divideCeil(
-                     FixedVecTy->getNumElements() *
-                         FixedVecTy->getElementType()->getScalarSizeInBits(),
-                     ABIVLen) <=
-             8;
-    }
+  auto *FirstEltTy = STy->getElementType(0);
+  if (!STy->containsHomogeneousTypes())
+    return false;
 
-    // If elements are not fixed-length vectors, it should be an array.
+  if (auto *ArrayTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) {
+    // Only struct of single array is accepted
     if (NumElts != 1)
       return false;
+    FirstEltTy = ArrayTy->getArrayElementType();
+    NumElts = ArrayTy->getNumElements();
+  }
 
-    // Check array of fixed-length vector and turn it into scalable vector type
-    // if legal.
-    if (auto *ArrTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) {
-      unsigned NumArrElt = ArrTy->getNumElements();
-      if (NumArrElt > 8)
-        return false;
-
-      auto *ArrEltTy = dyn_cast<llvm::FixedVectorType>(ArrTy->getElementType());
-      if (!ArrEltTy)
-        return false;
+  auto *FixedVecTy = dyn_cast<llvm::FixedVectorType>(FirstEltTy);
+  if (!FixedVecTy)
+    return false;
 
-      // LMUL
-      // = NumArrElt * fixed-length vector size / ABIVLen
-      // = fixed-length vector elt size * ScalVecNumElts / RVVBitsPerBlock
-      // =>
-      // ScalVecNumElts
-      // = (NumArrElt * fixed-length vector size * RVVBitsPerBlock) /
-      //   (ABIVLen * fixed-length vector elt size)
-      // = NumArrElt * num fixed-length vector elt * RVVBitsPerBlock /
-      //   ABIVLen
-      unsigned ScalVecNumElts = llvm::divideCeil(
-          NumArrElt * ArrEltTy->getNumElements() * llvm::RISCV::RVVBitsPerBlock,
-          ABIVLen);
-      VLSType = llvm::ScalableVectorType::get(ArrEltTy->getElementType(),
-                                              ScalVecNumElts);
-      // Check registers needed <= 8.
-      return llvm::divideCeil(
-                 ScalVecNumElts *
-                     ArrEltTy->getElementType()->getScalarSizeInBits(),
-                 llvm::RISCV::RVVBitsPerBlock) <= 8;
-    }
+  // Turn them into scalable vector type or vector tuple type if legal.
+  if (NumElts == 1) {
+    // Handle single fixed-length vector.
+    VLSType = llvm::ScalableVectorType::get(
+        FixedVecTy->getElementType(),
+        llvm::divideCeil(FixedVecTy->getNumElements() *
+                             llvm::RISCV::RVVBitsPerBlock,
+                         ABIVLen));
+    // Check registers needed <= 8.
+    return llvm::divideCeil(
+               FixedVecTy->getNumElements() *
+                   FixedVecTy->getElementType()->getScalarSizeInBits(),
+               ABIVLen) <= 8;
   }
-  return false;
+  // LMUL
+  // = fixed-length vector size / ABIVLen
+  // = 8 * I8EltCount / RVVBitsPerBlock
+  // =>
+  // I8EltCount
+  // = (fixed-length vector size * RVVBitsPerBlock) / (ABIVLen * 8)
+  unsigned I8EltCount =
+      llvm::divideCeil(FixedVecTy->getNumElements() *
+                           FixedVecTy->getElementType()->getScalarSizeInBits() *
+                           llvm::RISCV::RVVBitsPerBlock,
+                       ABIVLen * 8);
+  VLSType = llvm::TargetExtType::get(
+      getVMContext(), "riscv.vector.tuple",
+      llvm::ScalableVectorType::get(llvm::Type::getInt8Ty(getVMContext()),
+                                    I8EltCount),
+      NumElts);
+  // Check registers needed <= 8.
+  return NumElts * llvm::divideCeil(
+                       FixedVecTy->getNumElements() *
+                           FixedVecTy->getElementType()->getScalarSizeInBits(),
+                       ABIVLen) <=
+         8;
 }
 
 // Fixed-length RVV vectors are represented as scalable vectors in function
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
index 3044d91f1c31c..82e43fff0c3aa 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.c
@@ -153,14 +153,14 @@ void __attribute__((riscv_vls_cc)) test_st_i32x4_arr1(struct st_i32x4_arr1 arg)
 // CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr1_256(<vscale x 1 x i32> %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 8 x i8>, 4) %arg)
 void __attribute__((riscv_vls_cc)) test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256(<vscale x 4 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr4_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 4) %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8(<vscale x 16 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg)
 void __attribute__((riscv_vls_cc)) test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @test_st_i32x4_arr8_256(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg)
 void __attribute__((riscv_vls_cc(256))) test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {}
 
 // CHECK-LLVM: define dso_local riscv_vls_cc(128) void @test_st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg)
diff --git a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
index 594bfe159b28c..5f6539796c20d 100644
--- a/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
+++ b/clang/test/CodeGen/RISCV/riscv-vector-callingconv-llvm-ir.cpp
@@ -133,14 +133,14 @@ typedef int __attribute__((vector_size(256))) int32x64_t;
 // CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr1_25613st_i32x4_arr1(<vscale x 1 x i32> %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr1_256(struct st_i32x4_arr1 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr413st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 8 x i8>, 4) %arg)
 [[riscv::vls_cc]] void test_st_i32x4_arr4(struct st_i32x4_arr4 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4(<vscale x 4 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr4_25613st_i32x4_arr4(target("riscv.vector.tuple", <vscale x 4 x i8>, 4) %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr4_256(struct st_i32x4_arr4 arg) {}
 
-// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8(<vscale x 16 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z18test_st_i32x4_arr813st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 8 x i8>, 8) %arg)
 [[riscv::vls_cc]] void test_st_i32x4_arr8(struct st_i32x4_arr8 arg) {}
-// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8(<vscale x 8 x i32> %arg)
+// CHECK-LLVM: define dso_local riscv_vls_cc(256) void @_Z22test_st_i32x4_arr8_25613st_i32x4_arr8(target("riscv.vector.tuple", <vscale x 4 x i8>, 8) %arg)
 [[riscv::vls_cc(256)]] void test_st_i32x4_arr8_256(struct st_i32x4_arr8 arg) {}
 
 // CHECK-LLVM: define dso_local riscv_vls_cc(128) void @_Z15test_st_i32x4x210st_i32x4x2(target("riscv.vector.tuple", <vscale x 8 x i8>, 2) %arg)

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@4vtomat 4vtomat merged commit 6ee3751 into llvm:main Jul 9, 2025
9 checks passed
@4vtomat 4vtomat deleted the vls_cc_struct_of_array branch July 9, 2025 04:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:RISC-V clang:codegen IR generation bugs: mangling, exceptions, etc. clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants