[clang] [llvm] [RISCV][VLS] Support RISCV VLS calling convention (PR #100346)

Kito Cheng via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 16 19:04:44 PST 2025


================
@@ -359,9 +405,153 @@ ABIArgInfo RISCVABIInfo::coerceAndExpandFPCCEligibleStruct(
   return ABIArgInfo::getCoerceAndExpand(CoerceToType, UnpaddedCoerceToType);
 }
 
+bool RISCVABIInfo::detectVLSCCEligibleStruct(QualType Ty, unsigned ABIVLen,
+                                             llvm::Type *&VLSType) const {
+  // No riscv_vls_cc attribute.
+  if (ABIVLen == 1)
+    return false;
+
+  // Legal struct for VLS calling convention should fulfill following rules:
+  // 1. Struct element should be either "homogeneous fixed-length vectors" or "a
+  //    fixed-length vector array".
+  // 2. Number of struct elements or array elements should be power of 2.
+  // 3. Total number of vector registers needed should not exceed 8.
+  //
+  // Examples: Assume ABI_VLEN = 128.
+  // These are legal structs:
+  //   a. Structs with 1, 2, 4 or 8 "same" fixed-length vectors, e.g.
+  //   struct {
+  //     __attribute__((vector_size(16))) int a;
+  //     __attribute__((vector_size(16))) int b;
+  //   }
+  //
+  //   b. Structs with "single" fixed-length vector array with lengh 1, 2, 4
+  //   or 8, e.g.
+  //   struct {
+  //     __attribute__((vector_size(16))) int a[2];
+  //   }
+  // These are illegal structs:
+  //   a. Structs with 3 fixed-length vectors, e.g.
+  //   struct {
+  //     __attribute__((vector_size(16))) int a;
+  //     __attribute__((vector_size(16))) int b;
+  //     __attribute__((vector_size(16))) int c;
+  //   }
+  //
+  //   b. Structs with "multiple" fixed-length vector array, e.g.
+  //   struct {
+  //     __attribute__((vector_size(16))) int a[2];
+  //     __attribute__((vector_size(16))) int b[2];
+  //   }
+  //
+  //   c. Vector registers needed exceeds 8, e.g.
+  //   struct {
+  //     // Registers needed for single fixed-length element:
+  //     // 64 * 8 / ABI_VLEN = 4
+  //     __attribute__((vector_size(64))) int a;
+  //     __attribute__((vector_size(64))) int b;
+  //     __attribute__((vector_size(64))) int c;
+  //     __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))) {
+    int NumElts = STy->getStructNumElements();
+    if (NumElts > 8 || !llvm::isPowerOf2_32(NumElts))
+      return false;
+
+    auto *FirstEltTy = STy->getElementType(0);
+    if (!STy->containsHomogeneousTypes())
+      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;
+    }
+
+    // If elements are not fixed-length vectors, it should be an array.
+    if (NumElts != 1)
+      return false;
+
+    // Check array of fixed-length vector and turn it into scalable vector type
+    // if legal.
+    if (auto *ArrTy = dyn_cast<llvm::ArrayType>(FirstEltTy)) {
+      int NumArrElt = ArrTy->getNumElements();
+      if (NumArrElt > 8 || !llvm::isPowerOf2_32(NumArrElt))
----------------
kito-cheng wrote:

```suggestion
      if (NumArrElt > 8)
```

https://github.com/llvm/llvm-project/pull/100346


More information about the llvm-commits mailing list