LLVM 24.0.0git
AArch64.cpp
Go to the documentation of this file.
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
10#include "llvm/ABI/TargetInfo.h"
11#include "llvm/ABI/Types.h"
17#include <algorithm>
18#include <cstdint>
19
20namespace llvm {
21namespace abi {
22
24public:
26 : TargetInfo(TB), Opts(Opts) {}
27
28 const ABICompatInfo &getABICompatInfo() const override {
29 return Opts.CompatInfo;
30 }
31
32 void computeInfo(FunctionInfo &FI) const override {
34 FI.getReturnInfo() =
35 classifyReturnType(FI.getReturnType(), FI.isVariadic());
36
37 unsigned ArgNo = 0;
38 unsigned NSRN = 0, NPRN = 0;
39 for (auto &I : FI.arguments()) {
40 const bool IsNamedArg =
41 !FI.isVariadic() || ArgNo < FI.getNumRequiredArgs();
42 ++ArgNo;
43 I.Info = classifyArgumentType(I.ABIType, FI.isVariadic(), IsNamedArg,
44 FI.getCallingConvention(), NSRN, NPRN);
45 }
46 }
47
48private:
50
51 ArgInfo classifyReturnType(const Type *RetTy, bool IsVariadicFn) const;
52 ArgInfo classifyArgumentType(const Type *Ty, bool IsVariadicFn,
53 bool IsNamedArg, unsigned CallingConvention,
54 unsigned &NSRN, unsigned &NPRN) const;
55
56 bool isDarwinPCS() const { return Opts.Kind == AArch64ABIKind::DarwinPCS; }
57 bool isSoftFloat() const { return Opts.Kind == AArch64ABIKind::AAPCSSoft; }
58
59 const VectorType *
60 convertFixedToScalableVectorType(const VectorType *VT) const;
61
62 ArgInfo coerceIllegalVector(const VectorType *VT, unsigned &NSRN,
63 unsigned &NPRN) const;
64
65 bool isIllegalVectorType(const Type *Ty) const;
66
67 bool passAsAggregateType(const Type *Ty) const;
68
69 bool isHomogeneousAggregateBaseType(const Type *Ty) const override;
70 bool isHomogeneousAggregateSmallEnough(const Type *Base,
71 uint64_t Members) const override;
73 bool isPermittedToBeHomogeneousAggregate(const RecordType *RT) const override;
74};
75
76std::unique_ptr<TargetInfo>
78 return std::make_unique<AArch64TargetInfo>(TB, Opts);
79}
80
81static void reportNYI(StringRef Feature) {
83 << Feature
84 << " is not yet implemented for AArch64 in the LLVM ABI library.\n";
85}
86
87ArgInfo AArch64TargetInfo::classifyReturnType(const Type *RetTy,
88 bool IsVariadicFn) const {
89 if (RetTy->isVoid())
90 return ArgInfo::getIgnore();
91
92 if (const auto *VT = dyn_cast<VectorType>(RetTy)) {
93 if (VT->isFixedLengthSVEData() || VT->isFixedLengthSVEPredicate()) {
94 unsigned NSRN = 0, NPRN = 0;
95 return coerceIllegalVector(VT, NSRN, NPRN);
96 }
97
98 // Large vector types should be returned via memory.
99 if (VT->getABISizeInBits() > 128)
101 }
102
103 if (!passAsAggregateType(RetTy)) {
104 if (const auto *IntTy = dyn_cast<IntegerType>(RetTy)) {
105 if (IntTy->isBitInt())
106 if (RetTy->getSizeInBits().getFixedValue() > 128)
108
109 if (isPromotableInteger(IntTy) && isDarwinPCS())
110 return ArgInfo::getExtend(IntTy);
111 }
112
113 // Everything not handled above is returned directly.
114 return ArgInfo::getDirect();
115 }
116
117 uint64_t Size = RetTy->getFixedSizeInBitsOrZero();
118 if (!RetTy->isSVESizelessType() && (RetTy->isEmptyRecord() || Size == 0))
119 return ArgInfo::getIgnore();
120
121 const Type *Base = nullptr;
122 uint64_t Members = 0;
123 if (isHomogeneousAggregate(RetTy, Base, Members) &&
124 !(Opts.IsILP32 && IsVariadicFn)) {
125 // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
126 return ArgInfo::getDirect();
127 }
128
129 reportNYI("Aggregate return type handling");
130 return ArgInfo::getIgnore();
131}
132
133ArgInfo AArch64TargetInfo::classifyArgumentType(
134 const Type *Ty, bool IsVariadicFn, bool IsNamedArg,
135 unsigned CallingConvention, unsigned &NSRN, unsigned &NPRN) const {
137
138 // Arm64EC variadic functions classify their arguments with the x86-64
139 // rules rather than the AArch64 ones.
140 if (IsVariadicFn && Opts.IsWindowsArm64EC) {
141 reportNYI("Arm64EC variadic argument handling");
142 return ArgInfo::getIgnore();
143 }
144
145 // Handle illegal vector types here.
146 if (isIllegalVectorType(Ty))
147 return coerceIllegalVector(cast<VectorType>(Ty), NSRN, NPRN);
148
149 if (!passAsAggregateType(Ty)) {
150 if (const auto *IntTy = dyn_cast<IntegerType>(Ty)) {
151 if (IntTy->isBitInt())
152 if (Ty->getSizeInBits().getFixedValue() > 128)
154 /*ByVal=*/false);
155
156 if (isPromotableInteger(IntTy) && isDarwinPCS())
157 return ArgInfo::getExtend(IntTy);
158 }
159
160 // Predicates and svcount_t are passed in a predicate register. Legal
161 // vectors, SVE data vectors, and floating-point types are passed in a
162 // SIMD and floating-point register. A tuple occupies one register of the
163 // appropriate kind per vector it contains.
164 if (const auto *VT = dyn_cast<VectorType>(Ty)) {
165 if (VT->isSVEPredicate() || VT->isSVECount())
166 NPRN = std::min(NPRN + 1, 4u);
167 else
168 NSRN = std::min(NSRN + 1, 8u);
169 } else if (const auto *TT = dyn_cast<TupleType>(Ty)) {
170 if (TT->getVectorType()->isSVEPredicate())
171 NPRN = std::min(NPRN + TT->getNumVectors(), 4u);
172 else
173 NSRN = std::min(NSRN + TT->getNumVectors(), 8u);
174 } else if (Ty->isFloat()) {
175 NSRN = std::min(NSRN + 1, 8u);
176 }
177
178 // Everything not handled above is returned directly.
179 return ArgInfo::getDirect();
180 }
181
182 // Structures with either a non-trivial destructor or a non-trivial
183 // copy constructor are always indirect.
184 if (auto RecordRAA = getRecordArgABI(Ty)) {
186 /*ByVal=*/RecordRAA ==
188 }
189
190 // AAPCS64 does not say that empty C records are ignored as arguments,
191 // but other compilers do so in certain situations, and we copy that behavior.
192 uint64_t Size = Ty->getFixedSizeInBitsOrZero();
193 if (!Ty->isSVESizelessType() && (Ty->isEmptyRecord() || Size == 0)) {
194 // Darwin overrides the psABI here to ignore all empty records in all modes.
195 // The ABI explicitly says that an empty class shall be treated as if its
196 // type were an aggregate with a single member of type unsigned byte.
197 if (!Opts.IsCXX || isDarwinPCS())
198 return ArgInfo::getIgnore();
199
200 // In C++ mode, arguments which have sizeof() == 0 (which are non-standard
201 // C++) are ignored. This isn't defined by any standard, so we copy GCC's
202 // behaviour here.
203 if (Size == 0)
204 return ArgInfo::getIgnore();
205 }
206
207 // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
208 const Type *Base = nullptr;
209 uint64_t Members = 0;
210 bool IsWin64 = Opts.Kind == AArch64ABIKind::Win64 ||
212 bool IsWinVariadic = IsWin64 && IsVariadicFn;
213 // In variadic functions on Windows, all composite types are treated alike,
214 // no special handling of HFAs/HVAs.
215 if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) {
216 NSRN = std::min(NSRN + Members, uint64_t(8));
217 uint64_t BaseAllocSizeInBits = Base->getTypeAllocSize().getFixedValue() * 8;
218 const Type *CoerceTy =
219 TB.getArrayType(Base, Members, Members * BaseAllocSizeInBits);
220 if (Opts.Kind != AArch64ABIKind::AAPCS)
221 return ArgInfo::getDirect(CoerceTy);
222
223 // For HFAs/HVAs, cap the argument alignment to 16, otherwise
224 // set it to 8 according to the AAPCS64 document.
225 unsigned TyAlign = Ty->getUnadjustedAlignment().value();
226 TyAlign = (TyAlign >= 16) ? 16 : 8;
227 return ArgInfo::getDirect(CoerceTy, /*Offset=*/0, llvm::Align(TyAlign));
228 }
229
230 reportNYI("Aggregate argument type handling");
231 return ArgInfo::getIgnore();
232}
233
234bool AArch64TargetInfo::passAsAggregateType(const Type *Ty) const {
235 if (Opts.Kind == AArch64ABIKind::AAPCS && Ty->isSVESizelessType()) {
236 // svcount_t and the single-vector types occupy a register of their own,
237 // so only the data and predicate tuples are passed as aggregates.
238 const auto *TupleTy = dyn_cast<TupleType>(Ty);
239 assert((!TupleTy || TupleTy->getNumVectors() > 1) &&
240 "unexpected single vector tuple");
241 return TupleTy && !TupleTy->getVectorType()->isSVECount();
242 }
243 return isAggregateTypeForABI(Ty);
244}
245
246/// Returns the scalable vector type that \p VT, a fixed-length SVE vector,
247/// is passed as. A scalable SVE vector holds 128 bits per granule, so the
248/// scalable element count is 128 divided by the element size, regardless of
249/// how many elements the fixed-length type has.
250const VectorType *AArch64TargetInfo::convertFixedToScalableVectorType(
251 const VectorType *VT) const {
252 // TODO: Verify that this correctly handles MFloat8 when we decide on a
253 // mapping for that type.
254
255 if (VT->isFixedLengthSVEPredicate())
256 return TB.getScalablePredicateOrCountVectorType(Align(2),
258
259 assert(VT->isFixedLengthSVEData() && "expected a fixed-length SVE vector!");
260
261 const Type *EltTy = VT->getElementType();
262 uint64_t EltBits = EltTy->getSizeInBits().getFixedValue();
263 assert(EltBits >= 8 && EltBits <= 64 && isPowerOf2_64(EltBits) &&
264 "unexpected element type for SVE data vector!");
265
266 return TB.getVectorType(EltTy, ElementCount::getScalable(128 / EltBits),
267 llvm::Align(16), VectorKind::SVEData);
268}
269
270ArgInfo AArch64TargetInfo::coerceIllegalVector(const VectorType *VT,
271 unsigned &NSRN,
272 unsigned &NPRN) const {
273 if (VT->isFixedLengthSVEPredicate()) {
274 // Fixed-length predicates are described with 8-bit elements, but they are
275 // passed in a predicate register as a scalable vector of 16 one-bit
276 // elements.
277 assert(isa<IntegerType>(VT->getElementType()) &&
278 VT->getElementType()->getSizeInBits().getFixedValue() == 8 &&
279 "unexpected element type for SVE predicate!");
280 NPRN = std::min(NPRN + 1, 4u);
281 return ArgInfo::getDirect(TB.getScalablePredicateOrCountVectorType(
283 }
284
285 if (VT->isFixedLengthSVEData()) {
286 NSRN = std::min(NSRN + 1, 8u);
287 return ArgInfo::getDirect(convertFixedToScalableVectorType(VT));
288 }
289
290 uint64_t Size = VT->getABISizeInBits();
291 // Android promotes <2 x i8> to i16, not i32
292 if (Opts.IsAndroidOrOHOS && (Size <= 16)) {
293 auto *ResType = TB.getIntegerType(16, llvm::Align(2), /*Signed=*/false);
294 return ArgInfo::getDirect(ResType);
295 }
296 const Type *I32 = TB.getIntegerType(32, llvm::Align(4), /*Signed=*/false);
297 if (Size <= 32)
298 return ArgInfo::getDirect(I32);
299 if (Size == 64) {
300 NSRN = std::min(NSRN + 1, 8u);
301 return ArgInfo::getDirect(
302 TB.getVectorType(I32, ElementCount::getFixed(2), llvm::Align(8)));
303 }
304 if (Size == 128) {
305 NSRN = std::min(NSRN + 1, 8u);
306 return ArgInfo::getDirect(
307 TB.getVectorType(I32, ElementCount::getFixed(4), llvm::Align(16)));
308 }
309
310 return getNaturalAlignIndirect(VT, getAllocaAddrSpace(), /*ByVal=*/false);
311}
312
313bool AArch64TargetInfo::isIllegalVectorType(const Type *Ty) const {
314 if (const auto *VT = dyn_cast<VectorType>(Ty)) {
315 // Check whether VT is a fixed-length SVE vector. These types are
316 // represented as scalable vectors in function args/return and must be
317 // coerced from fixed vectors.
318 if (VT->isFixedLengthSVEData() || VT->isFixedLengthSVEPredicate())
319 return true;
320
321 // Scalable SVE types are legal.
322 if (VT->isScalable())
323 return false;
324
325 // Check whether VT is legal.
326 unsigned NumElements = VT->getNumElements().getFixedValue();
327 uint64_t Size = VT->getABISizeInBits();
328 // NumElements should be power of 2.
329 if (!isPowerOf2_32(NumElements))
330 return true;
331
332 // arm64_32 has to be compatible with the ARM logic here, which allows huge
333 // vectors for some reason.
334 if (Opts.IsILP32 && Opts.IsMachO)
335 return Size <= 32;
336
337 return Size != 64 && (Size != 128 || NumElements == 1);
338 }
339 return false;
340}
341
342bool AArch64TargetInfo::isHomogeneousAggregateBaseType(const Type *Ty) const {
343 // Soft-float ABI: no types are homogeneous aggregates.
344 if (isSoftFloat())
345 return false;
346
347 // Homogeneous aggregates for AAPCS64 must have base types of a floating
348 // point type or a short-vector type.
349 if (Ty->isFloat())
350 return true;
351
352 if (const auto *VT = dyn_cast<VectorType>(Ty)) {
353 if (VT->isScalable() || VT->isSVEData() || VT->isSVEPredicate())
354 return false;
355
356 uint64_t VecSize = VT->getABISizeInBits();
357 if (VecSize == 64 || VecSize == 128)
358 return true;
359 }
360 return false;
361}
362
363bool AArch64TargetInfo::isHomogeneousAggregateSmallEnough(
364 const Type * /*Base*/, uint64_t Members) const {
365 return Members <= 4;
366}
367
369 const {
370 // AAPCS64 applies homogeneity to the output of the data layout decision, so
371 // zero-length bitfields do not affect homogeneity.
372 return true;
373}
374
375bool AArch64TargetInfo::isPermittedToBeHomogeneousAggregate(
376 const RecordType *RT) const {
377 if (Opts.IsMicrosoftCXXABI && RT->isCXXRecord()) {
378 // This won't always return false, but we don't have enough information to
379 // perform the full check correctly yet.
380 reportNYI("MicrosoftCXXABI homogeneous record classification");
381 return false;
382 }
383
384 return true;
385}
386
387} // namespace abi
388} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
#define I(x, y, z)
Definition MD5.cpp:57
FunctionLoweringInfo::StatepointRelocationRecord RecordType
Target-specific ABI information and factory functions.
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition TypeSize.h:308
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:305
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Definition WithColor.cpp:86
AArch64TargetInfo(TypeBuilder &TB, const AArch64ABIOptions &Opts)
Definition AArch64.cpp:25
void computeInfo(FunctionInfo &FI) const override
Populate FI with the target's ABI-lowering decisions for each argument and return value.
Definition AArch64.cpp:32
const ABICompatInfo & getABICompatInfo() const override
Return this target's ABI compatibility flags.
Definition AArch64.cpp:28
Helper class to encapsulate information about how a specific type should be passed to or returned fro...
static ArgInfo getIgnore()
static ArgInfo getExtend(const Type *T)
static ArgInfo getDirect(const Type *T=nullptr, unsigned Offset=0, MaybeAlign Align=std::nullopt, bool CanBeFlattened=true)
ArrayRef< ArgEntry > arguments() const
unsigned getNumRequiredArgs() const
CallingConv::ID getCallingConvention() const
const Type * getReturnType() const
virtual unsigned getAllocaAddrSpace() const
Address space in which indirect arguments are allocated (the target's alloca/stack space).
Definition TargetInfo.h:85
LLVM_ABI bool isHomogeneousAggregate(const Type *Ty, const Type *&Base, uint64_t &Members) const
Return true if Ty is an ELFv2-style homogeneous aggregate.
LLVM_ABI bool isPromotableInteger(const IntegerType *IT) const
virtual bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const
Return true if zero-length bitfields should be ignored when deciding whether an aggregate is homogene...
Definition TargetInfo.h:130
TargetInfo(TypeBuilder &Builder)
Definition TargetInfo.h:70
LLVM_ABI bool maybeCommonClassifyReturnType(FunctionInfo &FI) const
Apply rules for classifying return types that are common to all targets.
LLVM_ABI bool isAggregateTypeForABI(const Type *Ty) const
TypeBuilder & TB
Definition TargetInfo.h:67
LLVM_ABI const Type * useFirstFieldIfTransparentUnion(const Type *Ty) const
If Ty is a transparent union, return its first field type; otherwise return Ty unchanged.
LLVM_ABI ArgInfo getNaturalAlignIndirect(const Type *Ty, unsigned AddrSpace, bool ByVal=true) const
LLVM_ABI RecordArgABI getRecordArgABI(const RecordType *RT) const
TypeBuilder manages the lifecycle of ABI types using bump pointer allocation.
Definition Types.h:474
Represents the ABI-specific view of a type in LLVM.
Definition Types.h:48
This file defines the type system for the LLVMABI library, which mirrors ABI-relevant aspects of fron...
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
@ Win64
The C convention as implemented on Windows/x86-64 and AArch64.
static void reportNYI(StringRef Feature)
Definition AArch64.cpp:81
@ SVEPredicate
An AArch64 SVE predicate vector, such as svbool_t.
Definition Types.h:271
@ SVEData
An AArch64 SVE data vector, such as svint32_t.
Definition Types.h:264
@ RAA_DirectInMemory
Pass it on the stack using its defined layout.
Definition TargetInfo.h:34
LLVM_ABI std::unique_ptr< TargetInfo > createAArch64TargetInfo(TypeBuilder &TB, const AArch64ABIOptions &Opts)
Definition AArch64.cpp:77
CallingConvention
Definition Dwarf.h:851
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Helper struct shared between Function Specialization and SCCP Solver.
Definition SCCPSolver.h:42
Target / language flags that affect AArch64 ABI classification.
Definition TargetInfo.h:174
Flags controlling ABI compatibility behaviour that applies to every target.
Definition TargetInfo.h:43