[clang] [llvm] [LLVMABI][AARCH64] Handle vector types (PR #225201)

Madhur Amilkanthwar via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 28 01:47:20 PDT 2026


================
@@ -195,10 +230,114 @@ ArgInfo AArch64TargetInfo::classifyArgumentType(
 }
 
 bool AArch64TargetInfo::passAsAggregateType(const Type *Ty) const {
-  // TODO: Handle SVE types. For now, they don't get through the type mapper.
+  if (Opts.Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessType()) {
+    // svcount_t and the single-vector types occupy a register of their own,
+    // so only the data and predicate tuples are passed as aggregates.
+    const auto *TupleTy = dyn_cast<TupleType>(Ty);
+    assert((!TupleTy || TupleTy->getNumVectors() > 1) &&
+           "unexpected single vector tuple");
+    return TupleTy && !TupleTy->getVectorType()->isSVECount();
+  }
   return isAggregateTypeForABI(Ty);
 }
 
+/// Returns the scalable vector type that \p VT, a fixed-length SVE vector,
+/// is passed as. A scalable SVE vector holds 128 bits per granule, so the
+/// scalable element count is 128 divided by the element size, regardless of
+/// how many elements the fixed-length type has.
+const VectorType *AArch64TargetInfo::convertFixedToScalableVectorType(
+    const VectorType *VT) const {
+  // TODO: Verify that this correctly handles MFloat8 when we decide on a
+  // mapping for that type.
+
+  if (VT->isFixedLengthSVEPredicate())
+    return TB.getScalablePredicateVectorType();
+
+  assert(VT->isFixedLengthSVEData() && "expected a fixed-length SVE vector!");
+
+  const Type *EltTy = VT->getElementType();
+  uint64_t EltBits = EltTy->getSizeInBits().getFixedValue();
+  assert(EltBits >= 8 && EltBits <= 64 && isPowerOf2_64(EltBits) &&
+         "unexpected element type for SVE data vector!");
+
+  return TB.getVectorType(EltTy, ElementCount::getScalable(128 / EltBits),
+                          llvm::Align(16), VectorKind::SVEData);
+}
+
+ArgInfo AArch64TargetInfo::coerceIllegalVector(const Type *Ty, unsigned &NSRN,
+                                               unsigned &NPRN) const {
+  const auto *VT = cast<VectorType>(Ty);
+
+  if (VT->isFixedLengthSVEPredicate()) {
+    // Fixed-length predicates are described with 8-bit elements, but they are
+    // passed in a predicate register as a scalable vector of 16 one-bit
+    // elements.
+    assert(isa<IntegerType>(VT->getElementType()) &&
+           VT->getElementType()->getSizeInBits().getFixedValue() == 8 &&
+           "unexpected element type for SVE predicate!");
+    NPRN = std::min(NPRN + 1, 4u);
+    return ArgInfo::getDirect(TB.getScalablePredicateVectorType());
+  }
+
+  if (VT->isFixedLengthSVEData()) {
+    NSRN = std::min(NSRN + 1, 8u);
+    return ArgInfo::getDirect(convertFixedToScalableVectorType(VT));
+  }
+
+  uint64_t Size = VT->getABISizeInBits();
+  // Android promotes <2 x i8> to i16, not i32
+  if (Opts.IsAndroidOrOHOS && (Size <= 16)) {
+    auto *ResType = TB.getIntegerType(16, llvm::Align(2), /*Signed=*/false);
+    return ArgInfo::getDirect(ResType);
+  }
+  const Type *I32 = TB.getIntegerType(32, llvm::Align(4), /*Signed=*/false);
+  if (Size <= 32)
+    return ArgInfo::getDirect(I32);
+  if (Size == 64) {
+    NSRN = std::min(NSRN + 1, 8u);
+    return ArgInfo::getDirect(
+        TB.getVectorType(I32, ElementCount::getFixed(2), llvm::Align(8)));
+  }
+  if (Size == 128) {
+    NSRN = std::min(NSRN + 1, 8u);
+    return ArgInfo::getDirect(
+        TB.getVectorType(I32, ElementCount::getFixed(4), llvm::Align(16)));
+  }
+
+  return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
+}
+
+bool AArch64TargetInfo::isIllegalVectorType(const Type *Ty) const {
+  if (const auto *VT = dyn_cast<VectorType>(Ty)) {
+    // Check whether VT is a fixed-length SVE vector. These types are
+    // represented as scalable vectors in function args/return and must be
+    // coerced from fixed vectors.
+    if (VT->isFixedLengthSVEData() || VT->isFixedLengthSVEPredicate())
+      return true;
+
+    // Scalable SVE types are legal.
+    if (VT->isScalable())
+      return false;
+
+    // Check whether VT is legal.
+    assert(VT->getNumElements().isFixed() &&
+           "expected fixed number of elements!");
+    unsigned NumElements = VT->getNumElements().getKnownMinValue();
+    uint64_t Size = VT->getABISizeInBits();
+    // NumElements should be power of 2.
+    if (!llvm::isPowerOf2_32(NumElements))
----------------
madhur13490 wrote:

Nit: llvm:: isn't needed here since we're inside namespace llvm, and line 260 calls isPowerOf2_64 without it.

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


More information about the llvm-commits mailing list