aguinet created this revision.
aguinet added reviewers: t.p.northover, mstorsjo, thegameg.
Herald added subscribers: llvm-commits, cfe-commits, arphaman, dexonsmith, 
steven_wu, hiraditya, kristof.beyls, krytarowski.
Herald added a reviewer: aaron.ballman.
Herald added projects: clang, LLVM.
aguinet requested review of this revision.

This patch introduces the "darwin_abi" function attribute, to be able to 
compile functions for the Apple ARM64 ABI when targeting other ARM64 OSes. For 
now, only Linux/ARM64 is supported/tested.

I explained the motivation behind this and some limitations in this mail on 
llvm-dev: http://lists.llvm.org/pipermail/llvm-dev/2020-October/145680.html . 
Please note that, in this mail, I call this attribute "apple_abi". I decided to 
change it to "darwin_abi", because everything Apple-related is called "darwin" 
in clang/llvm. That being said, I don't have any strong opinion on this, and 
will be willing to hear any argument in favoir of one or the other.

It does not allow to target all the differences that exist in the Darwin ARM64 
ABI against the standard AAPCS one (see [1] for the exhaustive list).

What I beleive is implemented:

- 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" in [1].

- "The ABI requires the complete object (C1) and base-object (C2) constructors 
to return this to their callers. Similarly, the complete object (D1 
<https://reviews.llvm.org/D1>) and base-object (D2 
<https://reviews.llvm.org/D2>) destructors return this. This behavior matches 
the ARM 32-bit C++ ABI." (quoting [1]). I am not sure this would be useful to 
anyone, but that was not that hard to implement it, so I put it. The C++ 
support isn't complete in this patch though (see below), so maybe it's better 
to remove it.

- "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." (quoting [1])

- properly forwarding variadic arguments from a "darwin_abi function" to a 
linux one using va_list, by zeroing the relevant fields in the linux va_list 
structure to make sure only stack arguments will be used (cf. discussions in 
the aforementioned ML thread)

What isn't implemented and isn't supported (quoting [1]):

- "The ABI provides a fixed layout of two size_t words for array cookies, with 
no extra alignment requirements. This behavior matches the ARM 32-bit C++ ABI." 
=> this would require allowing the "darwin_abi" to be set on class types, and I 
think the overall feature would make a non-trivial patch. I prefer doing the C 
ABI right and eventually implement this afterwards.

- "A pointer to a function declared as extern “C” isn’t interchangeable with a 
function declared as extern “c++”. This behavior differs from the ARM64 ABI, in 
which the functions are interchangeable." => I'm not sure to find where this is 
tested in clang, let alone this would be possible to be tested.

- My understanding is that we should keep the Itanium mangling, even for 
functions with the "darwin_abi" attributes, so I didn't implemented the 
mangling differences. For instance, if I understood correctly, setting the 
"ms_abi" on a C++ function doesn't use the MSVC mangling.

- Everything remaining in the "Handle C++ Differences" section in [1]

[1] 
https://developer.apple.com/documentation/xcode/writing_arm64_code_for_apple_platforms
 for reference


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D89490

Files:
  clang/include/clang-c/Index.h
  clang/include/clang/Basic/Attr.td
  clang/include/clang/Basic/AttrDocs.td
  clang/include/clang/Basic/Specifiers.h
  clang/lib/AST/ItaniumMangle.cpp
  clang/lib/AST/Type.cpp
  clang/lib/AST/TypePrinter.cpp
  clang/lib/Basic/Targets/AArch64.cpp
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/ItaniumCXXABI.cpp
  clang/lib/CodeGen/TargetInfo.cpp
  clang/lib/Sema/SemaChecking.cpp
  clang/lib/Sema/SemaDeclAttr.cpp
  clang/lib/Sema/SemaType.cpp
  clang/test/CodeGen/darwin_abi.c
  clang/test/CodeGen/darwin_abi_empty_structs.cpp
  clang/test/CodeGen/darwin_abi_vaarg.c
  clang/test/CodeGen/debug-info-cc.c
  clang/test/CodeGenCXX/darwinabi-returnthis.cpp
  clang/tools/libclang/CXType.cpp
  llvm/include/llvm/BinaryFormat/Dwarf.def
  llvm/include/llvm/IR/CallingConv.h
  llvm/lib/AsmParser/LLLexer.cpp
  llvm/lib/AsmParser/LLParser.cpp
  llvm/lib/AsmParser/LLToken.h
  llvm/lib/IR/AsmWriter.cpp
  llvm/lib/Target/AArch64/AArch64CallingConvention.cpp
  llvm/lib/Target/AArch64/AArch64FastISel.cpp
  llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
  llvm/lib/Target/AArch64/AArch64ISelLowering.h
  llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
  llvm/lib/Target/AArch64/AArch64Subtarget.h
  llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp

Index: llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
===================================================================
--- llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
+++ llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp
@@ -474,8 +474,8 @@
   uint64_t StackOffset = Handler.StackUsed;
   if (F.isVarArg()) {
     auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
-    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;
     }
Index: llvm/lib/Target/AArch64/AArch64Subtarget.h
===================================================================
--- llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ 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
Index: llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64RegisterInfo.cpp
+++ 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<AArch64Subtarget>().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<AArch64Subtarget>().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<AArch64Subtarget>().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<AArch64Subtarget>().isTargetDarwin())
+  if (MF.getSubtarget<AArch64Subtarget>().isCallingConvDarwin(CC))
     return CSR_Darwin_AArch64_AAPCS_ThisReturn_RegMask;
   return CSR_AArch64_AAPCS_ThisReturn_RegMask;
 }
Index: llvm/lib/Target/AArch64/AArch64ISelLowering.h
===================================================================
--- llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ 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;
Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ 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<SDValue> &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<CCValAssign, 16> ArgLocs;
@@ -4278,7 +4285,7 @@
   // varargs
   AArch64FunctionInfo *FuncInfo = MF.getInfo<AArch64FunctionInfo>();
   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<AArch64FunctionInfo>();
+  auto PtrVT = getPointerTy(DAG.getDataLayout());
+  SDLoc DL(Op);
+
+  SDValue Chain = Op.getOperand(0);
+  SDValue VAList = Op.getOperand(1);
+  const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
+  SmallVector<SDValue, 4> 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);
 }
 
Index: llvm/lib/Target/AArch64/AArch64FastISel.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64FastISel.cpp
+++ 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) {
Index: llvm/lib/Target/AArch64/AArch64CallingConvention.cpp
===================================================================
--- llvm/lib/Target/AArch64/AArch64CallingConvention.cpp
+++ 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);
 }
Index: llvm/lib/IR/AsmWriter.cpp
===================================================================
--- llvm/lib/IR/AsmWriter.cpp
+++ 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;
Index: llvm/lib/AsmParser/LLToken.h
===================================================================
--- llvm/lib/AsmParser/LLToken.h
+++ 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,
Index: llvm/lib/AsmParser/LLParser.cpp
===================================================================
--- llvm/lib/AsmParser/LLParser.cpp
+++ 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,36 @@
   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);
Index: llvm/lib/AsmParser/LLLexer.cpp
===================================================================
--- llvm/lib/AsmParser/LLLexer.cpp
+++ 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);
Index: llvm/include/llvm/IR/CallingConv.h
===================================================================
--- llvm/include/llvm/IR/CallingConv.h
+++ 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
   };
Index: llvm/include/llvm/BinaryFormat/Dwarf.def
===================================================================
--- llvm/include/llvm/BinaryFormat/Dwarf.def
+++ 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
Index: clang/tools/libclang/CXType.cpp
===================================================================
--- clang/tools/libclang/CXType.cpp
+++ clang/tools/libclang/CXType.cpp
@@ -658,6 +658,7 @@
       TCALLINGCONV(X86RegCall);
       TCALLINGCONV(X86VectorCall);
       TCALLINGCONV(AArch64VectorCall);
