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"
16#include <algorithm>
17#include <cstdint>
18
19namespace llvm {
20namespace abi {
21
23public:
25 : TargetInfo(TB), Opts(Opts) {}
26
27 const ABICompatInfo &getABICompatInfo() const override {
28 return Opts.CompatInfo;
29 }
30
31 void computeInfo(FunctionInfo &FI) const override {
33 FI.getReturnInfo() =
34 classifyReturnType(FI.getReturnType(), FI.isVariadic());
35
36 unsigned ArgNo = 0;
37 unsigned NSRN = 0, NPRN = 0;
38 for (auto &I : FI.arguments()) {
39 const bool IsNamedArg =
40 !FI.isVariadic() || ArgNo < FI.getNumRequiredArgs();
41 ++ArgNo;
42 I.Info = classifyArgumentType(I.ABIType, FI.isVariadic(), IsNamedArg,
43 FI.getCallingConvention(), NSRN, NPRN);
44 }
45 }
46
47private:
49
50 ArgInfo classifyReturnType(const Type *RetTy, bool IsVariadicFn) const;
51 ArgInfo classifyArgumentType(const Type *Ty, bool IsVariadicFn,
52 bool IsNamedArg, unsigned CallingConvention,
53 unsigned &NSRN, unsigned &NPRN) const;
54
55 bool isDarwinPCS() const { return Opts.Kind == AArch64ABIKind::DarwinPCS; }
56 bool isSoftFloat() const { return Opts.Kind == AArch64ABIKind::AAPCSSoft; }
57 bool passAsAggregateType(const Type *Ty) const;
58
59 bool isHomogeneousAggregateBaseType(const Type *Ty) const override;
60 bool isHomogeneousAggregateSmallEnough(const Type *Base,
61 uint64_t Members) const override;
63 bool isPermittedToBeHomogeneousAggregate(const RecordType *RT) const override;
64};
65
66std::unique_ptr<TargetInfo>
68 return std::make_unique<AArch64TargetInfo>(TB, Opts);
69}
70
71static void reportNYI(StringRef Feature) {
73 << Feature
74 << " is not yet implemented for AArch64 in the LLVM ABI library.\n";
75}
76
77ArgInfo AArch64TargetInfo::classifyReturnType(const Type *RetTy,
78 bool IsVariadicFn) const {
79 if (RetTy->isVoid())
80 return ArgInfo::getIgnore();
81
82 if (RetTy->isVector()) {
83 reportNYI("Vector return type handling");
84 return ArgInfo::getIgnore();
85 }
86
87 if (!passAsAggregateType(RetTy)) {
88 if (const auto *IntTy = dyn_cast<IntegerType>(RetTy)) {
89 if (IntTy->isBitInt())
90 if (RetTy->getSizeInBits().getFixedValue() > 128)
92
93 if (isPromotableInteger(IntTy) && isDarwinPCS())
94 return ArgInfo::getExtend(IntTy);
95 }
96
97 // Everything not handled above is returned directly.
98 return ArgInfo::getDirect();
99 }
100
101 uint64_t Size = RetTy->getFixedSizeInBitsOrZero();
102 if (!RetTy->isSVESizelessType() && (RetTy->isEmptyRecord() || Size == 0))
103 return ArgInfo::getIgnore();
104
105 const Type *Base = nullptr;
106 uint64_t Members = 0;
107 if (isHomogeneousAggregate(RetTy, Base, Members) &&
108 !(Opts.IsILP32 && IsVariadicFn)) {
109 // Homogeneous Floating-point Aggregates (HFAs) are returned directly.
110 return ArgInfo::getDirect();
111 }
112
113 reportNYI("Aggregate return type handling");
114 return ArgInfo::getIgnore();
115}
116
117ArgInfo AArch64TargetInfo::classifyArgumentType(
118 const Type *Ty, bool IsVariadicFn, bool IsNamedArg,
119 unsigned CallingConvention, unsigned &NSRN, unsigned &NPRN) const {
121
122 if (Ty->isVector()) {
123 reportNYI("Vector argument type handling");
124 return ArgInfo::getIgnore();
125 }
126
127 if (!passAsAggregateType(Ty)) {
128 if (const auto *IntTy = dyn_cast<IntegerType>(Ty)) {
129 if (IntTy->isBitInt())
130 if (Ty->getSizeInBits().getFixedValue() > 128)
132 /*ByVal=*/false);
133
134 if (isPromotableInteger(IntTy) && isDarwinPCS())
135 return ArgInfo::getExtend(IntTy);
136 }
137
138 // TODO: Legal vector types will update NSRN or NPRN.
139
140 if (Ty->isFloat())
141 NSRN = std::min(NSRN + 1, 8u);
142
143 // Everything not handled above is returned directly.
144 return ArgInfo::getDirect();
145 }
146
147 // Structures with either a non-trivial destructor or a non-trivial
148 // copy constructor are always indirect.
149 if (auto RecordRAA = getRecordArgABI(Ty)) {
151 /*ByVal=*/RecordRAA ==
153 }
154
155 // AAPCS64 does not say that empty C records are ignored as arguments,
156 // but other compilers do so in certain situations, and we copy that behavior.
157 uint64_t Size = Ty->getFixedSizeInBitsOrZero();
158 if (!Ty->isSVESizelessType() && (Ty->isEmptyRecord() || Size == 0)) {
159 // Darwin overrides the psABI here to ignore all empty records in all modes.
160 // The ABI explicitly says that an empty class shall be treated as if its
161 // type were an aggregate with a single member of type unsigned byte.
162 if (!Opts.IsCXX || isDarwinPCS())
163 return ArgInfo::getIgnore();
164
165 // In C++ mode, arguments which have sizeof() == 0 (which are non-standard
166 // C++) are ignored. This isn't defined by any standard, so we copy GCC's
167 // behaviour here.
168 if (Size == 0)
169 return ArgInfo::getIgnore();
170 }
171
172 // Homogeneous Floating-point Aggregates (HFAs) need to be expanded.
173 const Type *Base = nullptr;
174 uint64_t Members = 0;
175 bool IsWin64 = Opts.Kind == AArch64ABIKind::Win64 ||
177 bool IsWinVariadic = IsWin64 && IsVariadicFn;
178 // In variadic functions on Windows, all composite types are treated alike,
179 // no special handling of HFAs/HVAs.
180 if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) {
181 NSRN = std::min(NSRN + Members, uint64_t(8));
182 uint64_t BaseAllocSizeInBits = Base->getTypeAllocSize().getFixedValue() * 8;
183 const Type *CoerceTy =
184 TB.getArrayType(Base, Members, Members * BaseAllocSizeInBits);
185 if (Opts.Kind != AArch64ABIKind::AAPCS)
186 return ArgInfo::getDirect(CoerceTy);
187
188 // For HFAs/HVAs, cap the argument alignment to 16, otherwise
189 // set it to 8 according to the AAPCS64 document.
190 unsigned TyAlign = Ty->getUnadjustedAlignment().value();
191 TyAlign = (TyAlign >= 16) ? 16 : 8;
192 return ArgInfo::getDirect(CoerceTy, /*Offset=*/0, llvm::Align(TyAlign));
193 }
194
195 reportNYI("Aggregate argument type handling");
196 return ArgInfo::getIgnore();
197}
198
199bool AArch64TargetInfo::passAsAggregateType(const Type *Ty) const {
200 // TODO: Handle SVE types. For now, they don't get through the type mapper.
201 return isAggregateTypeForABI(Ty);
202}
203
204bool AArch64TargetInfo::isHomogeneousAggregateBaseType(const Type *Ty) const {
205 // Soft-float ABI: no types are homogeneous aggregates.
206 if (isSoftFloat())
207 return false;
208
209 // Homogeneous aggregates for AAPCS64 must have base types of a floating
210 // point type or a short-vector type.
211 if (Ty->isFloat())
212 return true;
213
214 if (const auto *VT = dyn_cast<VectorType>(Ty)) {
215 if (VT->isScalable() || VT->isSVEData() || VT->isSVEPredicate())
216 return false;
217
218 // Clang's getTypeSize for non-power-of-2 vectors rounds the width up to
219 // the next power-of-2 alignment (e.g. 3 x float is 96 bits of payload but
220 // 128 bits of ABI size), so those vectors are short-vector HVA bases.
222 bit_ceil(std::max<uint64_t>(8, VT->getSizeInBits().getFixedValue()));
223 if (VecSize == 64 || VecSize == 128)
224 return true;
225 }
226 return false;
227}
228
229bool AArch64TargetInfo::isHomogeneousAggregateSmallEnough(
230 const Type * /*Base*/, uint64_t Members) const {
231 return Members <= 4;
232}
233
235 const {
236 // AAPCS64 applies homogeneity to the output of the data layout decision, so
237 // zero-length bitfields do not affect homogeneity.
238 return true;
239}
240
241bool AArch64TargetInfo::isPermittedToBeHomogeneousAggregate(
242 const RecordType *RT) const {
243 if (Opts.IsMicrosoftCXXABI && RT->isCXXRecord()) {
244 // This won't always return false, but we don't have enough information to
245 // perform the full check correctly yet.
246 reportNYI("MicrosoftCXXABI homogeneous record classification");
247 return false;
248 }
249
250 return true;
251}
252
253} // namespace abi
254} // namespace llvm
unsigned uint64_t
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
#define I(x, y, z)
Definition MD5.cpp:57
FunctionLoweringInfo::StatepointRelocationRecord RecordType
Target-specific ABI information and factory functions.
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:24
void computeInfo(FunctionInfo &FI) const override
Populate FI with the target's ABI-lowering decisions for each argument and return value.
Definition AArch64.cpp:31
const ABICompatInfo & getABICompatInfo() const override
Return this target's ABI compatibility flags.
Definition AArch64.cpp:27
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:443
Represents the ABI-specific view of a type in LLVM.
Definition Types.h:46
This file defines the type system for the LLVMABI library, which mirrors ABI-relevant aspects of fron...
@ Win64
The C convention as implemented on Windows/x86-64 and AArch64.
static void reportNYI(StringRef Feature)
Definition AArch64.cpp:71
@ 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:67
CallingConvention
Definition Dwarf.h:844
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
T bit_ceil(T Value)
Returns the smallest integral power of two no smaller than Value if Value is nonzero.
Definition bit.h:362
Helper struct shared between Function Specialization and SCCP Solver.
Definition SCCPSolver.h:42
Target / language flags that affect AArch64 ABI classification.
Definition TargetInfo.h:170
Flags controlling ABI compatibility behaviour that applies to every target.
Definition TargetInfo.h:43