mstorsjo created this revision.
Herald added subscribers: kristof.beyls, javed.absar, rengolin, aemerson.
This behaves mostly the same as __builtin_ms_va_list on x86_64; a va_list on
windows on aarch64 is a single pointer.
In order to signal the kind of va_list to llvm for handling of va_start, a
separate calling convention is used, signaled via __attribute__((ms_abi)) just
as on x86_64.
This allows wine on aarch64 to properly handle variadic functions, successfully
running arm64 exes (from the windows 10 sdk) with a few different variations of
fprintf and vsnprintf.
This depends on https://reviews.llvm.org/D34474 for llvm.
https://reviews.llvm.org/D34475
Files:
include/clang/Basic/BuiltinsAArch64.def
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/Specifiers.h
lib/AST/ItaniumMangle.cpp
lib/AST/MicrosoftMangle.cpp
lib/AST/Type.cpp
lib/AST/TypePrinter.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGBuiltin.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/CGDebugInfo.cpp
lib/CodeGen/TargetInfo.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDeclAttr.cpp
Index: lib/Sema/SemaDeclAttr.cpp
===================================================================
--- lib/Sema/SemaDeclAttr.cpp
+++ lib/Sema/SemaDeclAttr.cpp
@@ -4279,7 +4279,8 @@
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 = Context.getTargetInfo().getTriple().getArch() == llvm::Triple::aarch64 ? CC_AArch64Win64 :
+ Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
CC_X86_64Win64;
break;
case AttributeList::AT_SysVABI:
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -1437,6 +1437,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 ||
@@ -3619,12 +3622,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<FunctionType>()->getCallConv();
+
if (IsX64) {
- clang::CallingConv CC = CC_C;
- if (const FunctionDecl *FD = S.getCurFunctionDecl())
- CC = FD->getType()->getAs<FunctionType>()->getCallConv();
if (IsMSVAStart) {
// Don't allow this in System V ABI functions.
if (CC == CC_X86_64SysV || (!IsWindows && CC != CC_X86_64Win64))
@@ -3644,6 +3650,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/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -4822,6 +4822,8 @@
return isDarwinPCS() ? EmitDarwinVAArg(VAListAddr, Ty, CGF)
: EmitAAPCSVAArg(VAListAddr, Ty, CGF);
}
+ Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const override;
bool shouldPassIndirectlyForSwift(CharUnits totalSize,
ArrayRef<llvm::Type*> scalars,
@@ -5328,6 +5330,14 @@
TyInfo, SlotSize, /*AllowHigherAlign*/ true);
}
+Address AArch64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
+ QualType Ty) const {
+ return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
+ CGF.getContext().getTypeInfoInChars(Ty),
+ CharUnits::fromQuantity(8),
+ /*allowHigherAlign*/ false);
+}
+
//===----------------------------------------------------------------------===//
// ARM ABI Implementation
//===----------------------------------------------------------------------===//
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/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<StdCallAttr>())
return CC_X86StdCall;
@@ -218,7 +220,7 @@
return CC_IntelOclBicc;
if (D->hasAttr<MSABIAttr>())
- return IsWindows ? CC_C : CC_X86_64Win64;
+ return IsWindows ? CC_C : Arch == llvm::Triple::aarch64 ? CC_AArch64Win64 : CC_X86_64Win64;
if (D->hasAttr<SysVABIAttr>())
return IsWindows ? CC_X86_64SysV : CC_C;
@@ -463,8 +465,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<NSReturnsRetainedAttr>())
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -5274,6 +5274,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<unsigned>(-1);
switch (BuiltinID) {
default: break;
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -6202,6 +6202,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;
@@ -6356,6 +6359,7 @@
case CC_PreserveMost:
case CC_PreserveAll:
case CC_OpenCLKernel:
+ case CC_AArch64Win64:
return CCCR_OK;
default:
return CCCR_Warning;
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/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/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -2069,6 +2069,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/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: 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: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -7954,6 +7954,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<Varargs>;
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
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits