Index: include/clang/Basic/BuiltinsAArch64.def =================================================================== --- include/clang/Basic/BuiltinsAArch64.def +++ include/clang/Basic/BuiltinsAArch64.def @@ -61,4 +61,9 @@ BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc") BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc") +// Win64-compatible va_list functions +BUILTIN(__builtin_ms_va_start, "vc*&.", "nt") +BUILTIN(__builtin_ms_va_end, "vc*&", "n") +BUILTIN(__builtin_ms_va_copy, "vc*&c*&", "n") + #undef BUILTIN Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7983,6 +7983,8 @@ "'va_start' used in %select{System V|Win64}0 ABI function">; def err_ms_va_start_used_in_sysv_function : Error< "'__builtin_ms_va_start' used in System V ABI function">; +def err_ms_va_start_used_in_aapcs_function : Error< + "'__builtin_ms_va_start' used in AAPCS ABI function">; def warn_second_arg_of_va_start_not_last_named_param : Warning< "second argument to 'va_start' is not the last named parameter">, InGroup; Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -247,6 +247,7 @@ CC_Swift, // __attribute__((swiftcall)) CC_PreserveMost, // __attribute__((preserve_most)) CC_PreserveAll, // __attribute__((preserve_all)) + CC_AArch64Win64, // __attribute__((ms_abi)) }; /// \brief Checks whether the given calling convention supports variadic Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2539,6 +2539,7 @@ case CC_OpenCLKernel: case CC_PreserveMost: case CC_PreserveAll: + case CC_AArch64Win64: // FIXME: we should be mangling all of the above. return ""; Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2124,6 +2124,7 @@ llvm_unreachable("Unsupported CC for mangling"); case CC_X86_64Win64: case CC_X86_64SysV: + case CC_AArch64Win64: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; case CC_X86ThisCall: Out << 'E'; break; Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -2641,6 +2641,7 @@ case CC_Swift: return "swiftcall"; case CC_PreserveMost: return "preserve_most"; case CC_PreserveAll: return "preserve_all"; + case CC_AArch64Win64: return "ms_abi"; } llvm_unreachable("Invalid calling convention."); Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -742,6 +742,9 @@ case CC_PreserveAll: OS << " __attribute__((preserve_all))"; break; + case CC_AArch64Win64: + OS << " __attribute__((ms_abi))"; + break; } } Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -6282,6 +6282,9 @@ LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad(); + // Make __builtin_ms_va_list available. + HasBuiltinMSVaList = true; + // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; @@ -6462,6 +6465,7 @@ case CC_PreserveMost: case CC_PreserveAll: case CC_OpenCLKernel: + case CC_AArch64Win64: return CCCR_OK; default: return CCCR_Warning; Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -5352,6 +5352,31 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { + if (BuiltinID == AArch64::BI__builtin_ms_va_start || + BuiltinID == AArch64::BI__builtin_ms_va_end) + return EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(), + BuiltinID == AArch64::BI__builtin_ms_va_start); + if (BuiltinID == AArch64::BI__builtin_ms_va_copy) { + // Lower this manually. We can't reliably determine whether or not any + // given va_copy() is for a Win64 va_list from the calling convention + // alone, because it's legal to do this from an AAPCS ABI function. + // With opaque pointer types, we won't have enough information in LLVM + // IR to determine this from the argument types, either. Best to do it + // now, while we have enough information. + Address DestAddr = EmitMSVAListRef(E->getArg(0)); + Address SrcAddr = EmitMSVAListRef(E->getArg(1)); + + llvm::Type *BPP = Int8PtrPtrTy; + + DestAddr = Address(Builder.CreateBitCast(DestAddr.getPointer(), BPP, "cp"), + DestAddr.getAlignment()); + SrcAddr = Address(Builder.CreateBitCast(SrcAddr.getPointer(), BPP, "ap"), + SrcAddr.getAlignment()); + + Value *ArgPtr = Builder.CreateLoad(SrcAddr, "ap.val"); + return Builder.CreateStore(ArgPtr, DestAddr); + } + unsigned HintID = static_cast(-1); switch (BuiltinID) { default: break; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -64,6 +64,7 @@ case CC_PreserveMost: return llvm::CallingConv::PreserveMost; case CC_PreserveAll: return llvm::CallingConv::PreserveAll; case CC_Swift: return llvm::CallingConv::Swift; + case CC_AArch64Win64: return llvm::CallingConv::AArch64_Win64; } } @@ -191,7 +192,8 @@ FTP, FD); } -static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) { +static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows, + llvm::Triple::ArchType Arch) { // Set the appropriate calling convention for the Function. if (D->hasAttr()) return CC_X86StdCall; @@ -218,7 +220,8 @@ return CC_IntelOclBicc; if (D->hasAttr()) - return IsWindows ? CC_C : CC_X86_64Win64; + return IsWindows ? CC_C : Arch == llvm::Triple::aarch64 ? CC_AArch64Win64 + : CC_X86_64Win64; if (D->hasAttr()) return IsWindows ? CC_X86_64SysV : CC_C; @@ -463,8 +466,11 @@ } FunctionType::ExtInfo einfo; - bool IsWindows = getContext().getTargetInfo().getTriple().isOSWindows(); - einfo = einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows)); + const llvm::Triple &TT = getContext().getTargetInfo().getTriple(); + bool IsWindows = TT.isOSWindows(); + llvm::Triple::ArchType Arch = TT.getArch(); + einfo = + einfo.withCallingConv(getCallingConventionForDecl(MD, IsWindows, Arch)); if (getContext().getLangOpts().ObjCAutoRefCount && MD->hasAttr()) Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -967,6 +967,7 @@ case CC_PreserveMost: case CC_PreserveAll: case CC_X86RegCall: + case CC_AArch64Win64: return 0; } return 0; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1440,6 +1440,9 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == AArch64::BI__builtin_ms_va_start) + return SemaBuiltinVAStart(BuiltinID, TheCall); + if (BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || @@ -3622,12 +3625,15 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); bool IsX64 = TT.getArch() == llvm::Triple::x86_64; + bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64; bool IsWindows = TT.isOSWindows(); - bool IsMSVAStart = BuiltinID == X86::BI__builtin_ms_va_start; + bool IsMSVAStart = BuiltinID == X86::BI__builtin_ms_va_start || + BuiltinID == AArch64::BI__builtin_ms_va_start; + clang::CallingConv CC = CC_C; + if (const FunctionDecl *FD = S.getCurFunctionDecl()) + CC = FD->getType()->getAs()->getCallConv(); + if (IsX64) { - clang::CallingConv CC = CC_C; - if (const FunctionDecl *FD = S.getCurFunctionDecl()) - CC = FD->getType()->getAs()->getCallConv(); if (IsMSVAStart) { // Don't allow this in System V ABI functions. if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_X86_64Win64)) @@ -3647,6 +3653,22 @@ return false; } + if (IsAArch64) { + if (IsMSVAStart) { + // Don't allow this in AAPCS functions. + if (CC == CC_C || (!IsWindows && CC != CC_AArch64Win64)) + return S.Diag(Fn->getLocStart(), + diag::err_ms_va_start_used_in_aapcs_function); + } else { + // On aarch64 Unix, don't allow this in Win64 ABI functions. + if (!IsWindows && CC == CC_AArch64Win64) + return S.Diag(Fn->getLocStart(), + diag::err_va_start_used_in_wrong_abi_function) + << !IsWindows; + } + return false; + } + if (IsMSVAStart) return S.Diag(Fn->getLocStart(), diag::err_x86_builtin_64_only); return false; Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4279,8 +4279,13 @@ case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; case AttributeList::AT_MSABI: - CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : - CC_X86_64Win64; + + CC = Context.getTargetInfo().getTriple().isOSWindows() + ? CC_C + : Context.getTargetInfo().getTriple().getArch() == + llvm::Triple::aarch64 + ? CC_AArch64Win64 + : CC_X86_64Win64; break; case AttributeList::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV :