10#include "TargetInfo.h"
21class ARMABIInfo :
public ABIInfo {
23 bool IsFloatABISoftFP;
33 switch (
getTarget().getTriple().getEnvironment()) {
34 case llvm::Triple::Android:
35 case llvm::Triple::EABI:
36 case llvm::Triple::EABIHF:
37 case llvm::Triple::GNUEABI:
38 case llvm::Triple::GNUEABIT64:
39 case llvm::Triple::GNUEABIHF:
40 case llvm::Triple::GNUEABIHFT64:
41 case llvm::Triple::MuslEABI:
42 case llvm::Triple::MuslEABIHF:
49 bool isEABIHF()
const {
50 switch (
getTarget().getTriple().getEnvironment()) {
51 case llvm::Triple::EABIHF:
52 case llvm::Triple::GNUEABIHF:
53 case llvm::Triple::GNUEABIHFT64:
54 case llvm::Triple::MuslEABIHF:
69 unsigned functionCallConv)
const;
71 unsigned functionCallConv)
const;
73 uint64_t Members)
const;
74 bool shouldIgnoreEmptyArg(
QualType Ty)
const;
76 bool isIllegalVectorType(
QualType Ty)
const;
77 bool containsAnyFP16Vectors(
QualType Ty)
const;
81 uint64_t Members)
const override;
84 bool isEffectivelyAAPCS_VFP(
unsigned callConvention,
bool acceptHalf)
const;
91 llvm::CallingConv::ID getLLVMDefaultCC()
const;
92 llvm::CallingConv::ID getABIDefaultCC()
const;
102 unsigned NumElts)
const override;
109 SwiftInfo = std::make_unique<ARMSwiftABIInfo>(CGT);
117 return "mov\tr7, r7\t\t// marker for objc_retainAutoreleaseReturnValue";
121 llvm::Value *
Address)
const override {
122 llvm::Value *Four8 = llvm::ConstantInt::get(CGF.
Int8Ty, 4);
130 if (getABIInfo<ARMABIInfo>().isEABI())
137 auto *
Fn = dyn_cast<llvm::Function>(GV);
140 const auto *FD = dyn_cast_or_null<FunctionDecl>(
D);
142 if (FD && FD->hasAttr<TargetAttr>()) {
143 const auto *TA = FD->getAttr<TargetAttr>();
146 if (!
Attr.BranchProtection.empty()) {
155 diag::warn_target_unsupported_branch_protection_attribute)
159 }
else if (CGM.
getLangOpts().BranchTargetEnforcement ||
167 diag::warn_target_unsupported_branch_protection_attribute)
176 if (!FD || !FD->hasAttr<ARMInterruptAttr>())
179 const ARMInterruptAttr *
Attr = FD->getAttr<ARMInterruptAttr>();
181 switch (
Attr->getInterrupt()) {
182 case ARMInterruptAttr::Generic:
Kind =
"";
break;
183 case ARMInterruptAttr::IRQ:
Kind =
"IRQ";
break;
184 case ARMInterruptAttr::FIQ:
Kind =
"FIQ";
break;
185 case ARMInterruptAttr::SWI:
Kind =
"SWI";
break;
186 case ARMInterruptAttr::ABORT:
Kind =
"ABORT";
break;
187 case ARMInterruptAttr::UNDEF:
Kind =
"UNDEF";
break;
190 Fn->addFnAttr(
"interrupt", Kind);
194 const ARMSaveFPAttr *SaveFPAttr = FD->getAttr<ARMSaveFPAttr>();
196 Fn->addFnAttr(
"save-fp");
198 ARMABIKind ABI = getABIInfo<ARMABIInfo>().getABIKind();
199 if (ABI == ARMABIKind::APCS)
205 llvm::AttrBuilder B(
Fn->getContext());
206 B.addStackAlignmentAttr(8);
211class WindowsARMTargetCodeGenInfo :
public ARMTargetCodeGenInfo {
214 : ARMTargetCodeGenInfo(CGT, K) {}
216 void setTargetAttributes(
const Decl *
D, llvm::GlobalValue *GV,
219 void getDependentLibraryOption(llvm::StringRef Lib,
221 Opt =
"/DEFAULTLIB:" + qualifyWindowsLibrary(Lib);
224 void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef
Value,
226 Opt =
"/FAILIFMISMATCH:\"" + Name.str() +
"=" +
Value.str() +
"\"";
230void WindowsARMTargetCodeGenInfo::setTargetAttributes(
232 ARMTargetCodeGenInfo::setTargetAttributes(
D, GV, CGM);
233 if (GV->isDeclaration())
235 addStackProbeTargetAttributes(
D, GV, CGM);
253 llvm::CallingConv::ID cc = getRuntimeCC();
254 if (cc != llvm::CallingConv::C)
259llvm::CallingConv::ID ARMABIInfo::getLLVMDefaultCC()
const {
261 if (isEABIHF() || getTarget().getTriple().isWatchABI())
262 return llvm::CallingConv::ARM_AAPCS_VFP;
264 return llvm::CallingConv::ARM_AAPCS;
266 return llvm::CallingConv::ARM_APCS;
271llvm::CallingConv::ID ARMABIInfo::getABIDefaultCC()
const {
272 switch (getABIKind()) {
273 case ARMABIKind::APCS:
274 return llvm::CallingConv::ARM_APCS;
275 case ARMABIKind::AAPCS:
276 return llvm::CallingConv::ARM_AAPCS;
277 case ARMABIKind::AAPCS_VFP:
278 return llvm::CallingConv::ARM_AAPCS_VFP;
279 case ARMABIKind::AAPCS16_VFP:
280 return llvm::CallingConv::ARM_AAPCS_VFP;
282 llvm_unreachable(
"bad ABI kind");
285void ARMABIInfo::setCCs() {
286 assert(getRuntimeCC() == llvm::CallingConv::C);
290 llvm::CallingConv::ID abiCC = getABIDefaultCC();
291 if (abiCC != getLLVMDefaultCC())
298 llvm::Type *ResType =
299 llvm::Type::getInt32Ty(getVMContext());
302 if (Size == 64 || Size == 128) {
303 auto *ResType = llvm::FixedVectorType::get(
304 llvm::Type::getInt32Ty(getVMContext()), Size / 32);
307 return getNaturalAlignIndirect(
308 Ty, getDataLayout().getAllocaAddrSpace(),
314 uint64_t Members)
const {
315 assert(
Base &&
"Base class should be set for homogeneous aggregate");
319 if (!getTarget().hasFastHalfType() && containsAnyFP16Vectors(Ty)) {
321 auto *NewVecTy = llvm::FixedVectorType::get(
322 llvm::Type::getInt32Ty(getVMContext()), Size / 32);
323 llvm::Type *Ty = llvm::ArrayType::get(NewVecTy, Members);
328 if (getABIKind() == ARMABIKind::AAPCS ||
329 getABIKind() == ARMABIKind::AAPCS_VFP) {
332 Align = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity();
333 unsigned BaseAlign = getContext().getTypeAlignInChars(
Base).getQuantity();
334 Align = (Align > BaseAlign && Align >= 8) ? 8 : 0;
339bool ARMABIInfo::shouldIgnoreEmptyArg(
QualType Ty)
const {
341 assert((
isEmptyRecord(getContext(), Ty,
true) || Size == 0) &&
345 if (!getContext().getLangOpts().
CPlusPlus ||
346 getABIKind() == ARMABIKind::AAPCS16_VFP)
356 if (getContext().getLangOpts().getClangABICompat() <=
357 LangOptions::ClangABI::Ver19)
365 unsigned functionCallConv)
const {
375 !isVariadic && isEffectivelyAAPCS_VFP(functionCallConv,
false);
380 if (isIllegalVectorType(Ty))
381 return coerceIllegalVector(Ty);
386 Ty = ED->getIntegerType();
390 if (EIT->getNumBits() > 64)
391 return getNaturalAlignIndirect(
392 Ty, getDataLayout().getAllocaAddrSpace(),
395 return (isPromotableIntegerTypeForABI(Ty)
401 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
408 getContext().getTypeSize(Ty) == 0) {
409 if (shouldIgnoreEmptyArg(Ty))
420 if (isHomogeneousAggregate(Ty,
Base, Members))
421 return classifyHomogeneousAggregate(Ty,
Base, Members);
422 }
else if (getABIKind() == ARMABIKind::AAPCS16_VFP) {
428 if (isHomogeneousAggregate(Ty,
Base, Members)) {
429 assert(
Base && Members <= 4 &&
"unexpected homogeneous aggregate");
436 if (getABIKind() == ARMABIKind::AAPCS16_VFP &&
443 getDataLayout().getAllocaAddrSpace(),
false);
452 if (getABIKind() == ARMABIKind::AAPCS_VFP ||
453 getABIKind() == ARMABIKind::AAPCS) {
454 TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity();
455 ABIAlign = std::clamp(TyAlign, (uint64_t)4, (uint64_t)8);
457 TyAlign = getContext().getTypeAlignInChars(Ty).getQuantity();
460 assert(getABIKind() != ARMABIKind::AAPCS16_VFP &&
"unexpected byval");
463 getDataLayout().getAllocaAddrSpace(),
464 true, TyAlign > ABIAlign);
473 ElemTy = llvm::Type::getInt32Ty(getVMContext());
474 SizeRegs = (getContext().getTypeSize(Ty) + 31) / 32;
476 ElemTy = llvm::Type::getInt64Ty(getVMContext());
477 SizeRegs = (getContext().getTypeSize(Ty) + 63) / 64;
484 llvm::LLVMContext &VMContext) {
516 if (!RT)
return false;
527 bool HadField =
false;
530 i != e; ++i, ++idx) {
569 unsigned functionCallConv)
const {
573 !isVariadic && isEffectivelyAAPCS_VFP(functionCallConv,
true);
580 if (getContext().getTypeSize(RetTy) > 128)
581 return getNaturalAlignIndirect(RetTy,
582 getDataLayout().getAllocaAddrSpace());
585 if ((!getTarget().hasFastHalfType() &&
586 (VT->getElementType()->isFloat16Type() ||
587 VT->getElementType()->isHalfType())) ||
589 VT->getElementType()->isBFloat16Type()))
590 return coerceIllegalVector(RetTy);
596 RetTy = ED->getIntegerType();
599 if (EIT->getNumBits() > 64)
600 return getNaturalAlignIndirect(
601 RetTy, getDataLayout().getAllocaAddrSpace(),
609 if (getABIKind() == ARMABIKind::APCS) {
619 getVMContext(), getContext().getTypeSize(RetTy)));
633 return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace());
639 getContext().getTypeSize(RetTy) == 0)
646 if (isHomogeneousAggregate(RetTy,
Base, Members))
647 return classifyHomogeneousAggregate(RetTy,
Base, Members);
654 if (getDataLayout().isBigEndian())
664 }
else if (Size <= 128 && getABIKind() == ARMABIKind::AAPCS16_VFP) {
665 llvm::Type *Int32Ty = llvm::Type::getInt32Ty(getVMContext());
666 llvm::Type *CoerceTy =
667 llvm::ArrayType::get(Int32Ty, llvm::alignTo(Size, 32) / 32);
671 return getNaturalAlignIndirect(RetTy, getDataLayout().getAllocaAddrSpace());
675bool ARMABIInfo::isIllegalVectorType(
QualType Ty)
const {
683 if ((!getTarget().hasFastHalfType() &&
684 (VT->getElementType()->isFloat16Type() ||
685 VT->getElementType()->isHalfType())) ||
687 VT->getElementType()->isBFloat16Type()))
695 unsigned NumElements = VT->getNumElements();
697 if (!llvm::isPowerOf2_32(NumElements) && NumElements != 3)
701 unsigned NumElements = VT->getNumElements();
704 if (!llvm::isPowerOf2_32(NumElements))
714bool ARMABIInfo::containsAnyFP16Vectors(
QualType Ty)
const {
716 uint64_t NElements = AT->getZExtSize();
719 return containsAnyFP16Vectors(AT->getElementType());
723 if (
const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD))
725 return containsAnyFP16Vectors(B.getType());
729 if (llvm::any_of(RD->fields(), [
this](
FieldDecl *FD) {
730 return FD && containsAnyFP16Vectors(FD->getType());
737 return (VT->getElementType()->isFloat16Type() ||
738 VT->getElementType()->isBFloat16Type() ||
739 VT->getElementType()->isHalfType());
744bool ARMSwiftABIInfo::isLegalVectorType(
CharUnits VectorSize, llvm::Type *EltTy,
745 unsigned NumElts)
const {
746 if (!llvm::isPowerOf2_32(NumElts))
748 unsigned size = CGT.
getDataLayout().getTypeStoreSizeInBits(EltTy);
757bool ARMABIInfo::isHomogeneousAggregateBaseType(
QualType Ty)
const {
761 if (BT->getKind() == BuiltinType::Float ||
762 BT->getKind() == BuiltinType::Double ||
763 BT->getKind() == BuiltinType::LongDouble)
766 unsigned VecSize = getContext().getTypeSize(VT);
767 if (VecSize == 64 || VecSize == 128)
773bool ARMABIInfo::isHomogeneousAggregateSmallEnough(
const Type *
Base,
774 uint64_t Members)
const {
778bool ARMABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate()
const {
787bool ARMABIInfo::isEffectivelyAAPCS_VFP(
unsigned callConvention,
788 bool acceptHalf)
const {
790 if (callConvention != llvm::CallingConv::C)
791 return (callConvention == llvm::CallingConv::ARM_AAPCS_VFP);
793 return (getABIKind() == ARMABIKind::AAPCS_VFP) ||
794 (acceptHalf && (getABIKind() == ARMABIKind::AAPCS16_VFP));
804 if ((IsEmpty || Size == 0) && shouldIgnoreEmptyArg(Ty))
807 CharUnits TySize = getContext().getTypeSizeInChars(Ty);
808 CharUnits TyAlignForABI = getContext().getTypeUnadjustedAlignInChars(Ty);
811 bool IsIndirect =
false;
820 getABIKind() == ARMABIKind::AAPCS16_VFP &&
821 !isHomogeneousAggregate(Ty,
Base, Members)) {
828 }
else if (getABIKind() == ARMABIKind::AAPCS_VFP ||
829 getABIKind() == ARMABIKind::AAPCS) {
832 }
else if (getABIKind() == ARMABIKind::AAPCS16_VFP) {
840 TypeInfoChars TyInfo(TySize, TyAlignForABI, AlignRequirementKind::None);
845std::unique_ptr<TargetCodeGenInfo>
847 return std::make_unique<ARMTargetCodeGenInfo>(CGM.
getTypes(), Kind);
850std::unique_ptr<TargetCodeGenInfo>
852 return std::make_unique<WindowsARMTargetCodeGenInfo>(CGM.
getTypes(), K);
static bool isIntegerLikeType(QualType Ty, ASTContext &Context, llvm::LLVMContext &VMContext)
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const
Get or compute information about the layout of the specified record (struct/union/class) D,...
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...
uint64_t getFieldOffset(unsigned FieldNo) const
getFieldOffset - Get the offset of the given field index, in bits.
Attr - This represents one attribute.
A fixed int type of a specified bitwidth.
This class is used for builtin types like 'int'.
Represents a base class of a C++ class.
Represents a C++ struct/union/class.
CharUnits - This is an opaque type for sizes expressed in character units.
QuantityType getQuantity() const
getQuantity - Get the raw integer representation of this quantity.
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
std::string FloatABI
The ABI to use for passing floating point arguments.
ABIArgInfo - Helper class to encapsulate information about how a specific C type should be passed to ...
static ABIArgInfo getIgnore()
static ABIArgInfo getDirect(llvm::Type *T=nullptr, unsigned Offset=0, llvm::Type *Padding=nullptr, bool CanBeFlattened=true, unsigned Align=0)
static ABIArgInfo getIndirect(CharUnits Alignment, unsigned AddrSpace, bool ByVal=true, bool Realign=false, llvm::Type *Padding=nullptr)
static ABIArgInfo getExtend(QualType Ty, llvm::Type *T=nullptr)
ABIInfo - Target specific hooks for defining how a type should be passed or returned from functions.
virtual bool allowBFloatArgsAndRet() const
virtual bool isHomogeneousAggregateBaseType(QualType Ty) const
virtual bool isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const
const TargetInfo & getTarget() const
virtual RValue EmitVAArg(CodeGen::CodeGenFunction &CGF, CodeGen::Address VAListAddr, QualType Ty, AggValueSlot Slot) const =0
EmitVAArg - Emit the target dependent code to load a value of.
virtual bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const
virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const =0
Like RawAddress, an abstract representation of an aligned address, but the pointer contained in this ...
RecordArgABI
Specify how one should pass an argument of a record type.
@ RAA_DirectInMemory
Pass it on the stack using its defined layout.
CGFunctionInfo - Class to encapsulate the information about a function definition.
ABIArgInfo & getReturnInfo()
unsigned getCallingConvention() const
getCallingConvention - Return the user specified calling convention, which has been translated into a...
CanQualType getReturnType() const
MutableArrayRef< ArgInfo > arguments()
void setEffectiveCallingConvention(unsigned Value)
CodeGenFunction - This class organizes the per-function state that is used while generating LLVM code...
This class organizes the cross-function state that is used while generating LLVM code.
DiagnosticsEngine & getDiags() const
const LangOptions & getLangOpts() const
CodeGenTypes & getTypes()
const TargetInfo & getTarget() const
This class organizes the cross-module state that is used while lowering AST types to LLVM types.
llvm::Type * ConvertType(QualType T)
ConvertType - Convert type T into a llvm::Type.
const CodeGenOptions & getCodeGenOpts() const
const llvm::DataLayout & getDataLayout() const
RValue - This trivial value class is used to represent the result of an expression that is evaluated.
Target specific hooks for defining how a type should be passed or returned from functions with one of...
virtual bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy, unsigned NumElts) const
Returns true if the given vector type is legal from Swift's calling convention perspective.
TargetCodeGenInfo - This class organizes various target-specific codegeneration issues,...
virtual unsigned getSizeOfUnwindException() const
Determines the size of struct _Unwind_Exception on this platform, in 8-bit units.
virtual StringRef getARCRetainAutoreleasedReturnValueMarker() const
Retrieve the address of a function to call immediately before calling objc_retainAutoreleasedReturnVa...
static void setBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F)
virtual bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const
Initializes the given DWARF EH register-size table, a char*.
virtual void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const
setTargetAttributes - Provides a convenient hook to handle extra target-specific attributes for the g...
virtual int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const
Determines the DWARF register number for the stack pointer, for exception-handling purposes.
Complex values, per C99 6.2.5p11.
Represents the canonical version of C arrays with a specified constant size.
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
Decl - This represents one declaration (or definition), e.g.
SourceLocation getLocation() const
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
Represents a member of a struct/union/class.
bool isBitField() const
Determines whether this field is a bitfield.
bool hasSignReturnAddress() const
Check if return address signing is enabled.
A (possibly-)qualified type.
Represents a struct/union/class.
bool hasFlexibleArrayMember() const
field_iterator field_end() const
RecordDecl * getDefinitionOrSelf() const
field_iterator field_begin() const
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getOriginalDecl() const
TargetOptions & getTargetOpts() const
Retrieve the target options.
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
virtual bool isBranchProtectionSupportedArch(StringRef Arch) const
Determine if the Architecture in this TargetInfo supports branch protection.
virtual bool validateBranchProtection(StringRef Spec, StringRef Arch, BranchProtectionInfo &BPI, const LangOptions &LO, StringRef &Err) const
Determine if this TargetInfo supports the given branch protection specification.
virtual ParsedTargetAttr parseTargetAttr(StringRef Str) const
virtual bool hasBFloat16Type() const
Determine whether the _BFloat16 type is supported on this target.
std::string CPU
If given, the name of the target CPU to generate code for.
The base class of the type hierarchy.
RecordDecl * getAsRecordDecl() const
Retrieves the RecordDecl this type refers to.
bool isPointerType() const
bool isAnyComplexType() const
EnumDecl * getAsEnumDecl() const
Retrieves the EnumDecl this type refers to.
bool isVectorType() const
bool isRealFloatingType() const
Floating point categories.
const T * getAsCanonical() const
If this type is canonically the specified type, return its canonical type cast to that specified type...
const T * getAs() const
Member-template getAs<specific type>'.
Represents a GCC generic vector type.
ABIArgInfo classifyArgumentType(CodeGenModule &CGM, CanQualType type)
Classify the rules for how to pass a particular type.
std::unique_ptr< TargetCodeGenInfo > createARMTargetCodeGenInfo(CodeGenModule &CGM, ARMABIKind Kind)
CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI)
bool classifyReturnType(const CGCXXABI &CXXABI, CGFunctionInfo &FI, const ABIInfo &Info)
RValue emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType ValueTy, bool IsIndirect, TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign, bool AllowHigherAlign, AggValueSlot Slot, bool ForceRightAdjust=false)
Emit va_arg for a platform using the common void* representation, where arguments are simply emitted ...
bool isAggregateTypeForABI(QualType T)
std::unique_ptr< TargetCodeGenInfo > createWindowsARMTargetCodeGenInfo(CodeGenModule &CGM, ARMABIKind K)
void AssignToArrayRange(CodeGen::CGBuilderTy &Builder, llvm::Value *Array, llvm::Value *Value, unsigned FirstIndex, unsigned LastIndex)
QualType useFirstFieldIfTransparentUnion(QualType Ty)
Pass transparent unions as if they were the type of the first element.
bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays, bool AsIfNoUniqueAddr=false)
isEmptyRecord - Return true iff a structure contains only empty fields.
The JSON file list parser is used to communicate input to InstallAPI.
llvm::IntegerType * Int8Ty
i8, i16, i32, and i64
Contains information gathered from parsing the contents of TargetAttr.