Skip to content

Commit

Permalink
[AArch64] Add support for __builtin_ms_va_list on aarch64
Browse files Browse the repository at this point in the history
Move builtins from the x86 specific scope into the global
scope. Their use is still limited to x86_64 and aarch64 though.

This allows wine on aarch64 to properly handle variadic functions.

Differential Revision: https://reviews.llvm.org/D34475

llvm-svn: 308218
  • Loading branch information
mstorsjo committed Jul 17, 2017
1 parent 20f5a5c commit 022e782
Show file tree
Hide file tree
Showing 19 changed files with 138 additions and 54 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang-c/Index.h
Expand Up @@ -3205,7 +3205,7 @@ enum CXCallingConv {
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,
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/Builtins.def
Expand Up @@ -1413,6 +1413,11 @@ BUILTIN(__builtin_os_log_format, "v*v*cC*.", "p:0:nt")
// 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
5 changes: 0 additions & 5 deletions clang/include/clang/Basic/BuiltinsX86.def
Expand Up @@ -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", "")
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -8113,10 +8113,10 @@ def err_systemz_invalid_tabort_code : Error<
"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<
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/Specifiers.h
Expand Up @@ -236,7 +236,7 @@ namespace clang {
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")))
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/ItaniumMangle.cpp
Expand Up @@ -2529,7 +2529,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) {
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:
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/MicrosoftMangle.cpp
Expand Up @@ -2122,7 +2122,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) {
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;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Type.cpp
Expand Up @@ -2630,7 +2630,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) {
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";
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/TypePrinter.cpp
Expand Up @@ -751,7 +751,7 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info,
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:
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Basic/Targets.cpp
Expand Up @@ -4899,7 +4899,7 @@ class X86_64TargetInfo : public X86TargetInfo {
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:
Expand Down Expand Up @@ -6290,6 +6290,9 @@ class AArch64TargetInfo : public TargetInfo {
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;
Expand Down Expand Up @@ -6473,6 +6476,7 @@ class AArch64TargetInfo : public TargetInfo {
case CC_PreserveMost:
case CC_PreserveAll:
case CC_OpenCLKernel:
case CC_Win64:
return CCCR_OK;
default:
return CCCR_Warning;
Expand Down
52 changes: 27 additions & 25 deletions clang/lib/CodeGen/CGBuiltin.cpp
Expand Up @@ -2795,6 +2795,33 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
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
Expand Down Expand Up @@ -7223,31 +7250,6 @@ static Value *EmitX86SExtMask(CodeGenFunction &CGF, Value *Op,

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<Value*, 4> Ops;

// Find out if any arguments are required to be integer constant expressions.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGCall.cpp
Expand Up @@ -50,7 +50,7 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) {
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::Win64;
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;
case CC_AAPCS_VFP: return llvm::CallingConv::ARM_AAPCS_VFP;
Expand Down Expand Up @@ -218,7 +218,7 @@ static CallingConv getCallingConventionForDecl(const Decl *D, bool IsWindows) {
return CC_IntelOclBicc;

if (D->hasAttr<MSABIAttr>())
return IsWindows ? CC_C : CC_X86_64Win64;
return IsWindows ? CC_C : CC_Win64;

if (D->hasAttr<SysVABIAttr>())
return IsWindows ? CC_X86_64SysV : CC_C;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/CodeGen/CGDebugInfo.cpp
Expand Up @@ -956,7 +956,7 @@ static unsigned getDwarfCC(CallingConv CC) {
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:
Expand Down
17 changes: 8 additions & 9 deletions clang/lib/Sema/SemaChecking.cpp
Expand Up @@ -760,6 +760,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
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))
Expand Down Expand Up @@ -2102,9 +2103,6 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
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;
Expand Down Expand Up @@ -3629,24 +3627,25 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) {
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<FunctionType>()->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;
Expand All @@ -3655,7 +3654,7 @@ static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) {
}

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;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclAttr.cpp
Expand Up @@ -4280,7 +4280,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
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 :
Expand Down
68 changes: 68 additions & 0 deletions clang/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 win64cc void @f1()
// WIN64: call void @f1()
f2();
// LINUX: call void @f2()
// WIN64: call void @f2()
}
// LINUX: declare 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 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
}
11 changes: 11 additions & 0 deletions clang/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}}
}
2 changes: 1 addition & 1 deletion clang/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}}
}
2 changes: 1 addition & 1 deletion clang/tools/libclang/CXType.cpp
Expand Up @@ -611,7 +611,7 @@ CXCallingConv clang_getFunctionTypeCallingConv(CXType X) {
TCALLINGCONV(X86Pascal);
TCALLINGCONV(X86RegCall);
TCALLINGCONV(X86VectorCall);
TCALLINGCONV(X86_64Win64);
TCALLINGCONV(Win64);
TCALLINGCONV(X86_64SysV);
TCALLINGCONV(AAPCS);
TCALLINGCONV(AAPCS_VFP);
Expand Down

0 comments on commit 022e782

Please sign in to comment.