1//===- AArch64.cpp - AArch64 ABI Implementation ---------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ABI/FunctionInfo.h"
10#include "llvm/ABI/TargetInfo.h"
11#include "llvm/ABI/Types.h"
12#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/SmallVector.h"
14#include "llvm/Support/Casting.h"
15#include "llvm/Support/ErrorHandling.h"
16#include "llvm/Support/MathExtras.h"
17#include "llvm/Support/TypeSize.h"
18#include "llvm/Support/WithColor.h"
19#include <algorithm>
20#include <cstdint>
21
22namespace llvm {
23namespace abi {
24
25class AArch64TargetInfo : public TargetInfo {
26public:
27 AArch64TargetInfo(TypeBuilder &TB, const AArch64ABIOptions &Opts)
28 : TargetInfo(TB), Opts(Opts) {}
29
30 const ABICompatInfo &getABICompatInfo() const override {
31 return Opts.CompatInfo;
32 }
33
34 void computeInfo(FunctionInfo &FI) const override {
35 if (!maybeCommonClassifyReturnType(FI))
36 FI.getReturnInfo() =
37 classifyReturnType(RetTy: FI.getReturnType(), IsVariadicFn: FI.isVariadic());
38
39 unsigned ArgNo = 0;
40 unsigned NSRN = 0, NPRN = 0;
41 for (auto &I : FI.arguments()) {
42 const bool IsNamedArg =
43 !FI.isVariadic() || ArgNo < FI.getNumRequiredArgs();
44 ++ArgNo;
45 I.Info = classifyArgumentType(Ty: I.ABIType, IsVariadicFn: FI.isVariadic(), IsNamedArg,
46 CallingConvention: FI.getCallingConvention(), NSRN, NPRN);
47 }
48 }
49
50private:
51 AArch64ABIOptions Opts;
52
53 ArgInfo classifyReturnType(const Type *RetTy, bool IsVariadicFn) const;
54 ArgInfo classifyArgumentType(const Type *Ty, bool IsVariadicFn,
55 bool IsNamedArg, unsigned CallingConvention,
56 unsigned &NSRN, unsigned &NPRN) const;
57
58 bool isDarwinPCS() const { return Opts.Kind == AArch64ABIKind::DarwinPCS; }
59 bool isSoftFloat() const { return Opts.Kind == AArch64ABIKind::AAPCSSoft; }
60
61 const VectorType *
62 convertFixedToScalableVectorType(const VectorType *VT) const;
63
64 ArgInfo coerceIllegalVector(const VectorType *VT, unsigned &NSRN,
65 unsigned &NPRN) const;
66 ArgInfo coerceAndExpandPureScalableAggregate(
67 const Type *Ty, bool IsNamedArg, unsigned NVec, unsigned NPred,
68 const SmallVectorImpl<const Type *> &UnpaddedCoerceToSeq, unsigned &NSRN,
69 unsigned &NPRN) const;
70
71 bool isIllegalVectorType(const Type *Ty) const;
72
73 bool passAsAggregateType(const Type *Ty) const;
74 bool passAsPureScalableType(const Type *Ty, unsigned &NV, unsigned &NP,
75 SmallVectorImpl<const Type *> &CoerceToSeq) const;
76
77 void flattenType(const Type *Ty,
78 SmallVectorImpl<const Type *> &Flattened) const;
79
80 bool isHomogeneousAggregateBaseType(const Type *Ty) const override;
81 bool isHomogeneousAggregateSmallEnough(const Type *Base,
82 uint64_t Members) const override;
83 bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const override;
84 bool isPermittedToBeHomogeneousAggregate(const RecordType *RT) const override;
85};
86
87std::unique_ptr<TargetInfo>
88createAArch64TargetInfo(TypeBuilder &TB, const AArch64ABIOptions &Opts) {
89 return std::make_unique<AArch64TargetInfo>(args&: TB, args: Opts);
90}
91
92static void reportNYI(StringRef Feature) {
93 WithColor::warning()
94 << Feature
95 << " is not yet implemented for AArch64 in the LLVM ABI library.\n";
96}
97
98ArgInfo AArch64TargetInfo::classifyReturnType(const Type *RetTy,
99 bool IsVariadicFn) const {
100 if (RetTy->isVoid())
101 return ArgInfo::getIgnore();
102
103 if (const auto *VT = dyn_cast<VectorType>(Val: RetTy)) {
104 if (VT->isFixedLengthSVEData() || VT->isFixedLengthSVEPredicate()) {
105 unsigned NSRN = 0, NPRN = 0;
106 return coerceIllegalVector(VT, NSRN, NPRN);
107 }
108
109 // Large vector types should be returned via memory.
110 if (VT->getABISizeInBits() > 128)
111 return getNaturalAlignIndirect(Ty: RetTy, AddrSpace: getAllocaAddrSpace());
112 }
113
114 if (!passAsAggregateType(Ty: RetTy)) {
115 if (const auto *IntTy = dyn_cast<IntegerType>(Val: RetTy)) {
116 if (IntTy->isBitInt())
117 if (RetTy->getSizeInBits().getFixedValue() > 128)
118 return getNaturalAlignIndirect(Ty: RetTy, AddrSpace: getAllocaAddrSpace());
119
120 if (isPromotableInteger(IT: IntTy) && isDarwinPCS())
121 return ArgInfo::getExtend(T: IntTy);
122 }
123
124 // Everything not handled above is returned directly.
125 return ArgInfo::getDirect();
126 }
127
128 uint64_t Size = RetTy->getFixedSizeInBitsOrZero();
129 if (!RetTy->isSVESizelessType() && (RetTy->isEmptyRecord() || Size == 0))
130 return ArgInfo::getIgnore();
131
132 const Type *Base = nullptr;
133 uint64_t Members = 0;
134 if (isHomogeneousAggregate(Ty: RetTy, Base, Members) &&
135 !(Opts.IsILP32 && IsVariadicFn)) {
136 // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
137 return ArgInfo::getDirect();
138 }
139
140 // In AAPCS return values of a Pure Scalable type are treated as a single
141 // named argument and passed expanded in registers, or indirectly if there are
142 // not enough registers.
143 if (Opts.Kind == AArch64ABIKind::AAPCS) {
144 unsigned NSRN = 0, NPRN = 0;
145 unsigned NVec = 0, NPred = 0;
146 SmallVector<const Type *> UnpaddedCoerceToSeq;
147 if (passAsPureScalableType(Ty: RetTy, NV&: NVec, NP&: NPred, CoerceToSeq&: UnpaddedCoerceToSeq) &&
148 (NVec + NPred) > 0)
149 return coerceAndExpandPureScalableAggregate(
150 Ty: RetTy, /*IsNamedArg=*/true, NVec, NPred, UnpaddedCoerceToSeq, NSRN,
151 NPRN);
152 }
153
154 reportNYI(Feature: "Aggregate return type handling");
155 return ArgInfo::getIgnore();
156}
157
158ArgInfo AArch64TargetInfo::classifyArgumentType(
159 const Type *Ty, bool IsVariadicFn, bool IsNamedArg,
160 unsigned CallingConvention, unsigned &NSRN, unsigned &NPRN) const {
161 Ty = useFirstFieldIfTransparentUnion(Ty);
162
163 // Arm64EC variadic functions classify their arguments with the x86-64
164 // rules rather than the AArch64 ones.
165 if (IsVariadicFn && Opts.IsWindowsArm64EC) {
166 reportNYI(Feature: "Arm64EC variadic argument handling");
167 return ArgInfo::getIgnore();
168 }
169
170 // Handle illegal vector types here.
171 if (isIllegalVectorType(Ty))
172 return coerceIllegalVector(VT: cast<VectorType>(Val: Ty), NSRN, NPRN);
173
174 if (!passAsAggregateType(Ty)) {
175 if (const auto *IntTy = dyn_cast<IntegerType>(Val: Ty)) {
176 if (IntTy->isBitInt())
177 if (Ty->getSizeInBits().getFixedValue() > 128)
178 return getNaturalAlignIndirect(Ty, AddrSpace: getAllocaAddrSpace(),
179 /*ByVal=*/false);
180
181 if (isPromotableInteger(IT: IntTy) && isDarwinPCS())
182 return ArgInfo::getExtend(T: IntTy);
183 }
184
185 // Predicates and svcount_t are passed in a predicate register. Legal
186 // vectors, SVE data vectors, and floating-point types are passed in a
187 // SIMD and floating-point register. A tuple occupies one register of the
188 // appropriate kind per vector it contains.
189 if (const auto *VT = dyn_cast<VectorType>(Val: Ty)) {
190 if (VT->isSVEPredicate() || VT->isSVECount())
191 NPRN = std::min(a: NPRN + 1, b: 4u);
192 else
193 NSRN = std::min(a: NSRN + 1, b: 8u);
194 } else if (const auto *TT = dyn_cast<TupleType>(Val: Ty)) {
195 if (TT->getVectorType()->isSVEPredicate())
196 NPRN = std::min(a: NPRN + TT->getNumVectors(), b: 4u);
197 else
198 NSRN = std::min(a: NSRN + TT->getNumVectors(), b: 8u);
199 } else if (Ty->isFloat()) {
200 NSRN = std::min(a: NSRN + 1, b: 8u);
201 }
202
203 // Everything not handled above is returned directly.
204 return ArgInfo::getDirect();
205 }
206
207 // Structures with either a non-trivial destructor or a non-trivial
208 // copy constructor are always indirect.
209 if (auto RecordRAA = getRecordArgABI(Ty)) {
210 return getNaturalAlignIndirect(Ty, AddrSpace: getAllocaAddrSpace(),
211 /*ByVal=*/RecordRAA ==
212 RecordArgABI::RAA_DirectInMemory);
213 }
214
215 // AAPCS64 does not say that empty C records are ignored as arguments,
216 // but other compilers do so in certain situations, and we copy that behavior.
217 uint64_t Size = Ty->getFixedSizeInBitsOrZero();
218 if (!Ty->isSVESizelessType() && (Ty->isEmptyRecord() || Size == 0)) {
219 // Darwin overrides the psABI here to ignore all empty records in all modes.
220 // The ABI explicitly says that an empty class shall be treated as if its
221 // type were an aggregate with a single member of type unsigned byte.
222 if (!Opts.IsCXX || isDarwinPCS())
223 return ArgInfo::getIgnore();
224
225 // In C++ mode, arguments which have sizeof() == 0 (which are non-standard
226 // C++) are ignored. This isn't defined by any standard, so we copy GCC's
227 // behaviour here.
228 if (Size == 0)
229 return ArgInfo::getIgnore();
230 }
231
232 // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
233 const Type *Base = nullptr;
234 uint64_t Members = 0;
235 bool IsWin64 = Opts.Kind == AArch64ABIKind::Win64 ||
236 CallingConvention == llvm::CallingConv::Win64;
237 bool IsWinVariadic = IsWin64 && IsVariadicFn;
238 // In variadic functions on Windows, all composite types are treated alike,
239 // no special handling of HFAs/HVAs.
240 if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) {
241 NSRN = std::min(a: NSRN + Members, b: uint64_t(8));
242 uint64_t BaseAllocSizeInBits = Base->getTypeAllocSize().getFixedValue() * 8;
243 const Type *CoerceTy =
244 TB.getArrayType(ElementType: Base, NumElements: Members, SizeInBits: Members * BaseAllocSizeInBits);
245 if (Opts.Kind != AArch64ABIKind::AAPCS)
246 return ArgInfo::getDirect(T: CoerceTy);
247
248 // For HFAs/HVAs, cap the argument alignment to 16, otherwise
249 // set it to 8 according to the AAPCS64 document.
250 unsigned TyAlign = Ty->getUnadjustedAlignment().value();
251 TyAlign = (TyAlign >= 16) ? 16 : 8;
252 return ArgInfo::getDirect(T: CoerceTy, /*Offset=*/0, Align: llvm::Align(TyAlign));
253 }
254
255 // In AAPCS, named arguments of a Pure Scalable Type are passed expanded
256 // in registers, or indirectly if there are not enough registers.
257 if (Opts.Kind == AArch64ABIKind::AAPCS) {
258 unsigned NVec = 0, NPred = 0;
259 SmallVector<const Type *> UnpaddedCoerceToSeq;
260 if (passAsPureScalableType(Ty, NV&: NVec, NP&: NPred, CoerceToSeq&: UnpaddedCoerceToSeq) &&
261 (NVec + NPred) > 0)
262 return coerceAndExpandPureScalableAggregate(
263 Ty, IsNamedArg, NVec, NPred, UnpaddedCoerceToSeq, NSRN, NPRN);
264 }
265
266 reportNYI(Feature: "Aggregate argument type handling");
267 return ArgInfo::getIgnore();
268}
269
270bool AArch64TargetInfo::passAsAggregateType(const Type *Ty) const {
271 if (Opts.Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessType()) {
272 // svcount_t and the single-vector types occupy a register of their own,
273 // so only the data and predicate tuples are passed as aggregates.
274 const auto *TupleTy = dyn_cast<TupleType>(Val: Ty);
275 assert((!TupleTy || TupleTy->getNumVectors() > 1) &&
276 "unexpected single vector tuple");
277 return TupleTy && !TupleTy->getVectorType()->isSVECount();
278 }
279 return isAggregateTypeForABI(Ty);
280}
281
282/// Returns the scalable vector type that \p VT, a fixed-length SVE vector,
283/// is passed as. A scalable SVE vector holds 128 bits per granule, so the
284/// scalable element count is 128 divided by the element size, regardless of
285/// how many elements the fixed-length type has.
286const VectorType *AArch64TargetInfo::convertFixedToScalableVectorType(
287 const VectorType *VT) const {
288 // TODO: Verify that this correctly handles MFloat8 when we decide on a
289 // mapping for that type.
290
291 if (VT->isFixedLengthSVEPredicate())
292 return TB.getScalablePredicateOrCountVectorType(ABIAlign: Align(2),
293 Kind: VectorKind::SVEPredicate);
294
295 assert(VT->isFixedLengthSVEData() && "expected a fixed-length SVE vector!");
296
297 const Type *EltTy = VT->getElementType();
298 uint64_t EltBits = EltTy->getSizeInBits().getFixedValue();
299 assert(EltBits >= 8 && EltBits <= 64 && isPowerOf2_64(EltBits) &&
300 "unexpected element type for SVE data vector!");
301
302 return TB.getVectorType(ElementType: EltTy, NumElements: ElementCount::getScalable(MinVal: 128 / EltBits),
303 Align: llvm::Align(16), VecKind: VectorKind::SVEData);
304}
305
306ArgInfo AArch64TargetInfo::coerceIllegalVector(const VectorType *VT,
307 unsigned &NSRN,
308 unsigned &NPRN) const {
309 if (VT->isFixedLengthSVEPredicate()) {
310 // Fixed-length predicates are described with 8-bit elements, but they are
311 // passed in a predicate register as a scalable vector of 16 one-bit
312 // elements.
313 assert(isa<IntegerType>(VT->getElementType()) &&
314 VT->getElementType()->getSizeInBits().getFixedValue() == 8 &&
315 "unexpected element type for SVE predicate!");
316 NPRN = std::min(a: NPRN + 1, b: 4u);
317 return ArgInfo::getDirect(T: TB.getScalablePredicateOrCountVectorType(
318 ABIAlign: Align(2), Kind: VectorKind::SVEPredicate));
319 }
320
321 if (VT->isFixedLengthSVEData()) {
322 NSRN = std::min(a: NSRN + 1, b: 8u);
323 return ArgInfo::getDirect(T: convertFixedToScalableVectorType(VT));
324 }
325
326 uint64_t Size = VT->getABISizeInBits();
327 // Android promotes <2 x i8> to i16, not i32
328 if (Opts.IsAndroidOrOHOS && (Size <= 16)) {
329 auto *ResType = TB.getIntegerType(BitWidth: 16, Align: llvm::Align(2), /*Signed=*/false);
330 return ArgInfo::getDirect(T: ResType);
331 }
332 const Type *I32 = TB.getIntegerType(BitWidth: 32, Align: llvm::Align(4), /*Signed=*/false);
333 if (Size <= 32)
334 return ArgInfo::getDirect(T: I32);
335 if (Size == 64) {
336 NSRN = std::min(a: NSRN + 1, b: 8u);
337 return ArgInfo::getDirect(
338 T: TB.getVectorType(ElementType: I32, NumElements: ElementCount::getFixed(MinVal: 2), Align: llvm::Align(8)));
339 }
340 if (Size == 128) {
341 NSRN = std::min(a: NSRN + 1, b: 8u);
342 return ArgInfo::getDirect(
343 T: TB.getVectorType(ElementType: I32, NumElements: ElementCount::getFixed(MinVal: 4), Align: llvm::Align(16)));
344 }
345
346 return getNaturalAlignIndirect(Ty: VT, AddrSpace: getAllocaAddrSpace(), /*ByVal=*/false);
347}
348
349bool AArch64TargetInfo::isIllegalVectorType(const Type *Ty) const {
350 if (const auto *VT = dyn_cast<VectorType>(Val: Ty)) {
351 // Check whether VT is a fixed-length SVE vector. These types are
352 // represented as scalable vectors in function args/return and must be
353 // coerced from fixed vectors.
354 if (VT->isFixedLengthSVEData() || VT->isFixedLengthSVEPredicate())
355 return true;
356
357 // Scalable SVE types are legal.
358 if (VT->isScalable())
359 return false;
360
361 // Check whether VT is legal.
362 unsigned NumElements = VT->getNumElements().getFixedValue();
363 uint64_t Size = VT->getABISizeInBits();
364 // NumElements should be power of 2.
365 if (!isPowerOf2_32(Value: NumElements))
366 return true;
367
368 // arm64_32 has to be compatible with the ARM logic here, which allows huge
369 // vectors for some reason.
370 if (Opts.IsILP32 && Opts.IsMachO)
371 return Size <= 32;
372
373 return Size != 64 && (Size != 128 || NumElements == 1);
374 }
375 return false;
376}
377
378// Expand a memory type into a sequence with an element for each non-record,
379// non-array member of the type, with the exception of the padding types, which
380// are retained.
381void AArch64TargetInfo::flattenType(
382 const Type *Ty, SmallVectorImpl<const Type *> &Flattened) const {
383 if (ArgInfo::isPaddingForCoerceAndExpand(Ty)) {
384 Flattened.push_back(Elt: Ty);
385 return;
386 }
387
388 if (const auto *AT = dyn_cast<ArrayType>(Val: Ty)) {
389 uint64_t NElt = AT->getNumElements();
390 if (NElt == 0)
391 return;
392
393 SmallVector<const Type *, 4> EltFlattened;
394 flattenType(Ty: AT->getElementType(), Flattened&: EltFlattened);
395
396 for (uint64_t I = 0; I < NElt; ++I)
397 llvm::append_range(C&: Flattened, R&: EltFlattened);
398 return;
399 }
400
401 if (const auto *RT = dyn_cast<RecordType>(Val: Ty)) {
402 for (const FieldInfo &Field : RT->getFields())
403 flattenType(Ty: Field.FieldType, Flattened);
404 return;
405 }
406
407 Flattened.push_back(Elt: Ty);
408}
409
410ArgInfo AArch64TargetInfo::coerceAndExpandPureScalableAggregate(
411 const Type *Ty, bool IsNamedArg, unsigned NVec, unsigned NPred,
412 const SmallVectorImpl<const Type *> &UnpaddedCoerceToSeq, unsigned &NSRN,
413 unsigned &NPRN) const {
414 // An unnamed argument, or one that does not fit in the remaining Z or P
415 // registers, is passed indirectly and does not consume those registers.
416 if (!IsNamedArg || NSRN + NVec > 8 || NPRN + NPred > 4)
417 return getNaturalAlignIndirect(Ty, AddrSpace: getAllocaAddrSpace(), /*ByVal=*/false);
418
419 NSRN += NVec;
420 NPRN += NPred;
421
422 // A sizeless SVE tuple is already one register per member.
423 if (Ty->isSVESizelessType())
424 return ArgInfo::getDirect();
425
426 assert(!UnpaddedCoerceToSeq.empty() && "pure scalable type has no members");
427 const Type *UnpaddedCoerceToType =
428 UnpaddedCoerceToSeq.size() == 1
429 ? UnpaddedCoerceToSeq[0]
430 : getStructOfTypes(Elems: UnpaddedCoerceToSeq, /*Packed=*/true);
431
432 SmallVector<const Type *, 8> CoerceToSeq;
433 flattenType(Ty: convertTypeForMem(Ty), Flattened&: CoerceToSeq);
434 return ArgInfo::getCoerceAndExpand(
435 CoerceToType: getStructOfTypes(Elems: CoerceToSeq, /*Packed=*/false), UnpaddedCoerceToType);
436}
437
438// A Pure Scalable Type (AAPCS64) is passed in Z and P registers. On success
439// NVec and NPred are how many of each it needs, and CoerceToSeq has one
440// scalable vector per register. A sequence longer than 12 is rejected so the
441// caller treats the type as a large composite.
442bool AArch64TargetInfo::passAsPureScalableType(
443 const Type *Ty, unsigned &NVec, unsigned &NPred,
444 SmallVectorImpl<const Type *> &CoerceToSeq) const {
445 if (const auto *AT = dyn_cast<ArrayType>(Val: Ty)) {
446 if (AT->isMatrixType())
447 return false;
448
449 uint64_t NElt = AT->getNumElements();
450 if (NElt == 0)
451 return false;
452
453 unsigned NV = 0, NP = 0;
454 SmallVector<const Type *, 4> EltCoerceToSeq;
455 if (!passAsPureScalableType(Ty: AT->getElementType(), NVec&: NV, NPred&: NP, CoerceToSeq&: EltCoerceToSeq))
456 return false;
457
458 if (CoerceToSeq.size() + NElt * EltCoerceToSeq.size() > 12)
459 return false;
460
461 for (uint64_t I = 0; I < NElt; ++I)
462 llvm::append_range(C&: CoerceToSeq, R&: EltCoerceToSeq);
463
464 NVec += NElt * NV;
465 NPred += NElt * NP;
466 return true;
467 }
468
469 if (const auto *RT = dyn_cast<RecordType>(Val: Ty)) {
470 if (getRecordArgABI(RT) != RAA_Default)
471 return false;
472 // Pure scalable types are never unions and never contain unions.
473 if (RT->isUnion())
474 return false;
475
476 // A flexible array member is lowered as a zero-length array, which the
477 // field walk below skips. The member disqualifies a pure scalable type.
478 if (RT->hasFlexibleArrayMember())
479 return false;
480
481 // Direct virtual bases are not in getBaseClasses(). A record that has
482 // one cannot be passed in registers, and getRecordArgABI rejected it
483 // above.
484 for (const FieldInfo &Base : RT->getBaseClasses()) {
485 if (Base.FieldType->isEmptyRecord())
486 continue;
487 if (!passAsPureScalableType(Ty: Base.FieldType, NVec, NPred, CoerceToSeq))
488 return false;
489 }
490 for (const FieldInfo &Field : RT->getFields()) {
491 if (Field.isEmpty())
492 continue;
493 if (!passAsPureScalableType(Ty: Field.FieldType, NVec, NPred, CoerceToSeq))
494 return false;
495 }
496 return true;
497 }
498
499 if (const auto *TT = dyn_cast<TupleType>(Val: Ty)) {
500 const VectorType *VT = TT->getVectorType();
501 if (!VT->isScalable() || VT->isSVECount())
502 return false;
503
504 unsigned N = TT->getNumVectors();
505 if (CoerceToSeq.size() + N > 12)
506 return false;
507
508 bool IsPred = VT->isSVEPredicate();
509 if (!IsPred && !VT->isSVEData())
510 return false;
511 if (IsPred)
512 NPred += N;
513 else
514 NVec += N;
515
516 for (unsigned I = 0; I < N; ++I)
517 CoerceToSeq.push_back(Elt: VT);
518 return true;
519 }
520
521 if (const auto *VT = dyn_cast<VectorType>(Val: Ty)) {
522 const Type *Coerced = nullptr;
523 bool IsPred = false;
524 if (VT->isFixedLengthSVEPredicate()) {
525 IsPred = true;
526 Coerced = convertFixedToScalableVectorType(VT);
527 } else if (VT->isFixedLengthSVEData()) {
528 Coerced = convertFixedToScalableVectorType(VT);
529 } else if (VT->isScalable() && VT->isSVEPredicate()) {
530 IsPred = true;
531 Coerced = VT;
532 } else if (VT->isScalable() && VT->isSVEData()) {
533 Coerced = VT;
534 } else {
535 return false;
536 }
537
538 if (CoerceToSeq.size() + 1 > 12)
539 return false;
540
541 if (IsPred)
542 ++NPred;
543 else
544 ++NVec;
545 CoerceToSeq.push_back(Elt: Coerced);
546 return true;
547 }
548
549 return false;
550}
551
552bool AArch64TargetInfo::isHomogeneousAggregateBaseType(const Type *Ty) const {
553 // Soft-float ABI: no types are homogeneous aggregates.
554 if (isSoftFloat())
555 return false;
556
557 // Homogeneous aggregates for AAPCS64 must have base types of a floating
558 // point type or a short-vector type.
559 if (Ty->isFloat())
560 return true;
561
562 if (const auto *VT = dyn_cast<VectorType>(Val: Ty)) {
563 if (VT->isScalable() || VT->isSVEData() || VT->isSVEPredicate())
564 return false;
565
566 uint64_t VecSize = VT->getABISizeInBits();
567 if (VecSize == 64 || VecSize == 128)
568 return true;
569 }
570 return false;
571}
572
573bool AArch64TargetInfo::isHomogeneousAggregateSmallEnough(
574 const Type * /*Base*/, uint64_t Members) const {
575 return Members <= 4;
576}
577
578bool AArch64TargetInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate()
579 const {
580 // AAPCS64 applies homogeneity to the output of the data layout decision, so
581 // zero-length bitfields do not affect homogeneity.
582 return true;
583}
584
585bool AArch64TargetInfo::isPermittedToBeHomogeneousAggregate(
586 const RecordType *RT) const {
587 if (Opts.IsMicrosoftCXXABI && RT->isCXXRecord()) {
588 // This won't always return false, but we don't have enough information to
589 // perform the full check correctly yet.
590 reportNYI(Feature: "MicrosoftCXXABI homogeneous record classification");
591 return false;
592 }
593
594 return true;
595}
596
597} // namespace abi
598} // namespace llvm
599