+      TCALLINGCONV(AArch64Darwin);
       TCALLINGCONV(Win64);
       TCALLINGCONV(X86_64SysV);
       TCALLINGCONV(AAPCS);
Index: clang/test/CodeGenCXX/darwinabi-returnthis.cpp
===================================================================
--- /dev/null
+++ 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]]
+}
Index: clang/test/CodeGen/debug-info-cc.c
===================================================================
--- clang/test/CodeGen/debug-info-cc.c
+++ 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
Index: clang/test/CodeGen/darwin_abi_vaarg.c
===================================================================
--- /dev/null
+++ 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;
+}
Index: clang/test/CodeGen/darwin_abi_empty_structs.cpp
===================================================================
--- /dev/null
+++ 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)
Index: clang/test/CodeGen/darwin_abi.c
===================================================================
--- /dev/null
+++ 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);
+}
Index: clang/lib/Sema/SemaType.cpp
===================================================================
--- clang/lib/Sema/SemaType.cpp
+++ 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<IntelOclBiccAttr>(Ctx, Attr);
   case ParsedAttr::AT_MSABI:
     return createSimpleAttr<MSABIAttr>(Ctx, Attr);
+  case ParsedAttr::AT_DarwinABI:
+    return createSimpleAttr<DarwinABIAttr>(Ctx, Attr);
   case ParsedAttr::AT_SysVABI:
     return createSimpleAttr<SysVABIAttr>(Ctx, Attr);
   case ParsedAttr::AT_PreserveMost:
Index: clang/lib/Sema/SemaDeclAttr.cpp
===================================================================
--- clang/lib/Sema/SemaDeclAttr.cpp
+++ 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:
Index: clang/lib/Sema/SemaChecking.cpp
===================================================================
--- clang/lib/Sema/SemaChecking.cpp
+++ 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;
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ 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);
Index: clang/lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ 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<CXXConstructorDecl>(GD.getDecl()) ||
+                               (isa<CXXDestructorDecl>(GD.getDecl()) &&
+                                GD.getDtorType() != Dtor_Deleting));
+    if (!IsCtorOrDtor) {
+      return false;
+    }
+    auto *FTy =
+        cast<FunctionDecl>(GD.getDecl())->getType()->getAs<FunctionType>();
+    const auto FCC = FTy->getCallConv();
+    return FCC == CallingConv::CC_AArch64Darwin;
+  }
+
   bool classifyReturnType(CGFunctionInfo &FI) const override;
 
   RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const override {
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ 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:
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ 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<StdCallAttr>())
     return CC_X86StdCall;
@@ -230,6 +233,9 @@
   if (D->hasAttr<MSABIAttr>())
     return IsWindows ? CC_C : CC_Win64;
 
+  if (D->hasAttr<DarwinABIAttr>())
+    return IsDarwin ? CC_C : CC_AArch64Darwin;
+
   if (D->hasAttr<SysVABIAttr>())
     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<NSReturnsRetainedAttr>())
Index: clang/lib/Basic/Targets/AArch64.cpp
===================================================================
--- clang/lib/Basic/Targets/AArch64.cpp
+++ 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:
Index: clang/lib/AST/TypePrinter.cpp
===================================================================
--- clang/lib/AST/TypePrinter.cpp
+++ 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: {
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ 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:
Index: clang/lib/AST/ItaniumMangle.cpp
===================================================================
--- clang/lib/AST/ItaniumMangle.cpp
+++ 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";
   }
Index: clang/include/clang/Basic/Specifiers.h
===================================================================
--- clang/include/clang/Basic/Specifiers.h
+++ 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
Index: clang/include/clang/Basic/AttrDocs.td
===================================================================
--- clang/include/clang/Basic/AttrDocs.td
+++ 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 = [{
Index: clang/include/clang/Basic/Attr.td
===================================================================
--- clang/include/clang/Basic/Attr.td
+++ 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<TargetMSP430> {
   // NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's
   // and AnyX86Interrupt's spellings must match.
Index: clang/include/clang-c/Index.h
===================================================================
--- clang/include/clang-c/Index.h
+++ 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
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to