Index: include/clang-c/Index.h =================================================================== --- include/clang-c/Index.h +++ include/clang-c/Index.h @@ -3205,7 +3205,7 @@ CXCallingConv_AAPCS_VFP = 7, CXCallingConv_X86RegCall = 8, CXCallingConv_IntelOclBicc = 9, - CXCallingConv_X86_64Win64 = 10, + CXCallingConv_Win64 = 10, CXCallingConv_X86_64SysV = 11, CXCallingConv_X86VectorCall = 12, CXCallingConv_Swift = 13, Index: include/clang/Basic/Builtins.def =================================================================== --- include/clang/Basic/Builtins.def +++ include/clang/Basic/Builtins.def @@ -1413,6 +1413,11 @@ // Builtins for XRay BUILTIN(__xray_customevent, "vcC*z", "") +// 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 #undef LIBBUILTIN #undef LANGBUILTIN Index: include/clang/Basic/BuiltinsX86.def =================================================================== --- include/clang/Basic/BuiltinsX86.def +++ include/clang/Basic/BuiltinsX86.def @@ -34,11 +34,6 @@ // can use it? BUILTIN(__builtin_cpu_supports, "bcC*", "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") - // Undefined Values // TARGET_BUILTIN(__builtin_ia32_undef128, "V2d", "nc", "") Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -8113,10 +8113,10 @@ "invalid transaction abort code">; def err_64_bit_builtin_32_bit_tgt : Error< "this builtin is only available on 64-bit targets">; +def err_builtin_x64_aarch64_only : Error< + "this builtin is only available on x86-64 and aarch64 targets">; def err_ppc_builtin_only_on_pwr7 : Error< "this builtin is only valid on POWER7 or later CPUs">; -def err_x86_builtin_64_only : Error< - "this builtin is only available on x86-64 targets">; def err_x86_builtin_invalid_rounding : Error< "invalid rounding argument">; def err_x86_builtin_invalid_scale : Error< Index: include/clang/Basic/Specifiers.h =================================================================== --- include/clang/Basic/Specifiers.h +++ include/clang/Basic/Specifiers.h @@ -236,7 +236,7 @@ CC_X86ThisCall, // __attribute__((thiscall)) CC_X86VectorCall, // __attribute__((vectorcall)) CC_X86Pascal, // __attribute__((pascal)) - CC_X86_64Win64, // __attribute__((ms_abi)) + CC_Win64, // __attribute__((ms_abi)) CC_X86_64SysV, // __attribute__((sysv_abi)) CC_X86RegCall, // __attribute__((regcall)) CC_AAPCS, // __attribute__((pcs("aapcs"))) Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -2529,7 +2529,7 @@ case CC_X86ThisCall: case CC_X86VectorCall: case CC_X86Pascal: - case CC_X86_64Win64: + case CC_Win64: case CC_X86_64SysV: case CC_X86RegCall: case CC_AAPCS: Index: lib/AST/MicrosoftMangle.cpp =================================================================== --- lib/AST/MicrosoftMangle.cpp +++ lib/AST/MicrosoftMangle.cpp @@ -2122,7 +2122,7 @@ switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); - case CC_X86_64Win64: + case CC_Win64: case CC_X86_64SysV: case CC_C: Out << 'A'; break; case CC_X86Pascal: Out << 'C'; break; Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -2630,7 +2630,7 @@ case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; case CC_X86VectorCall: return "vectorcall"; - case CC_X86_64Win64: return "ms_abi"; + case CC_Win64: return "ms_abi"; case CC_X86_64SysV: return "sysv_abi"; case CC_X86RegCall : return "regcall"; case CC_AAPCS: return "aapcs"; Index: lib/AST/TypePrinter.cpp =================================================================== --- lib/AST/TypePrinter.cpp +++ lib/AST/TypePrinter.cpp @@ -720,7 +720,7 @@ case CC_IntelOclBicc: OS << " __attribute__((intel_ocl_bicc))"; break; - case CC_X86_64Win64: + case CC_Win64: OS << " __attribute__((ms_abi))"; break; case CC_X86_64SysV: Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -4900,7 +4900,7 @@ case CC_Swift: case CC_X86VectorCall: case CC_IntelOclBicc: - case CC_X86_64Win64: + case CC_Win64: case CC_PreserveMost: case CC_PreserveAll: case CC_X86RegCall: @@ -6291,6 +6291,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; @@ -6474,6 +6477,7 @@ case CC_PreserveMost: case CC_PreserveAll: case CC_OpenCLKernel: + case CC_Win64: return CCCR_OK; default: return CCCR_Warning; Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -2795,6 +2795,32 @@ Arg1 = Builder.CreateTruncOrBitCast(Arg1, PTy1); return RValue::get(Builder.CreateCall(F, {Arg0Val, Arg1})); } + + case Builtin::BI__builtin_ms_va_start: + case Builtin::BI__builtin_ms_va_end: + return RValue::get(EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(), + BuiltinID == Builtin::BI__builtin_ms_va_start)); + + case Builtin::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 a System V 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 RValue::get(Builder.CreateStore(ArgPtr, DestAddr)); + } } // If this is an alias for a lib function (e.g. __builtin_sin), emit @@ -7223,31 +7249,6 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E) { - if (BuiltinID == X86::BI__builtin_ms_va_start || - BuiltinID == X86::BI__builtin_ms_va_end) - return EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(), - BuiltinID == X86::BI__builtin_ms_va_start); - if (BuiltinID == X86::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 a System V 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); - } - SmallVector Ops; // Find out if any arguments are required to be integer constant expressions. Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -50,7 +50,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_X86_64Win64: return llvm::CallingConv::X86_64_Win64; + case CC_Win64: return getTarget().getTriple().getArch() == llvm::Triple::aarch64 ? llvm::CallingConv::AArch64_Win64 : llvm::CallingConv::X86_64_Win64; case CC_X86_64SysV: return llvm::CallingConv::X86_64_SysV; case CC_AAPCS: return llvm::CallingConv::ARM_AAPCS; case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP; @@ -218,7 +218,7 @@ return CC_IntelOclBicc; if (D->hasAttr()) - return IsWindows ? CC_C : CC_X86_64Win64; + return IsWindows ? CC_C : CC_Win64; if (D->hasAttr()) return IsWindows ? CC_X86_64SysV : CC_C; Index: lib/CodeGen/CGDebugInfo.cpp =================================================================== --- lib/CodeGen/CGDebugInfo.cpp +++ lib/CodeGen/CGDebugInfo.cpp @@ -956,7 +956,7 @@ return llvm::dwarf::DW_CC_BORLAND_pascal; // FIXME: Create new DW_CC_ codes for these calling conventions. - case CC_X86_64Win64: + case CC_Win64: case CC_X86_64SysV: case CC_AAPCS: case CC_AAPCS_VFP: Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -760,6 +760,7 @@ if (CheckObjCString(TheCall->getArg(0))) return ExprError(); break; + case Builtin::BI__builtin_ms_va_start: case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: if (SemaBuiltinVAStart(BuiltinID, TheCall)) @@ -2095,9 +2096,6 @@ if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); - if (BuiltinID == X86::BI__builtin_ms_va_start) - return SemaBuiltinVAStart(BuiltinID, TheCall); - // If the intrinsic has rounding or SAE make sure its valid. if (CheckX86BuiltinRoundingOrSAE(BuiltinID, TheCall)) return true; @@ -3622,24 +3620,25 @@ 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; - if (IsX64) { + bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; + if (IsX64 || IsAArch64) { 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)) + if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_Win64)) return S.Diag(Fn->getLocStart(), diag::err_ms_va_start_used_in_sysv_function); } else { - // On x86-64 Unix, don't allow this in Win64 ABI functions. + // On x86-64/AArch64 Unix, don't allow this in Win64 ABI functions. // 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.) if ((IsWindows && CC == CC_X86_64SysV) || - (!IsWindows && CC == CC_X86_64Win64)) + (!IsWindows && CC == CC_Win64)) return S.Diag(Fn->getLocStart(), diag::err_va_start_used_in_wrong_abi_function) << !IsWindows; @@ -3648,7 +3647,7 @@ } if (IsMSVAStart) - return S.Diag(Fn->getLocStart(), diag::err_x86_builtin_64_only); + return S.Diag(Fn->getLocStart(), diag::err_builtin_x64_aarch64_only); return false; } Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -4280,7 +4280,7 @@ case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; case AttributeList::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : - CC_X86_64Win64; + CC_Win64; break; case AttributeList::AT_SysVABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_X86_64SysV : Index: test/CodeGen/ms_abi_aarch64.c =================================================================== --- /dev/null +++ test/CodeGen/ms_abi_aarch64.c @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm < %s | FileCheck -check-prefix=LINUX %s +// RUN: %clang_cc1 -triple aarch64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s + +void __attribute__((ms_abi)) f1(void); +void f2(void); +void f3(void) { + // LINUX-LABEL: define void @f3() + // WIN64-LABEL: define void @f3() + f1(); + // LINUX: call aarch64_win64cc void @f1() + // WIN64: call void @f1() + f2(); + // LINUX: call void @f2() + // WIN64: call void @f2() +} +// LINUX: declare aarch64_win64cc void @f1() +// LINUX: declare void @f2() +// WIN64: declare void @f1() +// WIN64: declare void @f2() + +// Win64 ABI varargs +void __attribute__((ms_abi)) f4(int a, ...) { + // LINUX-LABEL: define aarch64_win64cc void @f4 + // WIN64-LABEL: define void @f4 + __builtin_ms_va_list ap; + __builtin_ms_va_start(ap, a); + // LINUX: %[[AP:.*]] = alloca i8* + // LINUX: call void @llvm.va_start + // WIN64: %[[AP:.*]] = alloca i8* + // WIN64: call void @llvm.va_start + int b = __builtin_va_arg(ap, int); + // LINUX: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]] + // LINUX-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8 + // LINUX-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]] + // LINUX-NEXT: bitcast i8* %[[AP_CUR]] to i32* + // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]] + // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8 + // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]] + // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32* + __builtin_ms_va_list ap2; + __builtin_ms_va_copy(ap2, ap); + // LINUX: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]] + // LINUX-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]] + // WIN64: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]] + // WIN64-NEXT: store i8* %[[AP_VAL]], i8** %[[AP2:.*]] + __builtin_ms_va_end(ap); + // LINUX: call void @llvm.va_end + // WIN64: call void @llvm.va_end +} + +// Let's verify that normal va_lists work right on Win64, too. +void f5(int a, ...) { + // WIN64-LABEL: define void @f5 + __builtin_va_list ap; + __builtin_va_start(ap, a); + // WIN64: %[[AP:.*]] = alloca i8* + // WIN64: call void @llvm.va_start + int b = __builtin_va_arg(ap, int); + // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]] + // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8 + // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]] + // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32* + __builtin_va_list ap2; + __builtin_va_copy(ap2, ap); + // WIN64: call void @llvm.va_copy + __builtin_va_end(ap); + // WIN64: call void @llvm.va_end +} Index: test/Sema/varargs-aarch64.c =================================================================== --- /dev/null +++ test/Sema/varargs-aarch64.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple aarch64-linux-gnu + +void f1(int a, ...) { + __builtin_ms_va_list ap; + __builtin_ms_va_start(ap, a); // expected-error {{'__builtin_ms_va_start' used in System V ABI function}} +} + +void __attribute__((ms_abi)) f2(int a, ...) { + __builtin_va_list ap; + __builtin_va_start(ap, a); // expected-error {{'va_start' used in Win64 ABI function}} +} Index: test/Sema/varargs-x86-32.c =================================================================== --- test/Sema/varargs-x86-32.c +++ test/Sema/varargs-x86-32.c @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -triple i386-apple-darwin9 void foo(int a, ...) { - __builtin_ms_va_start((void *)0, a); // expected-error {{this builtin is only available on x86-64 targets}} + __builtin_ms_va_start((void *)0, a); // expected-error {{this builtin is only available on x86-64 and aarch64 targets}} } Index: tools/libclang/CXType.cpp =================================================================== --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -611,7 +611,7 @@ TCALLINGCONV(X86Pascal); TCALLINGCONV(X86RegCall); TCALLINGCONV(X86VectorCall); - TCALLINGCONV(X86_64Win64); + TCALLINGCONV(Win64); TCALLINGCONV(X86_64SysV); TCALLINGCONV(AAPCS); TCALLINGCONV(AAPCS_VFP);