106c3fb27SDimitry Andric //===- AArch64.cpp --------------------------------------------------------===// 206c3fb27SDimitry Andric // 306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606c3fb27SDimitry Andric // 706c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 806c3fb27SDimitry Andric 906c3fb27SDimitry Andric #include "ABIInfoImpl.h" 1006c3fb27SDimitry Andric #include "TargetInfo.h" 110fca6ea1SDimitry Andric #include "clang/AST/Decl.h" 120fca6ea1SDimitry Andric #include "clang/Basic/DiagnosticFrontend.h" 130fca6ea1SDimitry Andric #include "llvm/TargetParser/AArch64TargetParser.h" 1406c3fb27SDimitry Andric 1506c3fb27SDimitry Andric using namespace clang; 1606c3fb27SDimitry Andric using namespace clang::CodeGen; 1706c3fb27SDimitry Andric 1806c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 1906c3fb27SDimitry Andric // AArch64 ABI Implementation 2006c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 2106c3fb27SDimitry Andric 2206c3fb27SDimitry Andric namespace { 2306c3fb27SDimitry Andric 2406c3fb27SDimitry Andric class AArch64ABIInfo : public ABIInfo { 2506c3fb27SDimitry Andric AArch64ABIKind Kind; 2606c3fb27SDimitry Andric 2706c3fb27SDimitry Andric public: 2806c3fb27SDimitry Andric AArch64ABIInfo(CodeGenTypes &CGT, AArch64ABIKind Kind) 2906c3fb27SDimitry Andric : ABIInfo(CGT), Kind(Kind) {} 3006c3fb27SDimitry Andric 310fca6ea1SDimitry Andric bool isSoftFloat() const { return Kind == AArch64ABIKind::AAPCSSoft; } 320fca6ea1SDimitry Andric 3306c3fb27SDimitry Andric private: 3406c3fb27SDimitry Andric AArch64ABIKind getABIKind() const { return Kind; } 3506c3fb27SDimitry Andric bool isDarwinPCS() const { return Kind == AArch64ABIKind::DarwinPCS; } 3606c3fb27SDimitry Andric 3706c3fb27SDimitry Andric ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; 3806c3fb27SDimitry Andric ABIArgInfo classifyArgumentType(QualType RetTy, bool IsVariadic, 3906c3fb27SDimitry Andric unsigned CallingConvention) const; 4006c3fb27SDimitry Andric ABIArgInfo coerceIllegalVector(QualType Ty) const; 4106c3fb27SDimitry Andric bool isHomogeneousAggregateBaseType(QualType Ty) const override; 4206c3fb27SDimitry Andric bool isHomogeneousAggregateSmallEnough(const Type *Ty, 4306c3fb27SDimitry Andric uint64_t Members) const override; 4406c3fb27SDimitry Andric bool isZeroLengthBitfieldPermittedInHomogeneousAggregate() const override; 4506c3fb27SDimitry Andric 4606c3fb27SDimitry Andric bool isIllegalVectorType(QualType Ty) const; 4706c3fb27SDimitry Andric 4806c3fb27SDimitry Andric void computeInfo(CGFunctionInfo &FI) const override { 4906c3fb27SDimitry Andric if (!::classifyReturnType(getCXXABI(), FI, *this)) 5006c3fb27SDimitry Andric FI.getReturnInfo() = 5106c3fb27SDimitry Andric classifyReturnType(FI.getReturnType(), FI.isVariadic()); 5206c3fb27SDimitry Andric 5306c3fb27SDimitry Andric for (auto &it : FI.arguments()) 5406c3fb27SDimitry Andric it.info = classifyArgumentType(it.type, FI.isVariadic(), 5506c3fb27SDimitry Andric FI.getCallingConvention()); 5606c3fb27SDimitry Andric } 5706c3fb27SDimitry Andric 580fca6ea1SDimitry Andric RValue EmitDarwinVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF, 590fca6ea1SDimitry Andric AggValueSlot Slot) const; 6006c3fb27SDimitry Andric 610fca6ea1SDimitry Andric RValue EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF, 620fca6ea1SDimitry Andric AArch64ABIKind Kind, AggValueSlot Slot) const; 6306c3fb27SDimitry Andric 640fca6ea1SDimitry Andric RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 650fca6ea1SDimitry Andric AggValueSlot Slot) const override { 6606c3fb27SDimitry Andric llvm::Type *BaseTy = CGF.ConvertType(Ty); 6706c3fb27SDimitry Andric if (isa<llvm::ScalableVectorType>(BaseTy)) 6806c3fb27SDimitry Andric llvm::report_fatal_error("Passing SVE types to variadic functions is " 6906c3fb27SDimitry Andric "currently not supported"); 7006c3fb27SDimitry Andric 710fca6ea1SDimitry Andric return Kind == AArch64ABIKind::Win64 720fca6ea1SDimitry Andric ? EmitMSVAArg(CGF, VAListAddr, Ty, Slot) 730fca6ea1SDimitry Andric : isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF, Slot) 740fca6ea1SDimitry Andric : EmitAAPCSVAArg(VAListAddr, Ty, CGF, Kind, Slot); 7506c3fb27SDimitry Andric } 7606c3fb27SDimitry Andric 770fca6ea1SDimitry Andric RValue EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 780fca6ea1SDimitry Andric AggValueSlot Slot) const override; 7906c3fb27SDimitry Andric 8006c3fb27SDimitry Andric bool allowBFloatArgsAndRet() const override { 8106c3fb27SDimitry Andric return getTarget().hasBFloat16Type(); 8206c3fb27SDimitry Andric } 830fca6ea1SDimitry Andric 840fca6ea1SDimitry Andric using ABIInfo::appendAttributeMangling; 850fca6ea1SDimitry Andric void appendAttributeMangling(TargetClonesAttr *Attr, unsigned Index, 860fca6ea1SDimitry Andric raw_ostream &Out) const override; 870fca6ea1SDimitry Andric void appendAttributeMangling(StringRef AttrStr, 880fca6ea1SDimitry Andric raw_ostream &Out) const override; 8906c3fb27SDimitry Andric }; 9006c3fb27SDimitry Andric 9106c3fb27SDimitry Andric class AArch64SwiftABIInfo : public SwiftABIInfo { 9206c3fb27SDimitry Andric public: 9306c3fb27SDimitry Andric explicit AArch64SwiftABIInfo(CodeGenTypes &CGT) 9406c3fb27SDimitry Andric : SwiftABIInfo(CGT, /*SwiftErrorInRegister=*/true) {} 9506c3fb27SDimitry Andric 9606c3fb27SDimitry Andric bool isLegalVectorType(CharUnits VectorSize, llvm::Type *EltTy, 9706c3fb27SDimitry Andric unsigned NumElts) const override; 9806c3fb27SDimitry Andric }; 9906c3fb27SDimitry Andric 10006c3fb27SDimitry Andric class AArch64TargetCodeGenInfo : public TargetCodeGenInfo { 10106c3fb27SDimitry Andric public: 10206c3fb27SDimitry Andric AArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIKind Kind) 10306c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<AArch64ABIInfo>(CGT, Kind)) { 10406c3fb27SDimitry Andric SwiftInfo = std::make_unique<AArch64SwiftABIInfo>(CGT); 10506c3fb27SDimitry Andric } 10606c3fb27SDimitry Andric 10706c3fb27SDimitry Andric StringRef getARCRetainAutoreleasedReturnValueMarker() const override { 10806c3fb27SDimitry Andric return "mov\tfp, fp\t\t// marker for objc_retainAutoreleaseReturnValue"; 10906c3fb27SDimitry Andric } 11006c3fb27SDimitry Andric 11106c3fb27SDimitry Andric int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { 11206c3fb27SDimitry Andric return 31; 11306c3fb27SDimitry Andric } 11406c3fb27SDimitry Andric 11506c3fb27SDimitry Andric bool doesReturnSlotInterfereWithArgs() const override { return false; } 11606c3fb27SDimitry Andric 11706c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 11806c3fb27SDimitry Andric CodeGen::CodeGenModule &CGM) const override { 11906c3fb27SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); 12006c3fb27SDimitry Andric if (!FD) 12106c3fb27SDimitry Andric return; 12206c3fb27SDimitry Andric 1230fca6ea1SDimitry Andric TargetInfo::BranchProtectionInfo BPI(CGM.getLangOpts()); 12406c3fb27SDimitry Andric 1250fca6ea1SDimitry Andric if (const auto *TA = FD->getAttr<TargetAttr>()) { 12606c3fb27SDimitry Andric ParsedTargetAttr Attr = 12706c3fb27SDimitry Andric CGM.getTarget().parseTargetAttr(TA->getFeaturesStr()); 1280fca6ea1SDimitry Andric if (!Attr.BranchProtection.empty()) { 12906c3fb27SDimitry Andric StringRef Error; 13006c3fb27SDimitry Andric (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, 13106c3fb27SDimitry Andric Attr.CPU, BPI, Error); 13206c3fb27SDimitry Andric assert(Error.empty()); 13306c3fb27SDimitry Andric } 1340fca6ea1SDimitry Andric } 1350fca6ea1SDimitry Andric auto *Fn = cast<llvm::Function>(GV); 1360fca6ea1SDimitry Andric setBranchProtectionFnAttributes(BPI, *Fn); 13706c3fb27SDimitry Andric } 13806c3fb27SDimitry Andric 13906c3fb27SDimitry Andric bool isScalarizableAsmOperand(CodeGen::CodeGenFunction &CGF, 14006c3fb27SDimitry Andric llvm::Type *Ty) const override { 14106c3fb27SDimitry Andric if (CGF.getTarget().hasFeature("ls64")) { 14206c3fb27SDimitry Andric auto *ST = dyn_cast<llvm::StructType>(Ty); 14306c3fb27SDimitry Andric if (ST && ST->getNumElements() == 1) { 14406c3fb27SDimitry Andric auto *AT = dyn_cast<llvm::ArrayType>(ST->getElementType(0)); 14506c3fb27SDimitry Andric if (AT && AT->getNumElements() == 8 && 14606c3fb27SDimitry Andric AT->getElementType()->isIntegerTy(64)) 14706c3fb27SDimitry Andric return true; 14806c3fb27SDimitry Andric } 14906c3fb27SDimitry Andric } 15006c3fb27SDimitry Andric return TargetCodeGenInfo::isScalarizableAsmOperand(CGF, Ty); 15106c3fb27SDimitry Andric } 1520fca6ea1SDimitry Andric 1530fca6ea1SDimitry Andric void checkFunctionABI(CodeGenModule &CGM, 1540fca6ea1SDimitry Andric const FunctionDecl *Decl) const override; 1550fca6ea1SDimitry Andric 1560fca6ea1SDimitry Andric void checkFunctionCallABI(CodeGenModule &CGM, SourceLocation CallLoc, 1570fca6ea1SDimitry Andric const FunctionDecl *Caller, 1580fca6ea1SDimitry Andric const FunctionDecl *Callee, const CallArgList &Args, 1590fca6ea1SDimitry Andric QualType ReturnType) const override; 1600fca6ea1SDimitry Andric 1610fca6ea1SDimitry Andric private: 1620fca6ea1SDimitry Andric // Diagnose calls between functions with incompatible Streaming SVE 1630fca6ea1SDimitry Andric // attributes. 1640fca6ea1SDimitry Andric void checkFunctionCallABIStreaming(CodeGenModule &CGM, SourceLocation CallLoc, 1650fca6ea1SDimitry Andric const FunctionDecl *Caller, 1660fca6ea1SDimitry Andric const FunctionDecl *Callee) const; 1670fca6ea1SDimitry Andric // Diagnose calls which must pass arguments in floating-point registers when 1680fca6ea1SDimitry Andric // the selected target does not have floating-point registers. 1690fca6ea1SDimitry Andric void checkFunctionCallABISoftFloat(CodeGenModule &CGM, SourceLocation CallLoc, 1700fca6ea1SDimitry Andric const FunctionDecl *Caller, 1710fca6ea1SDimitry Andric const FunctionDecl *Callee, 1720fca6ea1SDimitry Andric const CallArgList &Args, 1730fca6ea1SDimitry Andric QualType ReturnType) const; 17406c3fb27SDimitry Andric }; 17506c3fb27SDimitry Andric 17606c3fb27SDimitry Andric class WindowsAArch64TargetCodeGenInfo : public AArch64TargetCodeGenInfo { 17706c3fb27SDimitry Andric public: 17806c3fb27SDimitry Andric WindowsAArch64TargetCodeGenInfo(CodeGenTypes &CGT, AArch64ABIKind K) 17906c3fb27SDimitry Andric : AArch64TargetCodeGenInfo(CGT, K) {} 18006c3fb27SDimitry Andric 18106c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 18206c3fb27SDimitry Andric CodeGen::CodeGenModule &CGM) const override; 18306c3fb27SDimitry Andric 18406c3fb27SDimitry Andric void getDependentLibraryOption(llvm::StringRef Lib, 18506c3fb27SDimitry Andric llvm::SmallString<24> &Opt) const override { 18606c3fb27SDimitry Andric Opt = "/DEFAULTLIB:" + qualifyWindowsLibrary(Lib); 18706c3fb27SDimitry Andric } 18806c3fb27SDimitry Andric 18906c3fb27SDimitry Andric void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, 19006c3fb27SDimitry Andric llvm::SmallString<32> &Opt) const override { 19106c3fb27SDimitry Andric Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; 19206c3fb27SDimitry Andric } 19306c3fb27SDimitry Andric }; 19406c3fb27SDimitry Andric 19506c3fb27SDimitry Andric void WindowsAArch64TargetCodeGenInfo::setTargetAttributes( 19606c3fb27SDimitry Andric const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { 19706c3fb27SDimitry Andric AArch64TargetCodeGenInfo::setTargetAttributes(D, GV, CGM); 19806c3fb27SDimitry Andric if (GV->isDeclaration()) 19906c3fb27SDimitry Andric return; 20006c3fb27SDimitry Andric addStackProbeTargetAttributes(D, GV, CGM); 20106c3fb27SDimitry Andric } 20206c3fb27SDimitry Andric } 20306c3fb27SDimitry Andric 20406c3fb27SDimitry Andric ABIArgInfo AArch64ABIInfo::coerceIllegalVector(QualType Ty) const { 20506c3fb27SDimitry Andric assert(Ty->isVectorType() && "expected vector type!"); 20606c3fb27SDimitry Andric 20706c3fb27SDimitry Andric const auto *VT = Ty->castAs<VectorType>(); 2085f757f3fSDimitry Andric if (VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) { 20906c3fb27SDimitry Andric assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); 21006c3fb27SDimitry Andric assert(VT->getElementType()->castAs<BuiltinType>()->getKind() == 21106c3fb27SDimitry Andric BuiltinType::UChar && 21206c3fb27SDimitry Andric "unexpected builtin type for SVE predicate!"); 21306c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ScalableVectorType::get( 21406c3fb27SDimitry Andric llvm::Type::getInt1Ty(getVMContext()), 16)); 21506c3fb27SDimitry Andric } 21606c3fb27SDimitry Andric 2175f757f3fSDimitry Andric if (VT->getVectorKind() == VectorKind::SveFixedLengthData) { 21806c3fb27SDimitry Andric assert(VT->getElementType()->isBuiltinType() && "expected builtin type!"); 21906c3fb27SDimitry Andric 22006c3fb27SDimitry Andric const auto *BT = VT->getElementType()->castAs<BuiltinType>(); 22106c3fb27SDimitry Andric llvm::ScalableVectorType *ResType = nullptr; 22206c3fb27SDimitry Andric switch (BT->getKind()) { 22306c3fb27SDimitry Andric default: 22406c3fb27SDimitry Andric llvm_unreachable("unexpected builtin type for SVE vector!"); 22506c3fb27SDimitry Andric case BuiltinType::SChar: 22606c3fb27SDimitry Andric case BuiltinType::UChar: 22706c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 22806c3fb27SDimitry Andric llvm::Type::getInt8Ty(getVMContext()), 16); 22906c3fb27SDimitry Andric break; 23006c3fb27SDimitry Andric case BuiltinType::Short: 23106c3fb27SDimitry Andric case BuiltinType::UShort: 23206c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 23306c3fb27SDimitry Andric llvm::Type::getInt16Ty(getVMContext()), 8); 23406c3fb27SDimitry Andric break; 23506c3fb27SDimitry Andric case BuiltinType::Int: 23606c3fb27SDimitry Andric case BuiltinType::UInt: 23706c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 23806c3fb27SDimitry Andric llvm::Type::getInt32Ty(getVMContext()), 4); 23906c3fb27SDimitry Andric break; 24006c3fb27SDimitry Andric case BuiltinType::Long: 24106c3fb27SDimitry Andric case BuiltinType::ULong: 24206c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 24306c3fb27SDimitry Andric llvm::Type::getInt64Ty(getVMContext()), 2); 24406c3fb27SDimitry Andric break; 24506c3fb27SDimitry Andric case BuiltinType::Half: 24606c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 24706c3fb27SDimitry Andric llvm::Type::getHalfTy(getVMContext()), 8); 24806c3fb27SDimitry Andric break; 24906c3fb27SDimitry Andric case BuiltinType::Float: 25006c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 25106c3fb27SDimitry Andric llvm::Type::getFloatTy(getVMContext()), 4); 25206c3fb27SDimitry Andric break; 25306c3fb27SDimitry Andric case BuiltinType::Double: 25406c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 25506c3fb27SDimitry Andric llvm::Type::getDoubleTy(getVMContext()), 2); 25606c3fb27SDimitry Andric break; 25706c3fb27SDimitry Andric case BuiltinType::BFloat16: 25806c3fb27SDimitry Andric ResType = llvm::ScalableVectorType::get( 25906c3fb27SDimitry Andric llvm::Type::getBFloatTy(getVMContext()), 8); 26006c3fb27SDimitry Andric break; 26106c3fb27SDimitry Andric } 26206c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 26306c3fb27SDimitry Andric } 26406c3fb27SDimitry Andric 26506c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 26606c3fb27SDimitry Andric // Android promotes <2 x i8> to i16, not i32 26706c3fb27SDimitry Andric if ((isAndroid() || isOHOSFamily()) && (Size <= 16)) { 26806c3fb27SDimitry Andric llvm::Type *ResType = llvm::Type::getInt16Ty(getVMContext()); 26906c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 27006c3fb27SDimitry Andric } 27106c3fb27SDimitry Andric if (Size <= 32) { 27206c3fb27SDimitry Andric llvm::Type *ResType = llvm::Type::getInt32Ty(getVMContext()); 27306c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 27406c3fb27SDimitry Andric } 27506c3fb27SDimitry Andric if (Size == 64) { 27606c3fb27SDimitry Andric auto *ResType = 27706c3fb27SDimitry Andric llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 2); 27806c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 27906c3fb27SDimitry Andric } 28006c3fb27SDimitry Andric if (Size == 128) { 28106c3fb27SDimitry Andric auto *ResType = 28206c3fb27SDimitry Andric llvm::FixedVectorType::get(llvm::Type::getInt32Ty(getVMContext()), 4); 28306c3fb27SDimitry Andric return ABIArgInfo::getDirect(ResType); 28406c3fb27SDimitry Andric } 28506c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 28606c3fb27SDimitry Andric } 28706c3fb27SDimitry Andric 28806c3fb27SDimitry Andric ABIArgInfo 28906c3fb27SDimitry Andric AArch64ABIInfo::classifyArgumentType(QualType Ty, bool IsVariadic, 29006c3fb27SDimitry Andric unsigned CallingConvention) const { 29106c3fb27SDimitry Andric Ty = useFirstFieldIfTransparentUnion(Ty); 29206c3fb27SDimitry Andric 29306c3fb27SDimitry Andric // Handle illegal vector types here. 29406c3fb27SDimitry Andric if (isIllegalVectorType(Ty)) 29506c3fb27SDimitry Andric return coerceIllegalVector(Ty); 29606c3fb27SDimitry Andric 29706c3fb27SDimitry Andric if (!isAggregateTypeForABI(Ty)) { 29806c3fb27SDimitry Andric // Treat an enum type as its underlying type. 29906c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 30006c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 30106c3fb27SDimitry Andric 30206c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) 30306c3fb27SDimitry Andric if (EIT->getNumBits() > 128) 3040fca6ea1SDimitry Andric return getNaturalAlignIndirect(Ty, false); 30506c3fb27SDimitry Andric 30606c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() 30706c3fb27SDimitry Andric ? ABIArgInfo::getExtend(Ty) 30806c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 30906c3fb27SDimitry Andric } 31006c3fb27SDimitry Andric 31106c3fb27SDimitry Andric // Structures with either a non-trivial destructor or a non-trivial 31206c3fb27SDimitry Andric // copy constructor are always indirect. 31306c3fb27SDimitry Andric if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { 31406c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == 31506c3fb27SDimitry Andric CGCXXABI::RAA_DirectInMemory); 31606c3fb27SDimitry Andric } 31706c3fb27SDimitry Andric 31806c3fb27SDimitry Andric // Empty records are always ignored on Darwin, but actually passed in C++ mode 31906c3fb27SDimitry Andric // elsewhere for GNU compatibility. 32006c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(Ty); 32106c3fb27SDimitry Andric bool IsEmpty = isEmptyRecord(getContext(), Ty, true); 32206c3fb27SDimitry Andric if (IsEmpty || Size == 0) { 32306c3fb27SDimitry Andric if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) 32406c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 32506c3fb27SDimitry Andric 32606c3fb27SDimitry Andric // GNU C mode. The only argument that gets ignored is an empty one with size 32706c3fb27SDimitry Andric // 0. 32806c3fb27SDimitry Andric if (IsEmpty && Size == 0) 32906c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 33006c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::Type::getInt8Ty(getVMContext())); 33106c3fb27SDimitry Andric } 33206c3fb27SDimitry Andric 33306c3fb27SDimitry Andric // Homogeneous Floating-point Aggregates (HFAs) need to be expanded. 33406c3fb27SDimitry Andric const Type *Base = nullptr; 33506c3fb27SDimitry Andric uint64_t Members = 0; 33606c3fb27SDimitry Andric bool IsWin64 = Kind == AArch64ABIKind::Win64 || 33706c3fb27SDimitry Andric CallingConvention == llvm::CallingConv::Win64; 33806c3fb27SDimitry Andric bool IsWinVariadic = IsWin64 && IsVariadic; 33906c3fb27SDimitry Andric // In variadic functions on Windows, all composite types are treated alike, 34006c3fb27SDimitry Andric // no special handling of HFAs/HVAs. 34106c3fb27SDimitry Andric if (!IsWinVariadic && isHomogeneousAggregate(Ty, Base, Members)) { 34206c3fb27SDimitry Andric if (Kind != AArch64ABIKind::AAPCS) 34306c3fb27SDimitry Andric return ABIArgInfo::getDirect( 34406c3fb27SDimitry Andric llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members)); 34506c3fb27SDimitry Andric 3465f757f3fSDimitry Andric // For HFAs/HVAs, cap the argument alignment to 16, otherwise 3475f757f3fSDimitry Andric // set it to 8 according to the AAPCS64 document. 34806c3fb27SDimitry Andric unsigned Align = 34906c3fb27SDimitry Andric getContext().getTypeUnadjustedAlignInChars(Ty).getQuantity(); 3505f757f3fSDimitry Andric Align = (Align >= 16) ? 16 : 8; 35106c3fb27SDimitry Andric return ABIArgInfo::getDirect( 35206c3fb27SDimitry Andric llvm::ArrayType::get(CGT.ConvertType(QualType(Base, 0)), Members), 0, 35306c3fb27SDimitry Andric nullptr, true, Align); 35406c3fb27SDimitry Andric } 35506c3fb27SDimitry Andric 35606c3fb27SDimitry Andric // Aggregates <= 16 bytes are passed directly in registers or on the stack. 35706c3fb27SDimitry Andric if (Size <= 128) { 35806c3fb27SDimitry Andric // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of 35906c3fb27SDimitry Andric // same size and alignment. 36006c3fb27SDimitry Andric if (getTarget().isRenderScriptTarget()) { 36106c3fb27SDimitry Andric return coerceToIntArray(Ty, getContext(), getVMContext()); 36206c3fb27SDimitry Andric } 36306c3fb27SDimitry Andric unsigned Alignment; 36406c3fb27SDimitry Andric if (Kind == AArch64ABIKind::AAPCS) { 36506c3fb27SDimitry Andric Alignment = getContext().getTypeUnadjustedAlign(Ty); 36606c3fb27SDimitry Andric Alignment = Alignment < 128 ? 64 : 128; 36706c3fb27SDimitry Andric } else { 36806c3fb27SDimitry Andric Alignment = 36906c3fb27SDimitry Andric std::max(getContext().getTypeAlign(Ty), 37006c3fb27SDimitry Andric (unsigned)getTarget().getPointerWidth(LangAS::Default)); 37106c3fb27SDimitry Andric } 37206c3fb27SDimitry Andric Size = llvm::alignTo(Size, Alignment); 37306c3fb27SDimitry Andric 37406c3fb27SDimitry Andric // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. 37506c3fb27SDimitry Andric // For aggregates with 16-byte alignment, we use i128. 37606c3fb27SDimitry Andric llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment); 37706c3fb27SDimitry Andric return ABIArgInfo::getDirect( 37806c3fb27SDimitry Andric Size == Alignment ? BaseTy 37906c3fb27SDimitry Andric : llvm::ArrayType::get(BaseTy, Size / Alignment)); 38006c3fb27SDimitry Andric } 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, /*ByVal=*/false); 38306c3fb27SDimitry Andric } 38406c3fb27SDimitry Andric 38506c3fb27SDimitry Andric ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, 38606c3fb27SDimitry Andric bool IsVariadic) const { 38706c3fb27SDimitry Andric if (RetTy->isVoidType()) 38806c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 38906c3fb27SDimitry Andric 39006c3fb27SDimitry Andric if (const auto *VT = RetTy->getAs<VectorType>()) { 3915f757f3fSDimitry Andric if (VT->getVectorKind() == VectorKind::SveFixedLengthData || 3925f757f3fSDimitry Andric VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) 39306c3fb27SDimitry Andric return coerceIllegalVector(RetTy); 39406c3fb27SDimitry Andric } 39506c3fb27SDimitry Andric 39606c3fb27SDimitry Andric // Large vector types should be returned via memory. 39706c3fb27SDimitry Andric if (RetTy->isVectorType() && getContext().getTypeSize(RetTy) > 128) 39806c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 39906c3fb27SDimitry Andric 40006c3fb27SDimitry Andric if (!isAggregateTypeForABI(RetTy)) { 40106c3fb27SDimitry Andric // Treat an enum type as its underlying type. 40206c3fb27SDimitry Andric if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) 40306c3fb27SDimitry Andric RetTy = EnumTy->getDecl()->getIntegerType(); 40406c3fb27SDimitry Andric 40506c3fb27SDimitry Andric if (const auto *EIT = RetTy->getAs<BitIntType>()) 40606c3fb27SDimitry Andric if (EIT->getNumBits() > 128) 40706c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 40806c3fb27SDimitry Andric 40906c3fb27SDimitry Andric return (isPromotableIntegerTypeForABI(RetTy) && isDarwinPCS() 41006c3fb27SDimitry Andric ? ABIArgInfo::getExtend(RetTy) 41106c3fb27SDimitry Andric : ABIArgInfo::getDirect()); 41206c3fb27SDimitry Andric } 41306c3fb27SDimitry Andric 41406c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(RetTy); 41506c3fb27SDimitry Andric if (isEmptyRecord(getContext(), RetTy, true) || Size == 0) 41606c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 41706c3fb27SDimitry Andric 41806c3fb27SDimitry Andric const Type *Base = nullptr; 41906c3fb27SDimitry Andric uint64_t Members = 0; 42006c3fb27SDimitry Andric if (isHomogeneousAggregate(RetTy, Base, Members) && 42106c3fb27SDimitry Andric !(getTarget().getTriple().getArch() == llvm::Triple::aarch64_32 && 42206c3fb27SDimitry Andric IsVariadic)) 42306c3fb27SDimitry Andric // Homogeneous Floating-point Aggregates (HFAs) are returned directly. 42406c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 42506c3fb27SDimitry Andric 42606c3fb27SDimitry Andric // Aggregates <= 16 bytes are returned directly in registers or on the stack. 42706c3fb27SDimitry Andric if (Size <= 128) { 42806c3fb27SDimitry Andric // On RenderScript, coerce Aggregates <= 16 bytes to an integer array of 42906c3fb27SDimitry Andric // same size and alignment. 43006c3fb27SDimitry Andric if (getTarget().isRenderScriptTarget()) { 43106c3fb27SDimitry Andric return coerceToIntArray(RetTy, getContext(), getVMContext()); 43206c3fb27SDimitry Andric } 43306c3fb27SDimitry Andric 43406c3fb27SDimitry Andric if (Size <= 64 && getDataLayout().isLittleEndian()) { 43506c3fb27SDimitry Andric // Composite types are returned in lower bits of a 64-bit register for LE, 43606c3fb27SDimitry Andric // and in higher bits for BE. However, integer types are always returned 43706c3fb27SDimitry Andric // in lower bits for both LE and BE, and they are not rounded up to 43806c3fb27SDimitry Andric // 64-bits. We can skip rounding up of composite types for LE, but not for 43906c3fb27SDimitry Andric // BE, otherwise composite types will be indistinguishable from integer 44006c3fb27SDimitry Andric // types. 44106c3fb27SDimitry Andric return ABIArgInfo::getDirect( 44206c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), Size)); 44306c3fb27SDimitry Andric } 44406c3fb27SDimitry Andric 44506c3fb27SDimitry Andric unsigned Alignment = getContext().getTypeAlign(RetTy); 44606c3fb27SDimitry Andric Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes 44706c3fb27SDimitry Andric 44806c3fb27SDimitry Andric // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. 44906c3fb27SDimitry Andric // For aggregates with 16-byte alignment, we use i128. 45006c3fb27SDimitry Andric if (Alignment < 128 && Size == 128) { 45106c3fb27SDimitry Andric llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext()); 45206c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64)); 45306c3fb27SDimitry Andric } 45406c3fb27SDimitry Andric return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); 45506c3fb27SDimitry Andric } 45606c3fb27SDimitry Andric 45706c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 45806c3fb27SDimitry Andric } 45906c3fb27SDimitry Andric 46006c3fb27SDimitry Andric /// isIllegalVectorType - check whether the vector type is legal for AArch64. 46106c3fb27SDimitry Andric bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { 46206c3fb27SDimitry Andric if (const VectorType *VT = Ty->getAs<VectorType>()) { 46306c3fb27SDimitry Andric // Check whether VT is a fixed-length SVE vector. These types are 46406c3fb27SDimitry Andric // represented as scalable vectors in function args/return and must be 46506c3fb27SDimitry Andric // coerced from fixed vectors. 4665f757f3fSDimitry Andric if (VT->getVectorKind() == VectorKind::SveFixedLengthData || 4675f757f3fSDimitry Andric VT->getVectorKind() == VectorKind::SveFixedLengthPredicate) 46806c3fb27SDimitry Andric return true; 46906c3fb27SDimitry Andric 47006c3fb27SDimitry Andric // Check whether VT is legal. 47106c3fb27SDimitry Andric unsigned NumElements = VT->getNumElements(); 47206c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(VT); 47306c3fb27SDimitry Andric // NumElements should be power of 2. 47406c3fb27SDimitry Andric if (!llvm::isPowerOf2_32(NumElements)) 47506c3fb27SDimitry Andric return true; 47606c3fb27SDimitry Andric 47706c3fb27SDimitry Andric // arm64_32 has to be compatible with the ARM logic here, which allows huge 47806c3fb27SDimitry Andric // vectors for some reason. 47906c3fb27SDimitry Andric llvm::Triple Triple = getTarget().getTriple(); 48006c3fb27SDimitry Andric if (Triple.getArch() == llvm::Triple::aarch64_32 && 48106c3fb27SDimitry Andric Triple.isOSBinFormatMachO()) 48206c3fb27SDimitry Andric return Size <= 32; 48306c3fb27SDimitry Andric 48406c3fb27SDimitry Andric return Size != 64 && (Size != 128 || NumElements == 1); 48506c3fb27SDimitry Andric } 48606c3fb27SDimitry Andric return false; 48706c3fb27SDimitry Andric } 48806c3fb27SDimitry Andric 48906c3fb27SDimitry Andric bool AArch64SwiftABIInfo::isLegalVectorType(CharUnits VectorSize, 49006c3fb27SDimitry Andric llvm::Type *EltTy, 49106c3fb27SDimitry Andric unsigned NumElts) const { 49206c3fb27SDimitry Andric if (!llvm::isPowerOf2_32(NumElts)) 49306c3fb27SDimitry Andric return false; 49406c3fb27SDimitry Andric if (VectorSize.getQuantity() != 8 && 49506c3fb27SDimitry Andric (VectorSize.getQuantity() != 16 || NumElts == 1)) 49606c3fb27SDimitry Andric return false; 49706c3fb27SDimitry Andric return true; 49806c3fb27SDimitry Andric } 49906c3fb27SDimitry Andric 50006c3fb27SDimitry Andric bool AArch64ABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { 5010fca6ea1SDimitry Andric // For the soft-float ABI variant, no types are considered to be homogeneous 5020fca6ea1SDimitry Andric // aggregates. 5030fca6ea1SDimitry Andric if (Kind == AArch64ABIKind::AAPCSSoft) 5040fca6ea1SDimitry Andric return false; 5050fca6ea1SDimitry Andric 50606c3fb27SDimitry Andric // Homogeneous aggregates for AAPCS64 must have base types of a floating 50706c3fb27SDimitry Andric // point type or a short-vector type. This is the same as the 32-bit ABI, 50806c3fb27SDimitry Andric // but with the difference that any floating-point type is allowed, 50906c3fb27SDimitry Andric // including __fp16. 51006c3fb27SDimitry Andric if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { 51106c3fb27SDimitry Andric if (BT->isFloatingPoint()) 51206c3fb27SDimitry Andric return true; 51306c3fb27SDimitry Andric } else if (const VectorType *VT = Ty->getAs<VectorType>()) { 51406c3fb27SDimitry Andric unsigned VecSize = getContext().getTypeSize(VT); 51506c3fb27SDimitry Andric if (VecSize == 64 || VecSize == 128) 51606c3fb27SDimitry Andric return true; 51706c3fb27SDimitry Andric } 51806c3fb27SDimitry Andric return false; 51906c3fb27SDimitry Andric } 52006c3fb27SDimitry Andric 52106c3fb27SDimitry Andric bool AArch64ABIInfo::isHomogeneousAggregateSmallEnough(const Type *Base, 52206c3fb27SDimitry Andric uint64_t Members) const { 52306c3fb27SDimitry Andric return Members <= 4; 52406c3fb27SDimitry Andric } 52506c3fb27SDimitry Andric 52606c3fb27SDimitry Andric bool AArch64ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() 52706c3fb27SDimitry Andric const { 52806c3fb27SDimitry Andric // AAPCS64 says that the rule for whether something is a homogeneous 52906c3fb27SDimitry Andric // aggregate is applied to the output of the data layout decision. So 53006c3fb27SDimitry Andric // anything that doesn't affect the data layout also does not affect 53106c3fb27SDimitry Andric // homogeneity. In particular, zero-length bitfields don't stop a struct 53206c3fb27SDimitry Andric // being homogeneous. 53306c3fb27SDimitry Andric return true; 53406c3fb27SDimitry Andric } 53506c3fb27SDimitry Andric 5360fca6ea1SDimitry Andric RValue AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, 5370fca6ea1SDimitry Andric CodeGenFunction &CGF, AArch64ABIKind Kind, 5380fca6ea1SDimitry Andric AggValueSlot Slot) const { 53906c3fb27SDimitry Andric ABIArgInfo AI = classifyArgumentType(Ty, /*IsVariadic=*/true, 54006c3fb27SDimitry Andric CGF.CurFnInfo->getCallingConvention()); 54106c3fb27SDimitry Andric // Empty records are ignored for parameter passing purposes. 5420fca6ea1SDimitry Andric if (AI.isIgnore()) 5430fca6ea1SDimitry Andric return Slot.asRValue(); 54406c3fb27SDimitry Andric 54506c3fb27SDimitry Andric bool IsIndirect = AI.isIndirect(); 54606c3fb27SDimitry Andric 54706c3fb27SDimitry Andric llvm::Type *BaseTy = CGF.ConvertType(Ty); 54806c3fb27SDimitry Andric if (IsIndirect) 54906c3fb27SDimitry Andric BaseTy = llvm::PointerType::getUnqual(BaseTy); 55006c3fb27SDimitry Andric else if (AI.getCoerceToType()) 55106c3fb27SDimitry Andric BaseTy = AI.getCoerceToType(); 55206c3fb27SDimitry Andric 55306c3fb27SDimitry Andric unsigned NumRegs = 1; 55406c3fb27SDimitry Andric if (llvm::ArrayType *ArrTy = dyn_cast<llvm::ArrayType>(BaseTy)) { 55506c3fb27SDimitry Andric BaseTy = ArrTy->getElementType(); 55606c3fb27SDimitry Andric NumRegs = ArrTy->getNumElements(); 55706c3fb27SDimitry Andric } 5580fca6ea1SDimitry Andric bool IsFPR = Kind != AArch64ABIKind::AAPCSSoft && 5590fca6ea1SDimitry Andric (BaseTy->isFloatingPointTy() || BaseTy->isVectorTy()); 56006c3fb27SDimitry Andric 56106c3fb27SDimitry Andric // The AArch64 va_list type and handling is specified in the Procedure Call 56206c3fb27SDimitry Andric // Standard, section B.4: 56306c3fb27SDimitry Andric // 56406c3fb27SDimitry Andric // struct { 56506c3fb27SDimitry Andric // void *__stack; 56606c3fb27SDimitry Andric // void *__gr_top; 56706c3fb27SDimitry Andric // void *__vr_top; 56806c3fb27SDimitry Andric // int __gr_offs; 56906c3fb27SDimitry Andric // int __vr_offs; 57006c3fb27SDimitry Andric // }; 57106c3fb27SDimitry Andric 57206c3fb27SDimitry Andric llvm::BasicBlock *MaybeRegBlock = CGF.createBasicBlock("vaarg.maybe_reg"); 57306c3fb27SDimitry Andric llvm::BasicBlock *InRegBlock = CGF.createBasicBlock("vaarg.in_reg"); 57406c3fb27SDimitry Andric llvm::BasicBlock *OnStackBlock = CGF.createBasicBlock("vaarg.on_stack"); 57506c3fb27SDimitry Andric llvm::BasicBlock *ContBlock = CGF.createBasicBlock("vaarg.end"); 57606c3fb27SDimitry Andric 57706c3fb27SDimitry Andric CharUnits TySize = getContext().getTypeSizeInChars(Ty); 57806c3fb27SDimitry Andric CharUnits TyAlign = getContext().getTypeUnadjustedAlignInChars(Ty); 57906c3fb27SDimitry Andric 58006c3fb27SDimitry Andric Address reg_offs_p = Address::invalid(); 58106c3fb27SDimitry Andric llvm::Value *reg_offs = nullptr; 58206c3fb27SDimitry Andric int reg_top_index; 58306c3fb27SDimitry Andric int RegSize = IsIndirect ? 8 : TySize.getQuantity(); 58406c3fb27SDimitry Andric if (!IsFPR) { 58506c3fb27SDimitry Andric // 3 is the field number of __gr_offs 58606c3fb27SDimitry Andric reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 3, "gr_offs_p"); 58706c3fb27SDimitry Andric reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "gr_offs"); 58806c3fb27SDimitry Andric reg_top_index = 1; // field number for __gr_top 58906c3fb27SDimitry Andric RegSize = llvm::alignTo(RegSize, 8); 59006c3fb27SDimitry Andric } else { 59106c3fb27SDimitry Andric // 4 is the field number of __vr_offs. 59206c3fb27SDimitry Andric reg_offs_p = CGF.Builder.CreateStructGEP(VAListAddr, 4, "vr_offs_p"); 59306c3fb27SDimitry Andric reg_offs = CGF.Builder.CreateLoad(reg_offs_p, "vr_offs"); 59406c3fb27SDimitry Andric reg_top_index = 2; // field number for __vr_top 59506c3fb27SDimitry Andric RegSize = 16 * NumRegs; 59606c3fb27SDimitry Andric } 59706c3fb27SDimitry Andric 59806c3fb27SDimitry Andric //======================================= 59906c3fb27SDimitry Andric // Find out where argument was passed 60006c3fb27SDimitry Andric //======================================= 60106c3fb27SDimitry Andric 60206c3fb27SDimitry Andric // If reg_offs >= 0 we're already using the stack for this type of 60306c3fb27SDimitry Andric // argument. We don't want to keep updating reg_offs (in case it overflows, 60406c3fb27SDimitry Andric // though anyone passing 2GB of arguments, each at most 16 bytes, deserves 60506c3fb27SDimitry Andric // whatever they get). 60606c3fb27SDimitry Andric llvm::Value *UsingStack = nullptr; 60706c3fb27SDimitry Andric UsingStack = CGF.Builder.CreateICmpSGE( 60806c3fb27SDimitry Andric reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, 0)); 60906c3fb27SDimitry Andric 61006c3fb27SDimitry Andric CGF.Builder.CreateCondBr(UsingStack, OnStackBlock, MaybeRegBlock); 61106c3fb27SDimitry Andric 61206c3fb27SDimitry Andric // Otherwise, at least some kind of argument could go in these registers, the 61306c3fb27SDimitry Andric // question is whether this particular type is too big. 61406c3fb27SDimitry Andric CGF.EmitBlock(MaybeRegBlock); 61506c3fb27SDimitry Andric 61606c3fb27SDimitry Andric // Integer arguments may need to correct register alignment (for example a 61706c3fb27SDimitry Andric // "struct { __int128 a; };" gets passed in x_2N, x_{2N+1}). In this case we 61806c3fb27SDimitry Andric // align __gr_offs to calculate the potential address. 61906c3fb27SDimitry Andric if (!IsFPR && !IsIndirect && TyAlign.getQuantity() > 8) { 62006c3fb27SDimitry Andric int Align = TyAlign.getQuantity(); 62106c3fb27SDimitry Andric 62206c3fb27SDimitry Andric reg_offs = CGF.Builder.CreateAdd( 62306c3fb27SDimitry Andric reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, Align - 1), 62406c3fb27SDimitry Andric "align_regoffs"); 62506c3fb27SDimitry Andric reg_offs = CGF.Builder.CreateAnd( 62606c3fb27SDimitry Andric reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, -Align), 62706c3fb27SDimitry Andric "aligned_regoffs"); 62806c3fb27SDimitry Andric } 62906c3fb27SDimitry Andric 63006c3fb27SDimitry Andric // Update the gr_offs/vr_offs pointer for next call to va_arg on this va_list. 63106c3fb27SDimitry Andric // The fact that this is done unconditionally reflects the fact that 63206c3fb27SDimitry Andric // allocating an argument to the stack also uses up all the remaining 63306c3fb27SDimitry Andric // registers of the appropriate kind. 63406c3fb27SDimitry Andric llvm::Value *NewOffset = nullptr; 63506c3fb27SDimitry Andric NewOffset = CGF.Builder.CreateAdd( 63606c3fb27SDimitry Andric reg_offs, llvm::ConstantInt::get(CGF.Int32Ty, RegSize), "new_reg_offs"); 63706c3fb27SDimitry Andric CGF.Builder.CreateStore(NewOffset, reg_offs_p); 63806c3fb27SDimitry Andric 63906c3fb27SDimitry Andric // Now we're in a position to decide whether this argument really was in 64006c3fb27SDimitry Andric // registers or not. 64106c3fb27SDimitry Andric llvm::Value *InRegs = nullptr; 64206c3fb27SDimitry Andric InRegs = CGF.Builder.CreateICmpSLE( 64306c3fb27SDimitry Andric NewOffset, llvm::ConstantInt::get(CGF.Int32Ty, 0), "inreg"); 64406c3fb27SDimitry Andric 64506c3fb27SDimitry Andric CGF.Builder.CreateCondBr(InRegs, InRegBlock, OnStackBlock); 64606c3fb27SDimitry Andric 64706c3fb27SDimitry Andric //======================================= 64806c3fb27SDimitry Andric // Argument was in registers 64906c3fb27SDimitry Andric //======================================= 65006c3fb27SDimitry Andric 65106c3fb27SDimitry Andric // Now we emit the code for if the argument was originally passed in 65206c3fb27SDimitry Andric // registers. First start the appropriate block: 65306c3fb27SDimitry Andric CGF.EmitBlock(InRegBlock); 65406c3fb27SDimitry Andric 65506c3fb27SDimitry Andric llvm::Value *reg_top = nullptr; 65606c3fb27SDimitry Andric Address reg_top_p = 65706c3fb27SDimitry Andric CGF.Builder.CreateStructGEP(VAListAddr, reg_top_index, "reg_top_p"); 65806c3fb27SDimitry Andric reg_top = CGF.Builder.CreateLoad(reg_top_p, "reg_top"); 65906c3fb27SDimitry Andric Address BaseAddr(CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, reg_top, reg_offs), 66006c3fb27SDimitry Andric CGF.Int8Ty, CharUnits::fromQuantity(IsFPR ? 16 : 8)); 66106c3fb27SDimitry Andric Address RegAddr = Address::invalid(); 66206c3fb27SDimitry Andric llvm::Type *MemTy = CGF.ConvertTypeForMem(Ty), *ElementTy = MemTy; 66306c3fb27SDimitry Andric 66406c3fb27SDimitry Andric if (IsIndirect) { 66506c3fb27SDimitry Andric // If it's been passed indirectly (actually a struct), whatever we find from 66606c3fb27SDimitry Andric // stored registers or on the stack will actually be a struct **. 66706c3fb27SDimitry Andric MemTy = llvm::PointerType::getUnqual(MemTy); 66806c3fb27SDimitry Andric } 66906c3fb27SDimitry Andric 67006c3fb27SDimitry Andric const Type *Base = nullptr; 67106c3fb27SDimitry Andric uint64_t NumMembers = 0; 67206c3fb27SDimitry Andric bool IsHFA = isHomogeneousAggregate(Ty, Base, NumMembers); 67306c3fb27SDimitry Andric if (IsHFA && NumMembers > 1) { 67406c3fb27SDimitry Andric // Homogeneous aggregates passed in registers will have their elements split 67506c3fb27SDimitry Andric // and stored 16-bytes apart regardless of size (they're notionally in qN, 67606c3fb27SDimitry Andric // qN+1, ...). We reload and store into a temporary local variable 67706c3fb27SDimitry Andric // contiguously. 67806c3fb27SDimitry Andric assert(!IsIndirect && "Homogeneous aggregates should be passed directly"); 67906c3fb27SDimitry Andric auto BaseTyInfo = getContext().getTypeInfoInChars(QualType(Base, 0)); 68006c3fb27SDimitry Andric llvm::Type *BaseTy = CGF.ConvertType(QualType(Base, 0)); 68106c3fb27SDimitry Andric llvm::Type *HFATy = llvm::ArrayType::get(BaseTy, NumMembers); 68206c3fb27SDimitry Andric Address Tmp = CGF.CreateTempAlloca(HFATy, 68306c3fb27SDimitry Andric std::max(TyAlign, BaseTyInfo.Align)); 68406c3fb27SDimitry Andric 68506c3fb27SDimitry Andric // On big-endian platforms, the value will be right-aligned in its slot. 68606c3fb27SDimitry Andric int Offset = 0; 68706c3fb27SDimitry Andric if (CGF.CGM.getDataLayout().isBigEndian() && 68806c3fb27SDimitry Andric BaseTyInfo.Width.getQuantity() < 16) 68906c3fb27SDimitry Andric Offset = 16 - BaseTyInfo.Width.getQuantity(); 69006c3fb27SDimitry Andric 69106c3fb27SDimitry Andric for (unsigned i = 0; i < NumMembers; ++i) { 69206c3fb27SDimitry Andric CharUnits BaseOffset = CharUnits::fromQuantity(16 * i + Offset); 69306c3fb27SDimitry Andric Address LoadAddr = 69406c3fb27SDimitry Andric CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, BaseOffset); 69506c3fb27SDimitry Andric LoadAddr = LoadAddr.withElementType(BaseTy); 69606c3fb27SDimitry Andric 69706c3fb27SDimitry Andric Address StoreAddr = CGF.Builder.CreateConstArrayGEP(Tmp, i); 69806c3fb27SDimitry Andric 69906c3fb27SDimitry Andric llvm::Value *Elem = CGF.Builder.CreateLoad(LoadAddr); 70006c3fb27SDimitry Andric CGF.Builder.CreateStore(Elem, StoreAddr); 70106c3fb27SDimitry Andric } 70206c3fb27SDimitry Andric 70306c3fb27SDimitry Andric RegAddr = Tmp.withElementType(MemTy); 70406c3fb27SDimitry Andric } else { 70506c3fb27SDimitry Andric // Otherwise the object is contiguous in memory. 70606c3fb27SDimitry Andric 70706c3fb27SDimitry Andric // It might be right-aligned in its slot. 70806c3fb27SDimitry Andric CharUnits SlotSize = BaseAddr.getAlignment(); 70906c3fb27SDimitry Andric if (CGF.CGM.getDataLayout().isBigEndian() && !IsIndirect && 71006c3fb27SDimitry Andric (IsHFA || !isAggregateTypeForABI(Ty)) && 71106c3fb27SDimitry Andric TySize < SlotSize) { 71206c3fb27SDimitry Andric CharUnits Offset = SlotSize - TySize; 71306c3fb27SDimitry Andric BaseAddr = CGF.Builder.CreateConstInBoundsByteGEP(BaseAddr, Offset); 71406c3fb27SDimitry Andric } 71506c3fb27SDimitry Andric 71606c3fb27SDimitry Andric RegAddr = BaseAddr.withElementType(MemTy); 71706c3fb27SDimitry Andric } 71806c3fb27SDimitry Andric 71906c3fb27SDimitry Andric CGF.EmitBranch(ContBlock); 72006c3fb27SDimitry Andric 72106c3fb27SDimitry Andric //======================================= 72206c3fb27SDimitry Andric // Argument was on the stack 72306c3fb27SDimitry Andric //======================================= 72406c3fb27SDimitry Andric CGF.EmitBlock(OnStackBlock); 72506c3fb27SDimitry Andric 72606c3fb27SDimitry Andric Address stack_p = CGF.Builder.CreateStructGEP(VAListAddr, 0, "stack_p"); 72706c3fb27SDimitry Andric llvm::Value *OnStackPtr = CGF.Builder.CreateLoad(stack_p, "stack"); 72806c3fb27SDimitry Andric 72906c3fb27SDimitry Andric // Again, stack arguments may need realignment. In this case both integer and 73006c3fb27SDimitry Andric // floating-point ones might be affected. 73106c3fb27SDimitry Andric if (!IsIndirect && TyAlign.getQuantity() > 8) { 7320fca6ea1SDimitry Andric OnStackPtr = emitRoundPointerUpToAlignment(CGF, OnStackPtr, TyAlign); 73306c3fb27SDimitry Andric } 73406c3fb27SDimitry Andric Address OnStackAddr = Address(OnStackPtr, CGF.Int8Ty, 73506c3fb27SDimitry Andric std::max(CharUnits::fromQuantity(8), TyAlign)); 73606c3fb27SDimitry Andric 73706c3fb27SDimitry Andric // All stack slots are multiples of 8 bytes. 73806c3fb27SDimitry Andric CharUnits StackSlotSize = CharUnits::fromQuantity(8); 73906c3fb27SDimitry Andric CharUnits StackSize; 74006c3fb27SDimitry Andric if (IsIndirect) 74106c3fb27SDimitry Andric StackSize = StackSlotSize; 74206c3fb27SDimitry Andric else 74306c3fb27SDimitry Andric StackSize = TySize.alignTo(StackSlotSize); 74406c3fb27SDimitry Andric 74506c3fb27SDimitry Andric llvm::Value *StackSizeC = CGF.Builder.getSize(StackSize); 74606c3fb27SDimitry Andric llvm::Value *NewStack = CGF.Builder.CreateInBoundsGEP( 74706c3fb27SDimitry Andric CGF.Int8Ty, OnStackPtr, StackSizeC, "new_stack"); 74806c3fb27SDimitry Andric 74906c3fb27SDimitry Andric // Write the new value of __stack for the next call to va_arg 75006c3fb27SDimitry Andric CGF.Builder.CreateStore(NewStack, stack_p); 75106c3fb27SDimitry Andric 75206c3fb27SDimitry Andric if (CGF.CGM.getDataLayout().isBigEndian() && !isAggregateTypeForABI(Ty) && 75306c3fb27SDimitry Andric TySize < StackSlotSize) { 75406c3fb27SDimitry Andric CharUnits Offset = StackSlotSize - TySize; 75506c3fb27SDimitry Andric OnStackAddr = CGF.Builder.CreateConstInBoundsByteGEP(OnStackAddr, Offset); 75606c3fb27SDimitry Andric } 75706c3fb27SDimitry Andric 75806c3fb27SDimitry Andric OnStackAddr = OnStackAddr.withElementType(MemTy); 75906c3fb27SDimitry Andric 76006c3fb27SDimitry Andric CGF.EmitBranch(ContBlock); 76106c3fb27SDimitry Andric 76206c3fb27SDimitry Andric //======================================= 76306c3fb27SDimitry Andric // Tidy up 76406c3fb27SDimitry Andric //======================================= 76506c3fb27SDimitry Andric CGF.EmitBlock(ContBlock); 76606c3fb27SDimitry Andric 76706c3fb27SDimitry Andric Address ResAddr = emitMergePHI(CGF, RegAddr, InRegBlock, OnStackAddr, 76806c3fb27SDimitry Andric OnStackBlock, "vaargs.addr"); 76906c3fb27SDimitry Andric 77006c3fb27SDimitry Andric if (IsIndirect) 7710fca6ea1SDimitry Andric return CGF.EmitLoadOfAnyValue( 7720fca6ea1SDimitry Andric CGF.MakeAddrLValue( 7730fca6ea1SDimitry Andric Address(CGF.Builder.CreateLoad(ResAddr, "vaarg.addr"), ElementTy, 7740fca6ea1SDimitry Andric TyAlign), 7750fca6ea1SDimitry Andric Ty), 7760fca6ea1SDimitry Andric Slot); 77706c3fb27SDimitry Andric 7780fca6ea1SDimitry Andric return CGF.EmitLoadOfAnyValue(CGF.MakeAddrLValue(ResAddr, Ty), Slot); 77906c3fb27SDimitry Andric } 78006c3fb27SDimitry Andric 7810fca6ea1SDimitry Andric RValue AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty, 7820fca6ea1SDimitry Andric CodeGenFunction &CGF, 7830fca6ea1SDimitry Andric AggValueSlot Slot) const { 78406c3fb27SDimitry Andric // The backend's lowering doesn't support va_arg for aggregates or 78506c3fb27SDimitry Andric // illegal vector types. Lower VAArg here for these cases and use 78606c3fb27SDimitry Andric // the LLVM va_arg instruction for everything else. 78706c3fb27SDimitry Andric if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty)) 7880fca6ea1SDimitry Andric return CGF.EmitLoadOfAnyValue( 7890fca6ea1SDimitry Andric CGF.MakeAddrLValue( 7900fca6ea1SDimitry Andric EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect()), Ty), 7910fca6ea1SDimitry Andric Slot); 79206c3fb27SDimitry Andric 79306c3fb27SDimitry Andric uint64_t PointerSize = getTarget().getPointerWidth(LangAS::Default) / 8; 79406c3fb27SDimitry Andric CharUnits SlotSize = CharUnits::fromQuantity(PointerSize); 79506c3fb27SDimitry Andric 79606c3fb27SDimitry Andric // Empty records are ignored for parameter passing purposes. 79706c3fb27SDimitry Andric if (isEmptyRecord(getContext(), Ty, true)) 7980fca6ea1SDimitry Andric return Slot.asRValue(); 79906c3fb27SDimitry Andric 80006c3fb27SDimitry Andric // The size of the actual thing passed, which might end up just 80106c3fb27SDimitry Andric // being a pointer for indirect types. 80206c3fb27SDimitry Andric auto TyInfo = getContext().getTypeInfoInChars(Ty); 80306c3fb27SDimitry Andric 80406c3fb27SDimitry Andric // Arguments bigger than 16 bytes which aren't homogeneous 80506c3fb27SDimitry Andric // aggregates should be passed indirectly. 80606c3fb27SDimitry Andric bool IsIndirect = false; 80706c3fb27SDimitry Andric if (TyInfo.Width.getQuantity() > 16) { 80806c3fb27SDimitry Andric const Type *Base = nullptr; 80906c3fb27SDimitry Andric uint64_t Members = 0; 81006c3fb27SDimitry Andric IsIndirect = !isHomogeneousAggregate(Ty, Base, Members); 81106c3fb27SDimitry Andric } 81206c3fb27SDimitry Andric 8130fca6ea1SDimitry Andric return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, TyInfo, SlotSize, 8140fca6ea1SDimitry Andric /*AllowHigherAlign*/ true, Slot); 81506c3fb27SDimitry Andric } 81606c3fb27SDimitry Andric 8170fca6ea1SDimitry Andric RValue AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr, 8180fca6ea1SDimitry Andric QualType Ty, AggValueSlot Slot) const { 81906c3fb27SDimitry Andric bool IsIndirect = false; 82006c3fb27SDimitry Andric 82106c3fb27SDimitry Andric // Composites larger than 16 bytes are passed by reference. 82206c3fb27SDimitry Andric if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) > 128) 82306c3fb27SDimitry Andric IsIndirect = true; 82406c3fb27SDimitry Andric 82506c3fb27SDimitry Andric return emitVoidPtrVAArg(CGF, VAListAddr, Ty, IsIndirect, 82606c3fb27SDimitry Andric CGF.getContext().getTypeInfoInChars(Ty), 82706c3fb27SDimitry Andric CharUnits::fromQuantity(8), 8280fca6ea1SDimitry Andric /*allowHigherAlign*/ false, Slot); 8290fca6ea1SDimitry Andric } 8300fca6ea1SDimitry Andric 8310fca6ea1SDimitry Andric static bool isStreamingCompatible(const FunctionDecl *F) { 8320fca6ea1SDimitry Andric if (const auto *T = F->getType()->getAs<FunctionProtoType>()) 8330fca6ea1SDimitry Andric return T->getAArch64SMEAttributes() & 8340fca6ea1SDimitry Andric FunctionType::SME_PStateSMCompatibleMask; 8350fca6ea1SDimitry Andric return false; 8360fca6ea1SDimitry Andric } 8370fca6ea1SDimitry Andric 8380fca6ea1SDimitry Andric // Report an error if an argument or return value of type Ty would need to be 8390fca6ea1SDimitry Andric // passed in a floating-point register. 8400fca6ea1SDimitry Andric static void diagnoseIfNeedsFPReg(DiagnosticsEngine &Diags, 8410fca6ea1SDimitry Andric const StringRef ABIName, 8420fca6ea1SDimitry Andric const AArch64ABIInfo &ABIInfo, 843*62987288SDimitry Andric const QualType &Ty, const NamedDecl *D, 844*62987288SDimitry Andric SourceLocation loc) { 8450fca6ea1SDimitry Andric const Type *HABase = nullptr; 8460fca6ea1SDimitry Andric uint64_t HAMembers = 0; 8470fca6ea1SDimitry Andric if (Ty->isFloatingType() || Ty->isVectorType() || 8480fca6ea1SDimitry Andric ABIInfo.isHomogeneousAggregate(Ty, HABase, HAMembers)) { 849*62987288SDimitry Andric Diags.Report(loc, diag::err_target_unsupported_type_for_abi) 8500fca6ea1SDimitry Andric << D->getDeclName() << Ty << ABIName; 8510fca6ea1SDimitry Andric } 8520fca6ea1SDimitry Andric } 8530fca6ea1SDimitry Andric 8540fca6ea1SDimitry Andric // If we are using a hard-float ABI, but do not have floating point registers, 8550fca6ea1SDimitry Andric // then report an error for any function arguments or returns which would be 8560fca6ea1SDimitry Andric // passed in floating-pint registers. 8570fca6ea1SDimitry Andric void AArch64TargetCodeGenInfo::checkFunctionABI( 8580fca6ea1SDimitry Andric CodeGenModule &CGM, const FunctionDecl *FuncDecl) const { 8590fca6ea1SDimitry Andric const AArch64ABIInfo &ABIInfo = getABIInfo<AArch64ABIInfo>(); 8600fca6ea1SDimitry Andric const TargetInfo &TI = ABIInfo.getContext().getTargetInfo(); 8610fca6ea1SDimitry Andric 8620fca6ea1SDimitry Andric if (!TI.hasFeature("fp") && !ABIInfo.isSoftFloat()) { 8630fca6ea1SDimitry Andric diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, 864*62987288SDimitry Andric FuncDecl->getReturnType(), FuncDecl, 865*62987288SDimitry Andric FuncDecl->getLocation()); 8660fca6ea1SDimitry Andric for (ParmVarDecl *PVD : FuncDecl->parameters()) { 8670fca6ea1SDimitry Andric diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, PVD->getType(), 868*62987288SDimitry Andric PVD, FuncDecl->getLocation()); 8690fca6ea1SDimitry Andric } 8700fca6ea1SDimitry Andric } 8710fca6ea1SDimitry Andric } 8720fca6ea1SDimitry Andric 8730fca6ea1SDimitry Andric void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming( 8740fca6ea1SDimitry Andric CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller, 8750fca6ea1SDimitry Andric const FunctionDecl *Callee) const { 8760fca6ea1SDimitry Andric if (!Caller || !Callee || !Callee->hasAttr<AlwaysInlineAttr>()) 8770fca6ea1SDimitry Andric return; 8780fca6ea1SDimitry Andric 8790fca6ea1SDimitry Andric bool CallerIsStreaming = 8800fca6ea1SDimitry Andric IsArmStreamingFunction(Caller, /*IncludeLocallyStreaming=*/true); 8810fca6ea1SDimitry Andric bool CalleeIsStreaming = 8820fca6ea1SDimitry Andric IsArmStreamingFunction(Callee, /*IncludeLocallyStreaming=*/true); 8830fca6ea1SDimitry Andric bool CallerIsStreamingCompatible = isStreamingCompatible(Caller); 8840fca6ea1SDimitry Andric bool CalleeIsStreamingCompatible = isStreamingCompatible(Callee); 8850fca6ea1SDimitry Andric 8860fca6ea1SDimitry Andric if (!CalleeIsStreamingCompatible && 8870fca6ea1SDimitry Andric (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) 88852418fc2SDimitry Andric CGM.getDiags().Report( 88952418fc2SDimitry Andric CallLoc, CalleeIsStreaming 89052418fc2SDimitry Andric ? diag::err_function_always_inline_attribute_mismatch 89152418fc2SDimitry Andric : diag::warn_function_always_inline_attribute_mismatch) 8920fca6ea1SDimitry Andric << Caller->getDeclName() << Callee->getDeclName() << "streaming"; 8930fca6ea1SDimitry Andric if (auto *NewAttr = Callee->getAttr<ArmNewAttr>()) 8940fca6ea1SDimitry Andric if (NewAttr->isNewZA()) 8950fca6ea1SDimitry Andric CGM.getDiags().Report(CallLoc, diag::err_function_always_inline_new_za) 8960fca6ea1SDimitry Andric << Callee->getDeclName(); 8970fca6ea1SDimitry Andric } 8980fca6ea1SDimitry Andric 8990fca6ea1SDimitry Andric // If the target does not have floating-point registers, but we are using a 9000fca6ea1SDimitry Andric // hard-float ABI, there is no way to pass floating-point, vector or HFA values 9010fca6ea1SDimitry Andric // to functions, so we report an error. 9020fca6ea1SDimitry Andric void AArch64TargetCodeGenInfo::checkFunctionCallABISoftFloat( 9030fca6ea1SDimitry Andric CodeGenModule &CGM, SourceLocation CallLoc, const FunctionDecl *Caller, 9040fca6ea1SDimitry Andric const FunctionDecl *Callee, const CallArgList &Args, 9050fca6ea1SDimitry Andric QualType ReturnType) const { 9060fca6ea1SDimitry Andric const AArch64ABIInfo &ABIInfo = getABIInfo<AArch64ABIInfo>(); 9070fca6ea1SDimitry Andric const TargetInfo &TI = ABIInfo.getContext().getTargetInfo(); 9080fca6ea1SDimitry Andric 9090fca6ea1SDimitry Andric if (!Caller || TI.hasFeature("fp") || ABIInfo.isSoftFloat()) 9100fca6ea1SDimitry Andric return; 9110fca6ea1SDimitry Andric 9120fca6ea1SDimitry Andric diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, ReturnType, 913*62987288SDimitry Andric Callee ? Callee : Caller, CallLoc); 9140fca6ea1SDimitry Andric 9150fca6ea1SDimitry Andric for (const CallArg &Arg : Args) 9160fca6ea1SDimitry Andric diagnoseIfNeedsFPReg(CGM.getDiags(), TI.getABI(), ABIInfo, Arg.getType(), 917*62987288SDimitry Andric Callee ? Callee : Caller, CallLoc); 9180fca6ea1SDimitry Andric } 9190fca6ea1SDimitry Andric 9200fca6ea1SDimitry Andric void AArch64TargetCodeGenInfo::checkFunctionCallABI(CodeGenModule &CGM, 9210fca6ea1SDimitry Andric SourceLocation CallLoc, 9220fca6ea1SDimitry Andric const FunctionDecl *Caller, 9230fca6ea1SDimitry Andric const FunctionDecl *Callee, 9240fca6ea1SDimitry Andric const CallArgList &Args, 9250fca6ea1SDimitry Andric QualType ReturnType) const { 9260fca6ea1SDimitry Andric checkFunctionCallABIStreaming(CGM, CallLoc, Caller, Callee); 9270fca6ea1SDimitry Andric checkFunctionCallABISoftFloat(CGM, CallLoc, Caller, Callee, Args, ReturnType); 9280fca6ea1SDimitry Andric } 9290fca6ea1SDimitry Andric 9300fca6ea1SDimitry Andric void AArch64ABIInfo::appendAttributeMangling(TargetClonesAttr *Attr, 9310fca6ea1SDimitry Andric unsigned Index, 9320fca6ea1SDimitry Andric raw_ostream &Out) const { 9330fca6ea1SDimitry Andric appendAttributeMangling(Attr->getFeatureStr(Index), Out); 9340fca6ea1SDimitry Andric } 9350fca6ea1SDimitry Andric 9360fca6ea1SDimitry Andric void AArch64ABIInfo::appendAttributeMangling(StringRef AttrStr, 9370fca6ea1SDimitry Andric raw_ostream &Out) const { 9380fca6ea1SDimitry Andric if (AttrStr == "default") { 9390fca6ea1SDimitry Andric Out << ".default"; 9400fca6ea1SDimitry Andric return; 9410fca6ea1SDimitry Andric } 9420fca6ea1SDimitry Andric 9430fca6ea1SDimitry Andric Out << "._"; 9440fca6ea1SDimitry Andric SmallVector<StringRef, 8> Features; 9450fca6ea1SDimitry Andric AttrStr.split(Features, "+"); 9460fca6ea1SDimitry Andric for (auto &Feat : Features) 9470fca6ea1SDimitry Andric Feat = Feat.trim(); 9480fca6ea1SDimitry Andric 9490fca6ea1SDimitry Andric llvm::sort(Features, [](const StringRef LHS, const StringRef RHS) { 9500fca6ea1SDimitry Andric return LHS.compare(RHS) < 0; 9510fca6ea1SDimitry Andric }); 9520fca6ea1SDimitry Andric 9530fca6ea1SDimitry Andric llvm::SmallDenseSet<StringRef, 8> UniqueFeats; 9540fca6ea1SDimitry Andric for (auto &Feat : Features) 9550fca6ea1SDimitry Andric if (auto Ext = llvm::AArch64::parseFMVExtension(Feat)) 9560fca6ea1SDimitry Andric if (UniqueFeats.insert(Ext->Name).second) 9570fca6ea1SDimitry Andric Out << 'M' << Ext->Name; 95806c3fb27SDimitry Andric } 95906c3fb27SDimitry Andric 96006c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 96106c3fb27SDimitry Andric CodeGen::createAArch64TargetCodeGenInfo(CodeGenModule &CGM, 96206c3fb27SDimitry Andric AArch64ABIKind Kind) { 96306c3fb27SDimitry Andric return std::make_unique<AArch64TargetCodeGenInfo>(CGM.getTypes(), Kind); 96406c3fb27SDimitry Andric } 96506c3fb27SDimitry Andric 96606c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 96706c3fb27SDimitry Andric CodeGen::createWindowsAArch64TargetCodeGenInfo(CodeGenModule &CGM, 96806c3fb27SDimitry Andric AArch64ABIKind K) { 96906c3fb27SDimitry Andric return std::make_unique<WindowsAArch64TargetCodeGenInfo>(CGM.getTypes(), K); 97006c3fb27SDimitry Andric } 971