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 @@ -1506,6 +1506,12 @@ let Documentation = [MSABIDocs]; } +def DarwinABI : DeclOrTypeAttr { + let Spellings = [Clang<"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 @@ -2321,6 +2321,40 @@ }]; } +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. + +The differences against the original ARM64 calling convention are `described by +Apple `_. + +Here is the list of what this attribute supports, quoting from the +aforementioned document: + +* targeting the Darwin AAPCS ABI for C functions, especially those with + variadic arguments. This means everything in section "Pass Arguments to + Functions Correctly" and "Update Code that Passes Arguments to Variadic + Functions", + +* "The ABI requires the complete object (C1) and base-object (C2) constructors + to return this to their callers. Similarly, the complete object (D1) and + base-object (D2) destructors return this. This behavior matches the ARM + 32-bit C++ ABI", + +* "When passing parameters to a function, Apple platforms ignore empty + structures unless those structures have a nontrivial destructor or copy + constructor. When passing such nontrivial structures, treat them as + aggregates with one byte member in the generic manner", + +* properly forwarding variadic arguments from a "darwin_abi function" to a + linux one using va_list. + + }]; +} + 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 @@ -269,6 +269,7 @@ 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 @@ -2902,6 +2902,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 @@ -3125,6 +3125,7 @@ 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"; @@ -3554,6 +3555,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 @@ -959,6 +959,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; @@ -1680,6 +1683,7 @@ 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 @@ -534,6 +534,7 @@ case CC_PreserveAll: case CC_OpenCLKernel: case CC_AArch64VectorCall: + case CC_AArch64Darwin: case CC_Win64: return CCCR_OK; default: @@ -805,6 +806,7 @@ case CC_Swift: case CC_Win64: return CCCR_OK; + case CC_AArch64Darwin: default: return CCCR_Warning; } 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 @@ -51,6 +51,7 @@ 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; @@ -200,7 +201,7 @@ } static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, - bool IsWindows) { + bool IsWindows, bool IsDarwin) { // Set the appropriate calling convention for the Function. if (D->hasAttr()) return CC_X86StdCall; @@ -232,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; @@ -487,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()) @@ -3896,8 +3902,9 @@ const auto *MD = Prototype.P.dyn_cast(); if (MD) { IsVariadic = MD->isVariadic(); - ExplicitCC = getCallingConventionForDecl( - MD, CGM.getTarget().getTriple().isOSWindows()); + llvm::Triple Triple = CGM.getTarget().getTriple(); + ExplicitCC = getCallingConventionForDecl(MD, Triple.isOSWindows(), + Triple.isOSDarwin()); ArgTypes.assign(MD->param_type_begin() + ParamsToSkip, MD->param_type_end()); } else { 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 @@ -1237,6 +1237,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,18 @@ UseARMGuardVarABI(UseARMGuardVarABI), Use32BitVTableOffsetABI(false) { } + bool HasThisReturn(GlobalDecl GD) const override { + // Returns true if AArch64 Darwin ABI is explicitly used. + bool IsCtorOrDtor = (isa(GD.getDecl()) || + (isa(GD.getDecl()) && + GD.getDtorType() != Dtor_Deleting)); + if (!IsCtorOrDtor) + return false; + const auto *FTy = + cast(GD.getDecl())->getType()->getAs(); + return FTy->getCallConv() == 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 @@ -5428,9 +5428,16 @@ private: ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == DarwinPCS; } + bool isDarwinPCS(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, @@ -5439,12 +5446,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, @@ -5647,7 +5655,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. @@ -5663,7 +5672,7 @@ if (EIT->getNumBits() > 128) return getNaturalAlignIndirect(Ty); - return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS() + return (isPromotableIntegerTypeForABI(Ty) && isDarwinPCS(CConv) ? ABIArgInfo::getExtend(Ty) : ABIArgInfo::getDirect()); } @@ -5680,7 +5689,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 @@ -5726,8 +5735,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(); @@ -5750,7 +5759,7 @@ if (EIT->getNumBits() > 128) return getNaturalAlignIndirect(RetTy); - return (isPromotableIntegerTypeForABI(RetTy) && isDarwinPCS() + return (isPromotableIntegerTypeForABI(RetTy) && isDarwinPCS(CConv) ? ABIArgInfo::getExtend(RetTy) : ABIArgInfo::getDirect()); } @@ -5853,7 +5862,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 @@ -5698,6 +5698,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; @@ -5713,8 +5714,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 @@ -4605,6 +4605,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; @@ -4773,6 +4776,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; @@ -7970,6 +7977,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: \ @@ -7326,6 +7327,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 the 'darwin_abi' attribute. + +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* {{.*}} %[[THIS:.*]]) +A::A() { + // CHECK: ret %struct.A* %[[THIS]] +} + +// CHECK: define aarch64_darwincc {{.*}} %struct.A* @_ZN1AD2Ev(%struct.A* {{.*}} %[[THIS:.*]]) +A::~A() { + // CHECK: ret %struct.A* %[[THIS]] +} diff --git a/clang/test/Sema/callingconv-darwin_abi.c b/clang/test/Sema/callingconv-darwin_abi.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/callingconv-darwin_abi.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-pc-linux-gnu %s + +void __attribute__((sysv_abi)) foo(void); +void (*pfoo)(void) = foo; // valid declaration + +void __attribute__((darwin_abi)) bar(void); +void (*pbar)(void) = bar; // expected-warning{{incompatible function pointer types}} +void(__attribute__((darwin_abi)) * pbar_valid)(void) = bar; // valid declaration + +void(__attribute__((darwin_abi)) * pfoo2)(void) = foo; // expected-warning{{incompatible function pointer types}} diff --git a/clang/test/Sema/darwin_abi-sysv_abi.c b/clang/test/Sema/darwin_abi-sysv_abi.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/darwin_abi-sysv_abi.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-pc-linux-gnu %s +// Based on ms_abi-sysv_abi.c + +// CC qualifier can be applied only to functions +int __attribute__((darwin_abi)) var1; // expected-warning{{'darwin_abi' only applies to function types; type here is 'int'}} +void __attribute__((darwin_abi)) foo(); // valid declaration + +// CC qualifier attribute does not take any argument +void __attribute__((darwin_abi("arg"))) foo0(void); // expected-error{{'darwin_abi' attribute takes no arguments}} + +// Different CC qualifiers are not compatible +void __attribute__((darwin_abi, sysv_abi)) foo1(void); // expected-error{{cdecl and darwin_abi attributes are not compatible}} +void __attribute__((darwin_abi)) foo2(); // expected-note{{previous declaration is here}} +void __attribute__((sysv_abi)) foo2(void); // expected-error{{function declared 'cdecl' here was previously declared 'darwin_abi'}} + +void bar(int i, int j) __attribute__((darwin_abi, cdecl)); // expected-error{{cdecl and darwin_abi attributes are not compatible}} diff --git a/clang/test/Sema/darwin_abi-win64.c b/clang/test/Sema/darwin_abi-win64.c new file mode 100644 --- /dev/null +++ b/clang/test/Sema/darwin_abi-win64.c @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -triple aarch64-unknown-windows-msvc %s + +void __attribute__((darwin_abi)) foo(void); // expected-warning{{'darwin_abi' calling convention is not supported for this target}} diff --git a/clang/test/Sema/no_callconv.cpp b/clang/test/Sema/no_callconv.cpp --- a/clang/test/Sema/no_callconv.cpp +++ b/clang/test/Sema/no_callconv.cpp @@ -9,6 +9,7 @@ void __attribute__((vectorcall)) funcA() {} // expected-error {{'vectorcall' calling convention is not supported for this target}} void __attribute__((regcall)) funcB() {} // expected-error {{'regcall' calling convention is not supported for this target}} void __attribute__((ms_abi)) funcH() {} // expected-error {{'ms_abi' calling convention is not supported for this target}} +void __attribute__((darwin_abi)) funcDW() {} // expected-error {{'darwin_abi' calling convention is not supported for this target}} void __attribute__((intel_ocl_bicc)) funcJ() {} // expected-error {{'intel_ocl_bicc' calling convention is not supported for this target}} void __attribute__((swiftcall)) funcK() {} // expected-error {{'swiftcall' calling convention is not supported for this target}} void __attribute__((pascal)) funcG() {} // expected-error {{'pascal' calling convention is not supported for this target}} @@ -38,6 +39,8 @@ void __attribute__((stdcall)) funcD() {} // expected-warning {{'stdcall' calling convention is not supported for this target}} void __attribute__((fastcall)) funcE() {} // expected-warning {{'fastcall' calling convention is not supported for this target}} void __attribute__((thiscall)) funcF() {} // expected-warning {{'thiscall' calling convention is not supported for this target}} +// darwin_abi is only supported for ARM64/Linux targets +void __attribute__((darwin_abi)) funcDW() {} // expected-warning {{'darwin_abi' calling convention is not supported for this target}} #endif void __attribute__((sysv_abi)) funcI() {} diff --git a/clang/test/Sema/varargs-aarch64.c b/clang/test/Sema/varargs-aarch64.c --- a/clang/test/Sema/varargs-aarch64.c +++ b/clang/test/Sema/varargs-aarch64.c @@ -9,3 +9,8 @@ __builtin_va_list ap; __builtin_va_start(ap, a); // expected-error {{'va_start' used in Win64 ABI function}} } + +void __attribute__((darwin_abi)) f3(int a, ...) { + __builtin_va_list ap; + __builtin_va_start(ap, a); // that is explicitely supported +} 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 @@ -244,6 +244,9 @@ /// Calling convention used for AMD graphics targets. AMDGPU_Gfx = 100, + /// The C convention as implemented on Darwin/AArch64. + AArch64Darwin = 101, + /// 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 @@ -606,6 +606,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 @@ -2072,6 +2072,7 @@ /// ::= 'spir_kernel' /// ::= 'x86_64_sysvcc' /// ::= 'win64cc' +/// ::= 'aarch64_darwincc' /// ::= 'webkit_jscc' /// ::= 'anyregcc' /// ::= 'preserve_mostcc' @@ -2108,10 +2109,9 @@ case lltok::kw_arm_apcscc: CC = CallingConv::ARM_APCS; break; case lltok::kw_arm_aapcscc: CC = CallingConv::ARM_AAPCS; break; case lltok::kw_arm_aapcs_vfpcc:CC = CallingConv::ARM_AAPCS_VFP; break; + case lltok::kw_aarch64_darwincc:CC = CallingConv::AArch64Darwin; break; case lltok::kw_aarch64_vector_pcs:CC = CallingConv::AArch64_VectorCall; break; - case lltok::kw_aarch64_sve_vector_pcs: - CC = CallingConv::AArch64_SVE_VectorCall; - break; + 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; 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 @@ -153,6 +153,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 @@ -375,9 +375,7 @@ case CallingConv::ARM_AAPCS: Out << "arm_aapcscc"; break; case CallingConv::ARM_AAPCS_VFP: Out << "arm_aapcs_vfpcc"; break; case CallingConv::AArch64_VectorCall: Out << "aarch64_vector_pcs"; break; - case CallingConv::AArch64_SVE_VectorCall: - Out << "aarch64_sve_vector_pcs"; - break; + case CallingConv::AArch64_SVE_VectorCall: Out << "aarch64_sve_vector_pcs"; break; case CallingConv::MSP430_INTR: Out << "msp430_intrcc"; break; case CallingConv::AVR_INTR: Out << "avr_intrcc "; break; case CallingConv::AVR_SIGNAL: Out << "avr_signalcc "; break; @@ -385,6 +383,7 @@ 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 @@ -197,7 +197,9 @@ 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 @@ -883,6 +883,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 @@ -4494,6 +4494,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; } } @@ -4509,7 +4514,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; @@ -4721,7 +4728,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. @@ -6947,6 +6954,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 = @@ -7047,11 +7110,17 @@ 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 @@ -73,7 +73,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 @@ -86,22 +85,25 @@ 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; @@ -220,6 +222,8 @@ 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) @@ -290,7 +294,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 @@ -566,6 +566,12 @@ } } + 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; }