diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -3394,6 +3394,7 @@ CXCallingConv_PreserveMost = 14, CXCallingConv_PreserveAll = 15, CXCallingConv_AArch64VectorCall = 16, + CXCallingConv_AArch64Darwin = 17, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -1477,6 +1477,12 @@ let Documentation = [MSABIDocs]; } +def DarwinABI : DeclOrTypeAttr { + let Spellings = [GCC<"darwin_abi">]; +// let Subjects = [Function, ObjCMethod]; + let Documentation = [DarwinABIDocs]; +} + def MSP430Interrupt : InheritableAttr, TargetSpecificAttr { // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's // and AnyX86Interrupt's spellings must match. diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2252,6 +2252,15 @@ }]; } +def DarwinABIDocs : Documentation { + let Category = DocCatCallingConvs; + let Content = [{ +On Linux ARM64 targets, this attribute changes the calling convention of +a function to match the default convention used on Apple ARM64. This +attribute has no effect on Apple targets or non-Linux ARM64 targets. + }]; +} + def StdCallDocs : Documentation { let Category = DocCatCallingConvs; let Content = [{ diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -268,24 +268,25 @@ /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { - CC_C, // __attribute__((cdecl)) - CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall, // __attribute__((fastcall)) - CC_X86ThisCall, // __attribute__((thiscall)) - CC_X86VectorCall, // __attribute__((vectorcall)) - CC_X86Pascal, // __attribute__((pascal)) - CC_Win64, // __attribute__((ms_abi)) - CC_X86_64SysV, // __attribute__((sysv_abi)) - CC_X86RegCall, // __attribute__((regcall)) - CC_AAPCS, // __attribute__((pcs("aapcs"))) - CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) - CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) - CC_SpirFunction, // default for OpenCL functions on SPIR target - CC_OpenCLKernel, // inferred for OpenCL kernels - CC_Swift, // __attribute__((swiftcall)) - CC_PreserveMost, // __attribute__((preserve_most)) - CC_PreserveAll, // __attribute__((preserve_all)) + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86VectorCall, // __attribute__((vectorcall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_Win64, // __attribute__((ms_abi)) + CC_X86_64SysV, // __attribute__((sysv_abi)) + CC_X86RegCall, // __attribute__((regcall)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + CC_SpirFunction, // default for OpenCL functions on SPIR target + CC_OpenCLKernel, // inferred for OpenCL kernels + CC_Swift, // __attribute__((swiftcall)) + CC_PreserveMost, // __attribute__((preserve_most)) + CC_PreserveAll, // __attribute__((preserve_all)) CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) + CC_AArch64Darwin, // __attribute__((darwin_abi)) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2900,6 +2900,8 @@ return "sysv_abi"; case CC_Win64: return "ms_abi"; + case CC_AArch64Darwin: + return "darwin_abi"; case CC_Swift: return "swiftcall"; } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3121,6 +3121,8 @@ case CC_X86Pascal: return "pascal"; case CC_X86VectorCall: return "vectorcall"; case CC_Win64: return "ms_abi"; + case CC_AArch64Darwin: + return "darwin_abi"; case CC_X86_64SysV: return "sysv_abi"; case CC_X86RegCall : return "regcall"; case CC_AAPCS: return "aapcs"; @@ -3548,6 +3550,7 @@ case attr::AArch64VectorPcs: case attr::Pascal: case attr::MSABI: + case attr::DarwinABI: case attr::SysVABI: case attr::IntelOclBicc: case attr::PreserveMost: diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -957,6 +957,9 @@ case CC_Win64: OS << " __attribute__((ms_abi))"; break; + case CC_AArch64Darwin: + OS << " __attribute__((darwin_abi))"; + break; case CC_X86_64SysV: OS << " __attribute__((sysv_abi))"; break; @@ -1640,6 +1643,9 @@ case attr::VectorCall: OS << "vectorcall"; break; case attr::Pascal: OS << "pascal"; break; case attr::MSABI: OS << "ms_abi"; break; + case attr::DarwinABI: + OS << "darwin_abi"; + break; case attr::SysVABI: OS << "sysv_abi"; break; case attr::RegCall: OS << "regcall"; break; case attr::Pcs: { diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -513,6 +513,7 @@ case CC_PreserveAll: case CC_OpenCLKernel: case CC_AArch64VectorCall: + case CC_AArch64Darwin: case CC_Win64: return CCCR_OK; default: diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -50,6 +50,8 @@ case CC_X86FastCall: return llvm::CallingConv::X86_FastCall; case CC_X86RegCall: return llvm::CallingConv::X86_RegCall; case CC_X86ThisCall: return llvm::CallingConv::X86_ThisCall; + case CC_AArch64Darwin: + return llvm::CallingConv::AArch64Darwin; case CC_Win64: return llvm::CallingConv::Win64; case CC_X86_64SysV: return llvm::CallingConv::X86_64_SysV; case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS; @@ -198,7 +200,8 @@ FTP); } -static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) { +static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows, + bool IsDarwin) { // Set the appropriate calling convention for the Function. if (D->hasAttr()) return CC_X86StdCall; @@ -230,6 +233,9 @@ if (D->hasAttr()) return IsWindows ? CC_C : CC_Win64; + if (D->hasAttr()) + return IsDarwin ? CC_C : CC_AArch64Darwin; + if (D->hasAttr()) return IsWindows ? CC_X86_64SysV : CC_C; @@ -485,7 +491,9 @@ FunctionType::ExtInfo einfo; bool IsWindows = getContext().getTargetInfo().getTriple().isOSWindows(); - einfo = einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows)); + bool IsDarwin = getContext().getTargetInfo().getTriple().isOSDarwin(); + einfo = einfo.withCallingConv( + getCallingConventionForDecl(MD, IsWindows, IsDarwin)); if (getContext().getLangOpts().ObjCAutoRefCount && MD->hasAttr()) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1230,6 +1230,8 @@ return llvm::dwarf::DW_CC_BORLAND_pascal; case CC_Win64: return llvm::dwarf::DW_CC_LLVM_Win64; + case CC_AArch64Darwin: + return llvm::dwarf::DW_CC_LLVM_AArch64Darwin; case CC_X86_64SysV: return llvm::dwarf::DW_CC_LLVM_X86_64SysV; case CC_AAPCS: diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -65,6 +65,20 @@ UseARMGuardVarABI(UseARMGuardVarABI), Use32BitVTableOffsetABI(false) { } + bool HasThisReturn(GlobalDecl GD) const override { + // Returns true if AArch64 Darwin ABI is explicitly used. + const bool IsCtorOrDtor = (isa(GD.getDecl()) || + (isa(GD.getDecl()) && + GD.getDtorType() != Dtor_Deleting)); + if (!IsCtorOrDtor) { + return false; + } + auto *FTy = + cast(GD.getDecl())->getType()->getAs(); + const auto FCC = FTy->getCallConv(); + return FCC == CallingConv::CC_AArch64Darwin; + } + bool classifyReturnType(CGFunctionInfo &FI) const override; RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override { diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -5446,9 +5446,16 @@ private: ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == DarwinPCS; } + bool isDarwinPCS(const unsigned CConv) const { + return isDarwinPCS() || CConv == llvm::CallingConv::AArch64Darwin; + } + bool isDarwinPCS(CGFunctionInfo const &FI) const { + return isDarwinPCS(FI.getCallingConvention()); + } - ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic, + unsigned CConv) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned CConv) const; ABIArgInfo coerceIllegalVector(QualType Ty) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, @@ -5457,12 +5464,13 @@ bool isIllegalVectorType(QualType Ty) const; void computeInfo(CGFunctionInfo &FI) const override { + const unsigned CConv = FI.getCallingConvention(); if (!::classifyReturnType(getCXXABI(), FI, *this)) FI.getReturnInfo() = - classifyReturnType(FI.getReturnType(), FI.isVariadic()); + classifyReturnType(FI.getReturnType(), FI.isVariadic(), CConv); for (auto &it : FI.arguments()) - it.info = classifyArgumentType(it.type); + it.info = classifyArgumentType(it.type, CConv); } Address EmitDarwinVAArg(Address VAListAddr, QualType Ty, @@ -5660,7 +5668,8 @@ return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty, + unsigned CConv) const { Ty = useFirstFieldIfTransparentUnion(Ty); // Handle illegal vector types here. @@ -5676,7 +5685,7 @@ if (EIT->getNumBits() > 128) return getNaturalAlignIndirect(Ty); - return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() + return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS(CConv) ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } @@ -5693,7 +5702,7 @@ uint64_t Size = getContext().getTypeSize(Ty); bool IsEmpty = isEmptyRecord(getContext(), Ty, true); if (IsEmpty || Size == 0) { - if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS()) + if (!getContext().getLangOpts().CPlusPlus || isDarwinPCS(CConv)) return ABIArgInfo::getIgnore(); // GNU C mode. The only argument that gets ignored is an empty one with size @@ -5739,8 +5748,8 @@ return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, - bool IsVariadic) const { +ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, bool IsVariadic, + unsigned CConv) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -5763,7 +5772,7 @@ if (EIT->getNumBits() > 128) return getNaturalAlignIndirect(RetTy); - return (isPromotableIntegerTypeForABI(RetTy) && isDarwinPCS() + return (isPromotableIntegerTypeForABI(RetTy) && isDarwinPCS(CConv) ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } @@ -5866,7 +5875,7 @@ Address AArch64ABIInfo::EmitAAPCSVAArg(Address VAListAddr, QualType Ty, CodeGenFunction &CGF) const { - ABIArgInfo AI = classifyArgumentType(Ty); + ABIArgInfo AI = classifyArgumentType(Ty, llvm::CallingConv::C); bool IsIndirect = AI.isIndirect(); llvm::Type *BaseTy = CGF.ConvertType(Ty); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -5612,6 +5612,7 @@ bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 || TT.getArch() == llvm::Triple::aarch64_32); bool IsWindows = TT.isOSWindows(); + bool IsLinux = TT.isOSLinux(); bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; if (IsX64 || IsAArch64) { CallingConv CC = CC_C; @@ -5627,8 +5628,10 @@ // On x64 Windows, don't allow this in System V ABI functions. // (Yes, that means there's no corresponding way to support variadic // System V ABI functions on Windows.) + // On Apple ARM64 ABI functions, only allow this on AArch64/Unix. if ((IsWindows && CC == CC_X86_64SysV) || - (!IsWindows && CC == CC_Win64)) + (!IsWindows && CC == CC_Win64) || + (!IsLinux && CC == CC_AArch64Darwin)) return S.Diag(Fn->getBeginLoc(), diag::err_va_start_used_in_wrong_abi_function) << !IsWindows; diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4465,6 +4465,9 @@ case ParsedAttr::AT_MSABI: D->addAttr(::new (S.Context) MSABIAttr(S.Context, AL)); return; + case ParsedAttr::AT_DarwinABI: + D->addAttr(::new (S.Context) DarwinABIAttr(S.Context, AL)); + return; case ParsedAttr::AT_SysVABI: D->addAttr(::new (S.Context) SysVABIAttr(S.Context, AL)); return; @@ -4633,6 +4636,10 @@ CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_Win64; break; + case ParsedAttr::AT_DarwinABI: + CC = Context.getTargetInfo().getTriple().isOSDarwin() ? CC_C + : CC_AArch64Darwin; + break; case ParsedAttr::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : CC_C; @@ -7742,6 +7749,7 @@ case ParsedAttr::AT_SwiftCall: case ParsedAttr::AT_VectorCall: case ParsedAttr::AT_MSABI: + case ParsedAttr::AT_DarwinABI: case ParsedAttr::AT_SysVABI: case ParsedAttr::AT_Pcs: case ParsedAttr::AT_IntelOclBicc: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -120,6 +120,7 @@ case ParsedAttr::AT_VectorCall: \ case ParsedAttr::AT_AArch64VectorPcs: \ case ParsedAttr::AT_MSABI: \ + case ParsedAttr::AT_DarwinABI: \ case ParsedAttr::AT_SysVABI: \ case ParsedAttr::AT_Pcs: \ case ParsedAttr::AT_IntelOclBicc: \ @@ -7301,6 +7302,8 @@ return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_MSABI: return createSimpleAttr(Ctx, Attr); + case ParsedAttr::AT_DarwinABI: + return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_SysVABI: return createSimpleAttr(Ctx, Attr); case ParsedAttr::AT_PreserveMost: diff --git a/clang/test/CodeGen/darwin_abi.c b/clang/test/CodeGen/darwin_abi.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/darwin_abi.c @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple aarch64-pc-linux %s -emit-llvm -o - |FileCheck %s +// Checks that correct LLVM IR is generated for functions that target +// the Darwin AArch64 ABI under Linux/AArch64. What we check: +// * sext/zext on return values and arguments +// * va_list forwarding from Darwin to Linux support + +// CHECK: define aarch64_darwincc signext i16 @f1(i16 signext +__attribute__((darwin_abi)) short f1(short a) { + return a + 1; +} + +// CHECK: define aarch64_darwincc zeroext i16 @f2(i16 zeroext +__attribute__((darwin_abi)) unsigned short f2(unsigned short a) { + return a + 1; +} + +// CHECK: define aarch64_darwincc void @foo(i32 %n, ...) +// CHECK: call void @llvm.va_start +void vfoo(int n, __builtin_va_list *va); +__attribute((darwin_abi)) void foo(int n, ...) { + __builtin_va_list va; + __builtin_va_start(va, n); + vfoo(n, &va); + __builtin_va_end(va); +} diff --git a/clang/test/CodeGen/darwin_abi_empty_structs.cpp b/clang/test/CodeGen/darwin_abi_empty_structs.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/darwin_abi_empty_structs.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -o - -O1 -triple aarch64-pc-linux | FileCheck %s +// Verify that "when passing parameters to a function, Apple platforms ignore +// empty structures unless those structures have a nontrivial destructor or +// copy constructor." when using darwin_abi + +struct Empty {}; + +__attribute__((darwin_abi)) void foo(int n, Empty E); +// CHECK: @_Z3bari(i32 %[[ARG:[[:alnum:]_]+]]) +void bar(int n) { + // CHECK: call aarch64_darwincc void @_Z3fooi5Empty(i32 %[[ARG]]) + return foo(n, Empty{}); +} + +// CHECK: declare aarch64_darwincc void @_Z3fooi5Empty(i32) diff --git a/clang/test/CodeGen/darwin_abi_vaarg.c b/clang/test/CodeGen/darwin_abi_vaarg.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/darwin_abi_vaarg.c @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple aarch64-pc-linux -emit-llvm %s -o - |FileCheck %s +// Check that va_arg used inside a function with the darwin_abi attribute still +// uses the Linux ABI lowering. + +// CHECK: define internal aarch64_darwincc i32 @vfoo(i32 %n, %struct.__va_list* %[[VA:[[:alnum:]_]+]]) +// CHECK: getelementptr inbounds %struct.__va_list, %struct.__va_list* %[[VA]], i32 0, i32 3 +__attribute__((darwin_abi, noinline)) static int vfoo(int n, __builtin_va_list va) { + int res = 0; + for (int i = 0; i < n; ++i) { + res += __builtin_va_arg(va, int); + } + return res; +} + +int foo(int n, ...) { + __builtin_va_list va; + __builtin_va_start(va, n); + const int res = vfoo(n, va); + __builtin_va_end(va); + return res; +} diff --git a/clang/test/CodeGen/debug-info-cc.c b/clang/test/CodeGen/debug-info-cc.c --- a/clang/test/CodeGen/debug-info-cc.c +++ b/clang/test/CodeGen/debug-info-cc.c @@ -2,26 +2,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-windows-msvc -o - -emit-llvm -debug-info-kind=limited %s | FileCheck %s --check-prefix=WINDOWS // RUN: %clang_cc1 -triple i386-pc-linux-gnu -o - -emit-llvm -debug-info-kind=limited %s | FileCheck %s --check-prefix=LINUX32 // RUN: %clang_cc1 -triple armv7--linux-gnueabihf -o - -emit-llvm -debug-info-kind=limited %s | FileCheck %s --check-prefix=ARM - -// enum CallingConv { -// CC_C, // __attribute__((cdecl)) -// CC_X86StdCall, // __attribute__((stdcall)) -// CC_X86FastCall, // __attribute__((fastcall)) -// CC_X86ThisCall, // __attribute__((thiscall)) -// CC_X86VectorCall, // __attribute__((vectorcall)) -// CC_X86Pascal, // __attribute__((pascal)) -// CC_Win64, // __attribute__((ms_abi)) -// CC_X86_64SysV, // __attribute__((sysv_abi)) -// CC_X86RegCall, // __attribute__((regcall)) -// CC_AAPCS, // __attribute__((pcs("aapcs"))) -// CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) -// CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) -// CC_SpirFunction, // default for OpenCL functions on SPIR target -// CC_OpenCLKernel, // inferred for OpenCL kernels -// CC_Swift, // __attribute__((swiftcall)) -// CC_PreserveMost, // __attribute__((preserve_most)) -// CC_PreserveAll, // __attribute__((preserve_all)) -// }; +// RUN: %clang_cc1 -triple aarch64-pc-linux -o - -emit-llvm -debug-info-kind=limited %s | FileCheck %s --check-prefix=AARCH64 #ifdef __x86_64__ @@ -118,3 +99,11 @@ return a+b; } #endif + +#if defined(__aarch64__) && defined(__linux__) +// AARCH64: !DISubprogram({{.*}}"add_darwinabi", {{.*}}type: ![[FTY:[0-9]+]] +// AARCH64: ![[FTY]] = !DISubroutineType({{.*}}cc: DW_CC_LLVM_AArch64Darwin, +__attribute__((darwin_abi)) int add_darwinabi(int a, int b) { + return a + b; +} +#endif diff --git a/clang/test/CodeGenCXX/darwinabi-returnthis.cpp b/clang/test/CodeGenCXX/darwinabi-returnthis.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/darwinabi-returnthis.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple aarch64-pc-linux-gnu -mconstructor-aliases %s -emit-llvm -O1 -o - | FileCheck %s + +struct A { + __attribute__((darwin_abi)) A(); + __attribute__((darwin_abi)) ~A(); +}; + +// CHECK: define aarch64_darwincc %struct.A* @_ZN1AC2Ev(%struct.A* readnone returned %[[THIS:.*]]) +A::A() { + // CHECK: ret %struct.A* %[[THIS]] +} + +// CHECK: define aarch64_darwincc %struct.A* @_ZN1AD2Ev(%struct.A* readnone returned %[[THIS:.*]]) +A::~A() { + // CHECK: ret %struct.A* %[[THIS]] +} diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -658,6 +658,7 @@ TCALLINGCONV(X86RegCall); TCALLINGCONV(X86VectorCall); TCALLINGCONV(AArch64VectorCall); + TCALLINGCONV(AArch64Darwin); TCALLINGCONV(Win64); TCALLINGCONV(X86_64SysV); TCALLINGCONV(AAPCS); diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -788,6 +788,7 @@ HANDLE_DW_CC(0xc9, LLVM_PreserveMost) HANDLE_DW_CC(0xca, LLVM_PreserveAll) HANDLE_DW_CC(0xcb, LLVM_X86RegCall) +HANDLE_DW_CC(0xcc, LLVM_AArch64Darwin) // From GCC source code (include/dwarf2.h): This DW_CC_ value is not currently // generated by any toolchain. It is used internally to GDB to indicate OpenCL C // functions that have been compiled with the IBM XL C for OpenCL compiler and use diff --git a/llvm/include/llvm/IR/CallingConv.h b/llvm/include/llvm/IR/CallingConv.h --- a/llvm/include/llvm/IR/CallingConv.h +++ b/llvm/include/llvm/IR/CallingConv.h @@ -241,6 +241,8 @@ /// The remainder matches the regular calling convention. WASM_EmscriptenInvoke = 99, + AArch64Darwin = 100, + /// The highest possible calling convention ID. Must be some 2^k - 1. MaxID = 1023 }; diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -605,6 +605,7 @@ KEYWORD(intel_ocl_bicc); KEYWORD(x86_64_sysvcc); KEYWORD(win64cc); + KEYWORD(aarch64_darwincc); KEYWORD(x86_regcallcc); KEYWORD(webkit_jscc); KEYWORD(swiftcc); diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2014,6 +2014,7 @@ /// ::= 'spir_kernel' /// ::= 'x86_64_sysvcc' /// ::= 'win64cc' +/// ::= 'aarch64_darwincc' /// ::= 'webkit_jscc' /// ::= 'anyregcc' /// ::= 'preserve_mostcc' @@ -2054,35 +2055,96 @@ case lltok::kw_aarch64_sve_vector_pcs: CC = CallingConv::AArch64_SVE_VectorCall; break; - case lltok::kw_msp430_intrcc: CC = CallingConv::MSP430_INTR; break; - case lltok::kw_avr_intrcc: CC = CallingConv::AVR_INTR; break; - case lltok::kw_avr_signalcc: CC = CallingConv::AVR_SIGNAL; break; - case lltok::kw_ptx_kernel: CC = CallingConv::PTX_Kernel; break; - case lltok::kw_ptx_device: CC = CallingConv::PTX_Device; break; - case lltok::kw_spir_kernel: CC = CallingConv::SPIR_KERNEL; break; - case lltok::kw_spir_func: CC = CallingConv::SPIR_FUNC; break; - case lltok::kw_intel_ocl_bicc: CC = CallingConv::Intel_OCL_BI; break; - case lltok::kw_x86_64_sysvcc: CC = CallingConv::X86_64_SysV; break; - case lltok::kw_win64cc: CC = CallingConv::Win64; break; - case lltok::kw_webkit_jscc: CC = CallingConv::WebKit_JS; break; - case lltok::kw_anyregcc: CC = CallingConv::AnyReg; break; - case lltok::kw_preserve_mostcc:CC = CallingConv::PreserveMost; break; - case lltok::kw_preserve_allcc: CC = CallingConv::PreserveAll; break; - case lltok::kw_ghccc: CC = CallingConv::GHC; break; - case lltok::kw_swiftcc: CC = CallingConv::Swift; break; - case lltok::kw_x86_intrcc: CC = CallingConv::X86_INTR; break; - case lltok::kw_hhvmcc: CC = CallingConv::HHVM; break; - case lltok::kw_hhvm_ccc: CC = CallingConv::HHVM_C; break; - case lltok::kw_cxx_fast_tlscc: CC = CallingConv::CXX_FAST_TLS; break; - case lltok::kw_amdgpu_vs: CC = CallingConv::AMDGPU_VS; break; - case lltok::kw_amdgpu_ls: CC = CallingConv::AMDGPU_LS; break; - case lltok::kw_amdgpu_hs: CC = CallingConv::AMDGPU_HS; break; - case lltok::kw_amdgpu_es: CC = CallingConv::AMDGPU_ES; break; - case lltok::kw_amdgpu_gs: CC = CallingConv::AMDGPU_GS; break; - case lltok::kw_amdgpu_ps: CC = CallingConv::AMDGPU_PS; break; - case lltok::kw_amdgpu_cs: CC = CallingConv::AMDGPU_CS; break; - case lltok::kw_amdgpu_kernel: CC = CallingConv::AMDGPU_KERNEL; break; - case lltok::kw_tailcc: CC = CallingConv::Tail; break; + case lltok::kw_msp430_intrcc: + CC = CallingConv::MSP430_INTR; + break; + case lltok::kw_avr_intrcc: + CC = CallingConv::AVR_INTR; + break; + case lltok::kw_avr_signalcc: + CC = CallingConv::AVR_SIGNAL; + break; + case lltok::kw_ptx_kernel: + CC = CallingConv::PTX_Kernel; + break; + case lltok::kw_ptx_device: + CC = CallingConv::PTX_Device; + break; + case lltok::kw_spir_kernel: + CC = CallingConv::SPIR_KERNEL; + break; + case lltok::kw_spir_func: + CC = CallingConv::SPIR_FUNC; + break; + case lltok::kw_intel_ocl_bicc: + CC = CallingConv::Intel_OCL_BI; + break; + case lltok::kw_x86_64_sysvcc: + CC = CallingConv::X86_64_SysV; + break; + case lltok::kw_win64cc: + CC = CallingConv::Win64; + break; + case lltok::kw_aarch64_darwincc: + CC = CallingConv::AArch64Darwin; + break; + case lltok::kw_webkit_jscc: + CC = CallingConv::WebKit_JS; + break; + case lltok::kw_anyregcc: + CC = CallingConv::AnyReg; + break; + case lltok::kw_preserve_mostcc: + CC = CallingConv::PreserveMost; + break; + case lltok::kw_preserve_allcc: + CC = CallingConv::PreserveAll; + break; + case lltok::kw_ghccc: + CC = CallingConv::GHC; + break; + case lltok::kw_swiftcc: + CC = CallingConv::Swift; + break; + case lltok::kw_x86_intrcc: + CC = CallingConv::X86_INTR; + break; + case lltok::kw_hhvmcc: + CC = CallingConv::HHVM; + break; + case lltok::kw_hhvm_ccc: + CC = CallingConv::HHVM_C; + break; + case lltok::kw_cxx_fast_tlscc: + CC = CallingConv::CXX_FAST_TLS; + break; + case lltok::kw_amdgpu_vs: + CC = CallingConv::AMDGPU_VS; + break; + case lltok::kw_amdgpu_ls: + CC = CallingConv::AMDGPU_LS; + break; + case lltok::kw_amdgpu_hs: + CC = CallingConv::AMDGPU_HS; + break; + case lltok::kw_amdgpu_es: + CC = CallingConv::AMDGPU_ES; + break; + case lltok::kw_amdgpu_gs: + CC = CallingConv::AMDGPU_GS; + break; + case lltok::kw_amdgpu_ps: + CC = CallingConv::AMDGPU_PS; + break; + case lltok::kw_amdgpu_cs: + CC = CallingConv::AMDGPU_CS; + break; + case lltok::kw_amdgpu_kernel: + CC = CallingConv::AMDGPU_KERNEL; + break; + case lltok::kw_tailcc: + CC = CallingConv::Tail; + break; case lltok::kw_cc: { Lex.Lex(); return ParseUInt32(CC); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -152,6 +152,7 @@ kw_spir_func, kw_x86_64_sysvcc, kw_win64cc, + kw_aarch64_darwincc, kw_webkit_jscc, kw_anyregcc, kw_swiftcc, diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -374,6 +374,9 @@ case CallingConv::PTX_Device: Out << "ptx_device"; break; case CallingConv::X86_64_SysV: Out << "x86_64_sysvcc"; break; case CallingConv::Win64: Out << "win64cc"; break; + case CallingConv::AArch64Darwin: + Out << "aarch64_darwincc"; + break; case CallingConv::SPIR_FUNC: Out << "spir_func"; break; case CallingConv::SPIR_KERNEL: Out << "spir_kernel"; break; case CallingConv::Swift: Out << "swiftcc"; break; diff --git a/llvm/lib/Target/AArch64/AArch64CallingConvention.cpp b/llvm/lib/Target/AArch64/AArch64CallingConvention.cpp --- a/llvm/lib/Target/AArch64/AArch64CallingConvention.cpp +++ b/llvm/lib/Target/AArch64/AArch64CallingConvention.cpp @@ -145,7 +145,9 @@ for (auto Reg : RegList) State.AllocateReg(Reg); - const Align SlotAlign = Subtarget.isTargetDarwin() ? Align(1) : Align(8); + const auto FCC = State.getMachineFunction().getFunction().getCallingConv(); + const Align SlotAlign = + Subtarget.isCallingConvDarwin(FCC) ? Align(1) : Align(8); return finishStackBlock(PendingMembers, LocVT, ArgFlags, State, SlotAlign); } diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -350,7 +350,8 @@ return CC_AArch64_GHC; if (CC == CallingConv::CFGuard_Check) return CC_AArch64_Win64_CFGuard_Check; - return Subtarget->isTargetDarwin() ? CC_AArch64_DarwinPCS : CC_AArch64_AAPCS; + return Subtarget->isCallingConvDarwin(CC) ? CC_AArch64_DarwinPCS + : CC_AArch64_AAPCS; } unsigned AArch64FastISel::fastMaterializeAlloca(const AllocaInst *AI) { diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -873,6 +873,7 @@ SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerAAPCS_VASTART(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerAAPCSFromDarwin_VASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerDarwin_VASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerWin64_VASTART(SDValue Op, SelectionDAG &DAG) const; SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const; diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -4079,6 +4079,11 @@ case CallingConv::AArch64_VectorCall: case CallingConv::AArch64_SVE_VectorCall: return CC_AArch64_AAPCS; + case CallingConv::AArch64Darwin: + if (!IsVarArg) + return CC_AArch64_DarwinPCS; + return Subtarget->isTargetILP32() ? CC_AArch64_DarwinPCS_ILP32_VarArg + : CC_AArch64_DarwinPCS_VarArg; } } @@ -4094,7 +4099,9 @@ SelectionDAG &DAG, SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineFrameInfo &MFI = MF.getFrameInfo(); - bool IsWin64 = Subtarget->isCallingConvWin64(MF.getFunction().getCallingConv()); + const auto FCC = MF.getFunction().getCallingConv(); + const bool IsWin64 = Subtarget->isCallingConvWin64(FCC); + const bool IsDarwin = Subtarget->isCallingConvDarwin(FCC); // Assign locations to all of the incoming arguments. SmallVector ArgLocs; @@ -4278,7 +4285,7 @@ // varargs AArch64FunctionInfo *FuncInfo = MF.getInfo(); if (isVarArg) { - if (!Subtarget->isTargetDarwin() || IsWin64) { + if (!IsDarwin || IsWin64) { // The AAPCS variadic function ABI is identical to the non-variadic // one. As a result there may be more arguments in registers and we should // save them for future reference. @@ -6429,6 +6436,62 @@ return getAddr(BA, DAG); } +SDValue +AArch64TargetLowering::LowerAAPCSFromDarwin_VASTART(SDValue Op, + SelectionDAG &DAG) const { + // Linux/AArch64 va_list structure is (AArch64 Procedure Call Standard, + // section B.3.): + // typedef struct { + // void *stack; + // void *gr_top; + // void *vr_top; + // int gr_offs; + // int vr_offs; + // } va_list; + // Darwin/AArch64 va_list is just a pointer to the stack, as all variadic + // arguments are pushed to the stack. + // So we basically set stack as LowerDarwin_VASTART would do, and then set + // the gr_offs & vr_offs fields to zero. This will enforce AAPCS functions + // processing va_list objects to only get objects from the stack. + + MachineFunction &MF = DAG.getMachineFunction(); + AArch64FunctionInfo *FuncInfo = MF.getInfo(); + auto PtrVT = getPointerTy(DAG.getDataLayout()); + SDLoc DL(Op); + + SDValue Chain = Op.getOperand(0); + SDValue VAList = Op.getOperand(1); + const Value *SV = cast(Op.getOperand(2))->getValue(); + SmallVector MemOps; + + // void *__stack at offset 0 + SDValue Stack = DAG.getFrameIndex(FuncInfo->getVarArgsStackIndex(), PtrVT); + MemOps.push_back( + DAG.getStore(Chain, DL, Stack, VAList, MachinePointerInfo(SV), Align(8))); + + // void *__gr_top at offset 8. Won't be used. + const int GPRSize = 0; + + // void *__vr_top at offset 16. Won't be used. + const int FPRSize = 0; + + // int __gr_offs at offset 24 + SDValue GROffsAddr = + DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(24, DL, PtrVT)); + MemOps.push_back( + DAG.getStore(Chain, DL, DAG.getConstant(-GPRSize, DL, MVT::i32), + GROffsAddr, MachinePointerInfo(SV, 24), Align(4))); + + // int __vr_offs at offset 28 + SDValue VROffsAddr = + DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getConstant(28, DL, PtrVT)); + MemOps.push_back( + DAG.getStore(Chain, DL, DAG.getConstant(-FPRSize, DL, MVT::i32), + VROffsAddr, MachinePointerInfo(SV, 28), Align(4))); + + return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps); +} + SDValue AArch64TargetLowering::LowerDarwin_VASTART(SDValue Op, SelectionDAG &DAG) const { AArch64FunctionInfo *FuncInfo = @@ -6529,11 +6592,19 @@ SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); - if (Subtarget->isCallingConvWin64(MF.getFunction().getCallingConv())) + const auto FCC = MF.getFunction().getCallingConv(); + if (Subtarget->isCallingConvWin64(FCC)) return LowerWin64_VASTART(Op, DAG); - else if (Subtarget->isTargetDarwin()) - return LowerDarwin_VASTART(Op, DAG); - else + else if (Subtarget->isCallingConvDarwin(FCC)) { + if (Subtarget->isTargetDarwin()) { + return LowerDarwin_VASTART(Op, DAG); + } + if (!Subtarget->isTargetWindows()) { + return LowerAAPCSFromDarwin_VASTART(Op, DAG); + } + report_fatal_error("can't lower Darwin vaarg if target OS isn't Darwin or " + "has an official AAPCS ABI (e.g. Linux)"); + } else return LowerAAPCS_VASTART(Op, DAG); } diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp @@ -74,7 +74,6 @@ const MCPhysReg * AArch64RegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const { assert(MF && "Invalid MachineFunction pointer."); - if (MF->getFunction().getCallingConv() == CallingConv::GHC) // GHC set of callee saved regs is empty as all those regs are // used for passing STG regs around @@ -87,22 +86,26 @@ if (MF->getSubtarget().isTargetDarwin()) return getDarwinCalleeSavedRegs(MF); - if (MF->getFunction().getCallingConv() == CallingConv::CFGuard_Check) + const auto FCC = MF->getFunction().getCallingConv(); + if (FCC == CallingConv::AArch64Darwin) { + return CSR_Darwin_AArch64_AAPCS_SaveList; + } + if (FCC == CallingConv::CFGuard_Check) return CSR_Win_AArch64_CFGuard_Check_SaveList; if (MF->getSubtarget().isTargetWindows()) return CSR_Win_AArch64_AAPCS_SaveList; - if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall) + if (FCC == CallingConv::AArch64_VectorCall) return CSR_AArch64_AAVPCS_SaveList; - if (MF->getFunction().getCallingConv() == CallingConv::AArch64_SVE_VectorCall) + if (FCC == CallingConv::AArch64_SVE_VectorCall) return CSR_AArch64_SVE_AAPCS_SaveList; if (MF->getSubtarget().getTargetLowering() ->supportSwiftError() && MF->getFunction().getAttributes().hasAttrSomewhere( Attribute::SwiftError)) return CSR_AArch64_AAPCS_SwiftError_SaveList; - if (MF->getFunction().getCallingConv() == CallingConv::PreserveMost) + if (FCC == CallingConv::PreserveMost) return CSR_AArch64_RT_MostRegs_SaveList; - if (MF->getFunction().getCallingConv() == CallingConv::Win64) + if (FCC == CallingConv::Win64) // This is for OSes other than Windows; Windows is a separate case further // above. return CSR_AArch64_AAPCS_X18_SaveList; @@ -221,6 +224,9 @@ return getDarwinCallPreservedMask(MF, CC); } + if (CC == CallingConv::AArch64Darwin) { + return CSR_Darwin_AArch64_AAPCS_RegMask; + } if (CC == CallingConv::AArch64_VectorCall) return SCS ? CSR_AArch64_AAVPCS_SCS_RegMask : CSR_AArch64_AAVPCS_RegMask; if (CC == CallingConv::AArch64_SVE_VectorCall) @@ -291,7 +297,7 @@ // In case that the calling convention does not use the same register for // both, the function should return NULL (does not currently apply) assert(CC != CallingConv::GHC && "should not be GHC calling convention."); - if (MF.getSubtarget().isTargetDarwin()) + if (MF.getSubtarget().isCallingConvDarwin(CC)) return CSR_Darwin_AArch64_AAPCS_ThisReturn_RegMask; return CSR_AArch64_AAPCS_ThisReturn_RegMask; } diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h --- a/llvm/lib/Target/AArch64/AArch64Subtarget.h +++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -549,6 +549,13 @@ } } + bool isCallingConvDarwin(CallingConv::ID CC) const { + if (CC == CallingConv::AArch64Darwin) { + return true; + } + return isTargetDarwin(); + } + void mirFileLoaded(MachineFunction &MF) const override; // Return the known range for the bit length of SVE data registers. A value diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -474,8 +474,8 @@ uint64_t StackOffset = Handler.StackUsed; if (F.isVarArg()) { auto &Subtarget = MF.getSubtarget(); - if (!Subtarget.isTargetDarwin()) { - // FIXME: we need to reimplement saveVarArgsRegisters from + if (!Subtarget.isCallingConvDarwin(MF.getFunction().getCallingConv())) { + // FIXME: we need to reimplement saveVarArgsRegisters from // AArch64ISelLowering. return false; } diff --git a/llvm/test/CodeGen/AArch64/darwin_abi.ll b/llvm/test/CodeGen/AArch64/darwin_abi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/darwin_abi.ll @@ -0,0 +1,29 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=aarch64-pc-linux | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-pc-linux" + +define dso_local aarch64_darwincc signext i16 @f1(i16 signext %a) local_unnamed_addr #0 { +; CHECK-LABEL: f1: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: add w8, w0, #1 // =1 +; CHECK-NEXT: sxth w0, w8 +; CHECK-NEXT: ret +entry: + %add = add i16 %a, 1 + ret i16 %add +} + +define dso_local aarch64_darwincc zeroext i16 @f2(i16 zeroext %a) local_unnamed_addr #0 { +; CHECK-LABEL: f2: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: add w8, w0, #1 // =1 +; CHECK-NEXT: and w0, w8, #0xffff +; CHECK-NEXT: ret +entry: + %add = add i16 %a, 1 + ret i16 %add +} + +attributes #0 = { norecurse nounwind readnone "disable-tail-calls"="false" "frame-pointer"="non-leaf" "target-cpu"="generic" } diff --git a/llvm/test/CodeGen/AArch64/darwin_abi_vararg.ll b/llvm/test/CodeGen/AArch64/darwin_abi_vararg.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/darwin_abi_vararg.ll @@ -0,0 +1,39 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=aarch64-pc-linux | FileCheck %s + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-pc-linux" + +%struct.__va_list = type { i8*, i8*, i8*, i32, i32 } + +define dso_local aarch64_darwincc void @foo(i32 %n, ...) local_unnamed_addr #0 { +; CHECK-LABEL: foo: +; CHECK: // %bb.0: // %entry +; CHECK-NEXT: sub sp, sp, #48 // =48 +; CHECK-NEXT: stp x29, x30, [sp, #32] // 16-byte Folded Spill +; CHECK-NEXT: add x29, sp, #32 // =32 +; CHECK-NEXT: add x8, x29, #16 // =16 +; CHECK-NEXT: mov x1, sp +; CHECK-NEXT: str xzr, [sp, #24] +; CHECK-NEXT: str x8, [sp] +; CHECK-NEXT: bl vfoo +; CHECK-NEXT: ldp x29, x30, [sp, #32] // 16-byte Folded Reload +; CHECK-NEXT: add sp, sp, #48 // =48 +; CHECK-NEXT: ret +entry: + %va = alloca %struct.__va_list, align 8 + %0 = bitcast %struct.__va_list* %va to i8* + call void @llvm.va_start(i8* nonnull %0) + call void @vfoo(i32 %n, %struct.__va_list* nonnull %va) #1 + call void @llvm.va_end(i8* nonnull %0) + ret void +} + +declare void @llvm.va_start(i8*) #1 + +declare dso_local void @vfoo(i32, %struct.__va_list*) local_unnamed_addr #0 + +declare void @llvm.va_end(i8*) #1 + +attributes #0 = { nounwind "disable-tail-calls"="false" "frame-pointer"="non-leaf" "target-cpu"="generic" } +attributes #1 = { nounwind }