cdavis5x updated this revision to Diff 33490.
cdavis5x added a comment.
- Rebase onto http://reviews.llvm.org/rL246348.
- Register the `__builtin_ms_va_list` predef decl. Fixes a nasty interaction
with modules.
- Mark `__builtin_ms_va_start` builtin as manually type-checked.
http://reviews.llvm.org/D1623
Files:
include/clang/AST/ASTContext.h
include/clang/AST/Expr.h
include/clang/Basic/BuiltinsX86.def
include/clang/Basic/TargetInfo.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTContext.cpp
lib/AST/ASTDiagnostic.cpp
lib/Basic/TargetInfo.cpp
lib/Basic/Targets.cpp
lib/CodeGen/CGBuiltin.cpp
lib/CodeGen/CGCall.cpp
lib/CodeGen/CGExprAgg.cpp
lib/CodeGen/CGExprComplex.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CodeGenFunction.cpp
lib/CodeGen/CodeGenFunction.h
lib/CodeGen/TargetInfo.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Serialization/ASTReader.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CodeGen/ms_abi.c
test/PCH/Inputs/va_arg.h
test/PCH/va_arg.c
test/PCH/va_arg.cpp
test/PCH/va_arg.h
test/Sema/varargs-x86-64.c
test/SemaTemplate/instantiate-expr-3.cpp
Index: test/SemaTemplate/instantiate-expr-3.cpp
===================================================================
--- test/SemaTemplate/instantiate-expr-3.cpp
+++ test/SemaTemplate/instantiate-expr-3.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fsyntax-only -verify %s
// ---------------------------------------------------------------------
// Imaginary literals
@@ -108,12 +108,41 @@
struct VaArg1 {
void f(int n, ...) {
VaList va;
- __builtin_va_start(va, n); // expected-error{{int}}
+ __builtin_va_start(va, n); // expected-error{{int}} expected-error{{char *}}
for (int i = 0; i != n; ++i)
(void)__builtin_va_arg(va, ArgType); // expected-error{{int}}
- __builtin_va_end(va); // expected-error{{int}}
+ __builtin_va_end(va); // expected-error{{int}} expected-error{{char *}}
}
};
template struct VaArg1<__builtin_va_list, int>;
+template struct VaArg1<__builtin_ms_va_list, int>; // expected-note{{instantiation}}
template struct VaArg1<int, int>; // expected-note{{instantiation}}
+
+template<typename ArgType>
+struct VaArg2 {
+ void f(int n, ...) {
+ __builtin_ms_va_list va;
+ __builtin_ms_va_start(va, n);
+ for (int i = 0; i != n; ++i)
+ (void)__builtin_va_arg(va, ArgType);
+ __builtin_ms_va_end(va);
+ }
+};
+
+template struct VaArg2<int>;
+
+template<typename VaList, typename ArgType>
+struct VaArg3 {
+ void f(int n, ...) {
+ VaList va;
+ __builtin_ms_va_start(va, n); // expected-error{{int}} expected-error{{__va_list_tag}}
+ for (int i = 0; i != n; ++i)
+ (void)__builtin_va_arg(va, ArgType); // expected-error{{int}}
+ __builtin_ms_va_end(va); // expected-error{{int}} expected-error{{__va_list_tag}}
+ }
+};
+
+template struct VaArg3<__builtin_ms_va_list, int>;
+template struct VaArg3<__builtin_va_list, int>; // expected-note{{instantiation}}
+template struct VaArg3<int, int>; // expected-note{{instantiation}}
Index: test/Sema/varargs-x86-64.c
===================================================================
--- test/Sema/varargs-x86-64.c
+++ test/Sema/varargs-x86-64.c
@@ -6,3 +6,70 @@
(void)__builtin_va_arg(args2, int); // expected-error {{first argument to 'va_arg' is of type 'const __builtin_va_list' and not 'va_list'}}
}
+void __attribute__((ms_abi)) g1(int a)
+{
+ __builtin_ms_va_list ap;
+
+ __builtin_ms_va_start(ap, a, a); // expected-error {{too many arguments to function}}
+ __builtin_ms_va_start(ap, a); // expected-error {{'va_start' used in function with fixed args}}
+}
+
+void __attribute__((ms_abi)) g2(int a, int b, ...)
+{
+ __builtin_ms_va_list ap;
+
+ __builtin_ms_va_start(ap, 10); // expected-warning {{second parameter of 'va_start' not last named argument}}
+ __builtin_ms_va_start(ap, a); // expected-warning {{second parameter of 'va_start' not last named argument}}
+ __builtin_ms_va_start(ap, b);
+}
+
+void __attribute__((ms_abi)) g3(float a, ...)
+{
+ __builtin_ms_va_list ap;
+
+ __builtin_ms_va_start(ap, a);
+ __builtin_ms_va_start(ap, (a));
+}
+
+void __attribute__((ms_abi)) g5() {
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap,ap); // expected-error {{'va_start' used in function with fixed args}}
+}
+
+void __attribute__((ms_abi)) g6(int a, ...) {
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap); // expected-error {{too few arguments to function}}
+}
+
+void __attribute__((ms_abi))
+bar(__builtin_ms_va_list authors, ...) {
+ __builtin_ms_va_start (authors, authors);
+ (void)__builtin_va_arg(authors, int);
+ __builtin_ms_va_end (authors);
+}
+
+void __attribute__((ms_abi)) g7(int a, ...) {
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap, a);
+ // FIXME: This error message is sub-par.
+ __builtin_va_arg(ap, int) = 1; // expected-error {{expression is not assignable}}
+ int *x = &__builtin_va_arg(ap, int); // expected-error {{cannot take the address of an rvalue}}
+ __builtin_ms_va_end(ap);
+}
+
+void __attribute__((ms_abi)) g8(int a, ...) {
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap, a);
+ (void)__builtin_va_arg(ap, void); // expected-error {{second argument to 'va_arg' is of incomplete type 'void'}}
+ __builtin_ms_va_end(ap);
+}
+
+enum E { x = -1, y = 2, z = 10000 };
+void __attribute__((ms_abi)) g9(__builtin_ms_va_list args)
+{
+ (void)__builtin_va_arg(args, float); // expected-warning {{second argument to 'va_arg' is of promotable type 'float'}}
+ (void)__builtin_va_arg(args, enum E); // Don't warn here in C
+ (void)__builtin_va_arg(args, short); // expected-warning {{second argument to 'va_arg' is of promotable type 'short'}}
+ (void)__builtin_va_arg(args, char); // expected-warning {{second argument to 'va_arg' is of promotable type 'char'}}
+}
+
Index: test/PCH/va_arg.h
===================================================================
--- test/PCH/va_arg.h
+++ test/PCH/va_arg.h
@@ -6,3 +6,10 @@
va_list v;
s = g (p, __builtin_va_arg(v, int));
}
+
+typedef __builtin_ms_va_list __ms_va_list;
+char * __attribute__((ms_abi)) h (char * (*i) (char **, int), char **p, ...) {
+ char *s;
+ __ms_va_list v;
+ s = i (p, __builtin_va_arg(v, int));
+}
Index: test/PCH/va_arg.cpp
===================================================================
--- test/PCH/va_arg.cpp
+++ test/PCH/va_arg.cpp
@@ -10,8 +10,13 @@
extern "C" {
int vsnprintf(char * , size_t, const char * , va_list) ;
+int __attribute__((ms_abi)) wvsprintfA(char *, const char *, __ms_va_list);
}
void f(char *buffer, unsigned count, const char* format, va_list argptr) {
vsnprintf(buffer, count, format, argptr);
}
+
+void g(char *buffer, const char* format, __ms_va_list argptr) {
+ wvsprintfA(buffer, format, argptr);
+}
Index: test/PCH/va_arg.c
===================================================================
--- test/PCH/va_arg.c
+++ test/PCH/va_arg.c
@@ -11,3 +11,10 @@
char *g(char **argv) {
f(g0, argv, 1, 2, 3);
}
+
+char *i0(char** argv, int argc) { return argv[argc]; }
+
+char *i(char **argv) {
+ h(i0, argv, 1, 2, 3);
+}
+
Index: test/PCH/Inputs/va_arg.h
===================================================================
--- test/PCH/Inputs/va_arg.h
+++ test/PCH/Inputs/va_arg.h
@@ -1,2 +1,5 @@
#include <stdarg.h>
+typedef __builtin_ms_va_list __ms_va_list;
+#define __ms_va_start(ap,a) __builtin_ms_va_start(ap,a)
+#define __ms_va_end(ap) __builtin_ms_va_end(ap)
Index: test/CodeGen/ms_abi.c
===================================================================
--- test/CodeGen/ms_abi.c
+++ test/CodeGen/ms_abi.c
@@ -1,11 +1,19 @@
// RUN: %clang_cc1 -triple x86_64-unknown-freebsd10.0 -emit-llvm < %s | FileCheck -check-prefix=FREEBSD %s
// RUN: %clang_cc1 -triple x86_64-pc-win32 -emit-llvm < %s | FileCheck -check-prefix=WIN64 %s
+struct foo {
+ int x;
+ float y;
+ char z;
+};
+// FREEBSD: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
+// WIN64: %[[STRUCT_FOO:.*]] = type { i32, float, i8 }
+
void __attribute__((ms_abi)) f1(void);
void __attribute__((sysv_abi)) f2(void);
void f3(void) {
-// FREEBSD: define void @f3()
-// WIN64: define void @f3()
+// FREEBSD-LABEL: define void @f3()
+// WIN64-LABEL: define void @f3()
f1();
// FREEBSD: call x86_64_win64cc void @f1()
// WIN64: call void @f1()
@@ -18,3 +26,79 @@
// WIN64: declare void @f1()
// WIN64: declare x86_64_sysvcc void @f2()
+// Win64 ABI varargs
+void __attribute__((ms_abi)) f4(int a, ...) {
+// FREEBSD-LABEL: define x86_64_win64cc void @f4
+// WIN64-LABEL: define void @f4
+ __builtin_ms_va_list ap;
+ __builtin_ms_va_start(ap, a);
+ // FREEBSD: %[[AP:.*]] = alloca i8*
+ // FREEBSD: call void @llvm.va_start
+ // WIN64: %[[AP:.*]] = alloca i8*
+ // WIN64: call void @llvm.va_start
+ int b = __builtin_va_arg(ap, int);
+ // FREEBSD: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+ // FREEBSD-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+ // FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr i8, i8* %[[AP_CUR]], i32 8
+ // FREEBSD-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ // WIN64: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR]] to i32*
+ // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr i8, i8* %[[AP_CUR]], i32 8
+ // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ double _Complex c = __builtin_va_arg(ap, double _Complex);
+ // FREEBSD: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
+ // FREEBSD-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
+ // FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr i8, i8* %[[AP_CUR2]], i32 16
+ // FREEBSD-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
+ // WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
+ // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr i8, i8* %[[AP_CUR2]], i32 16
+ // WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
+ struct foo d = __builtin_va_arg(ap, struct foo);
+ // FREEBSD: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
+ // FREEBSD-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
+ // FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr i8, i8* %[[AP_CUR3]], i32 16
+ // FREEBSD-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
+ // WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
+ // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr i8, i8* %[[AP_CUR3]], i32 16
+ // WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
+ __builtin_ms_va_list ap2;
+ __builtin_ms_va_copy(ap2, ap);
+ // FREEBSD: %[[AP_VAL:.*]] = load i8*, i8** %[[AP]]
+ // FREEBSD-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);
+ // FREEBSD: 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: bitcast i8* %[[AP_CUR]] to i32*
+ // WIN64-NEXT: %[[AP_NEXT:.*]] = getelementptr i8, i8* %[[AP_CUR]], i32 8
+ // WIN64-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
+ double _Complex c = __builtin_va_arg(ap, double _Complex);
+ // WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
+ // WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr i8, i8* %[[AP_CUR2]], i32 16
+ // WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
+ struct foo d = __builtin_va_arg(ap, struct foo);
+ // WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
+ // WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
+ // WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr i8, i8* %[[AP_CUR3]], i32 16
+ // WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
+ __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: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -771,6 +771,7 @@
Writer.AddTypeSourceInfo(E->getWrittenTypeInfo(), Record);
Writer.AddSourceLocation(E->getBuiltinLoc(), Record);
Writer.AddSourceLocation(E->getRParenLoc(), Record);
+ Record.push_back(E->isMicrosoftABI());
Code = serialization::EXPR_VA_ARG;
}
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -4060,6 +4060,7 @@
PREDEF_DECL_OBJC_INSTANCETYPE_ID);
RegisterPredefDecl(Context.BuiltinVaListDecl, PREDEF_DECL_BUILTIN_VA_LIST_ID);
RegisterPredefDecl(Context.VaListTagDecl, PREDEF_DECL_VA_LIST_TAG);
+ RegisterPredefDecl(Context.BuiltinMSVaListDecl, PREDEF_DECL_BUILTIN_MS_VA_LIST_ID);
RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID);
// Build a record containing all of the tentative definitions in this file, in
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -830,6 +830,7 @@
E->setWrittenTypeInfo(GetTypeSourceInfo(Record, Idx));
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
E->setRParenLoc(ReadSourceLocation(Record, Idx));
+ E->setIsMicrosoftABI(Record[Idx++]);
}
void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
Index: lib/Serialization/ASTReader.cpp
===================================================================
--- lib/Serialization/ASTReader.cpp
+++ lib/Serialization/ASTReader.cpp
@@ -6141,6 +6141,9 @@
case PREDEF_DECL_VA_LIST_TAG:
return Context.getVaListTagDecl();
+ case PREDEF_DECL_BUILTIN_MS_VA_LIST_ID:
+ return Context.getBuiltinMSVaListDecl();
+
case PREDEF_DECL_EXTERN_C_CONTEXT_ID:
return Context.getExternCContextDecl();
}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11649,43 +11649,56 @@
Expr *E, TypeSourceInfo *TInfo,
SourceLocation RPLoc) {
Expr *OrigExpr = E;
+ bool IsMS = false;
+
+ // It might be a __builtin_ms_va_list.
+ if (!E->isTypeDependent() &&
+ Context.getTargetInfo().hasBuiltinMSVaList()) {
+ QualType MSVaListType = Context.getBuiltinMSVaListType();
+ if (Context.hasSameType(MSVaListType, E->getType())) {
+ if (CheckForModifiableLvalue(E, BuiltinLoc, *this))
+ return ExprError();
+ IsMS = true;
+ }
+ }
// Get the va_list type
QualType VaListType = Context.getBuiltinVaListType();
- if (VaListType->isArrayType()) {
- // Deal with implicit array decay; for example, on x86-64,
- // va_list is an array, but it's supposed to decay to
- // a pointer for va_arg.
- VaListType = Context.getArrayDecayedType(VaListType);
- // Make sure the input expression also decays appropriately.
- ExprResult Result = UsualUnaryConversions(E);
- if (Result.isInvalid())
- return ExprError();
- E = Result.get();
- } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
- // If va_list is a record type and we are compiling in C++ mode,
- // check the argument using reference binding.
- InitializedEntity Entity
- = InitializedEntity::InitializeParameter(Context,
- Context.getLValueReferenceType(VaListType), false);
- ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
- if (Init.isInvalid())
- return ExprError();
- E = Init.getAs<Expr>();
- } else {
- // Otherwise, the va_list argument must be an l-value because
- // it is modified by va_arg.
- if (!E->isTypeDependent() &&
- CheckForModifiableLvalue(E, BuiltinLoc, *this))
- return ExprError();
+ if (!IsMS) {
+ if (VaListType->isArrayType()) {
+ // Deal with implicit array decay; for example, on x86-64,
+ // va_list is an array, but it's supposed to decay to
+ // a pointer for va_arg.
+ VaListType = Context.getArrayDecayedType(VaListType);
+ // Make sure the input expression also decays appropriately.
+ ExprResult Result = UsualUnaryConversions(E);
+ if (Result.isInvalid())
+ return ExprError();
+ E = Result.get();
+ } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) {
+ // If va_list is a record type and we are compiling in C++ mode,
+ // check the argument using reference binding.
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context,
+ Context.getLValueReferenceType(VaListType), false);
+ ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E);
+ if (Init.isInvalid())
+ return ExprError();
+ E = Init.getAs<Expr>();
+ } else {
+ // Otherwise, the va_list argument must be an l-value because
+ // it is modified by va_arg.
+ if (!E->isTypeDependent() &&
+ CheckForModifiableLvalue(E, BuiltinLoc, *this))
+ return ExprError();
+ }
}
- if (!E->isTypeDependent() &&
- !Context.hasSameType(VaListType, E->getType())) {
+ if (!IsMS && !E->isTypeDependent() &&
+ !Context.hasSameType(VaListType, E->getType()))
return ExprError(Diag(E->getLocStart(),
diag::err_first_argument_to_va_arg_not_of_type_va_list)
<< OrigExpr->getType() << E->getSourceRange());
- }
if (!TInfo->getType()->isDependentType()) {
if (RequireCompleteType(TInfo->getTypeLoc().getBeginLoc(), TInfo->getType(),
@@ -11727,7 +11740,7 @@
}
QualType T = TInfo->getType().getNonLValueExprType(Context);
- return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T);
+ return new (Context) VAArgExpr(BuiltinLoc, E, TInfo, RPLoc, T, IsMS);
}
ExprResult Sema::ActOnGNUNullExpr(SourceLocation TokenLoc) {
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -1034,6 +1034,10 @@
default: return false;
case X86::BI__builtin_cpu_supports:
return SemaBuiltinCpuSupports(TheCall);
+ case X86::BI__builtin_ms_va_start:
+ if (Context.getTargetInfo().getTriple().getArch() != llvm::Triple::x86_64)
+ return false;
+ return SemaBuiltinVAStart(TheCall);
case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break;
case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break;
case X86::BI__builtin_ia32_vpermil2pd:
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -237,6 +237,12 @@
}
}
+ if (PP.getTargetInfo().hasBuiltinMSVaList()) {
+ DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list");
+ if (IdResolver.begin(MSVaList) == IdResolver.end())
+ PushOnScopeChains(Context.getBuiltinMSVaListDecl(), TUScope);
+ }
+
DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list");
if (IdResolver.begin(BuiltinVaList) == IdResolver.end())
PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope);
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp
+++ lib/CodeGen/TargetInfo.cpp
@@ -3142,24 +3142,7 @@
llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty,
CodeGenFunction &CGF) const {
- llvm::Type *BPP = CGF.Int8PtrPtrTy;
-
- CGBuilderTy &Builder = CGF.Builder;
- llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP,
- "ap");
- llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
- llvm::Type *PTy =
- llvm::PointerType::getUnqual(CGF.ConvertType(Ty));
- llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
-
- uint64_t Offset =
- llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 8);
- llvm::Value *NextAddr =
- Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset),
- "ap.next");
- Builder.CreateStore(NextAddr, VAListAddrAsBPP);
-
- return AddrTyped;
+ return CGF.EmitMSVAArg(VAListAddr, Ty);
}
// PowerPC-32
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -1563,6 +1563,11 @@
// or the value of the expression, depending on how va_list is defined.
llvm::Value *EmitVAListRef(const Expr *E);
+ /// Emit a "reference" to a __builtin_ms_va_list; this is
+ /// always the value of the expression, because a __builtin_ms_va_list is a
+ /// pointer to a char.
+ llvm::Value *EmitMSVAListRef(const Expr *E);
+
/// EmitAnyExprToTemp - Similary to EmitAnyExpr(), however, the result will
/// always be accessible even if no aggregate location is provided.
RValue EmitAnyExprToTemp(const Expr *E);
@@ -1664,6 +1669,21 @@
/// to -1 in accordance with the Itanium C++ ABI.
void EmitNullInitialization(llvm::Value *DestPtr, QualType Ty);
+ /// Emits a call to an LLVM variable-argument intrinsic, either
+ /// \c llvm.va_start or \c llvm.va_end.
+ /// \param ArgValue A reference to the \c va_list as emitted by either
+ /// \c EmitVAListRef or \c EmitMSVAListRef.
+ /// \param IsStart If \c true, emits a call to \c llvm.va_start; otherwise,
+ /// calls \c llvm.va_end.
+ llvm::Value *EmitVAStartEnd(llvm::Value *ArgValue, bool IsStart);
+
+ /// \brief Generates code to get an argument from the passed-in pointer
+ /// and update it accordingly. Unlike \c EmitVAArg, this method always
+ /// obeys the Win64 ABI; it is intended to be used to generate code for
+ /// \c __builtin_va_arg when called on a \c __builtin_ms_va_list.
+ /// \return A pointer to the argument.
+ llvm::Value *EmitMSVAArg(llvm::Value *VAListAddr, QualType Ty);
+
// EmitVAArg - Generate code to get an argument from the passed in pointer
// and update it accordingly. The return value is a pointer to the argument.
// FIXME: We should be able to get rid of this method and use the va_arg
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -1651,6 +1651,10 @@
return EmitLValue(E).getAddress();
}
+llvm::Value* CodeGenFunction::EmitMSVAListRef(const Expr* E) {
+ return EmitLValue(E).getAddress();
+}
+
void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
llvm::Constant *Init) {
assert (Init && "Invalid DeclRefExpr initializer!");
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -3384,8 +3384,12 @@
if (Ty->isVariablyModifiedType())
CGF.EmitVariablyModifiedType(Ty);
- llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
- llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
+ llvm::Value *ArgValue = VE->isMicrosoftABI() ?
+ CGF.EmitMSVAListRef(VE->getSubExpr()) :
+ CGF.EmitVAListRef(VE->getSubExpr());
+ llvm::Value *ArgPtr = VE->isMicrosoftABI() ?
+ CGF.EmitMSVAArg(ArgValue, VE->getType()) :
+ CGF.EmitVAArg(ArgValue, VE->getType());
llvm::Type *ArgTy = ConvertType(VE->getType());
// If EmitVAArg fails, we fall back to the LLVM instruction.
Index: lib/CodeGen/CGExprComplex.cpp
===================================================================
--- lib/CodeGen/CGExprComplex.cpp
+++ lib/CodeGen/CGExprComplex.cpp
@@ -1016,8 +1016,12 @@
}
ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
- llvm::Value *ArgValue = CGF.EmitVAListRef(E->getSubExpr());
- llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, E->getType());
+ llvm::Value *ArgValue = E->isMicrosoftABI() ?
+ CGF.EmitMSVAListRef(E->getSubExpr()) :
+ CGF.EmitVAListRef(E->getSubExpr());
+ llvm::Value *ArgPtr = E->isMicrosoftABI() ?
+ CGF.EmitMSVAArg(ArgValue, E->getType()) :
+ CGF.EmitVAArg(ArgValue, E->getType());
if (!ArgPtr) {
CGF.ErrorUnsupported(E, "complex va_arg expression");
Index: lib/CodeGen/CGExprAgg.cpp
===================================================================
--- lib/CodeGen/CGExprAgg.cpp
+++ lib/CodeGen/CGExprAgg.cpp
@@ -959,8 +959,12 @@
}
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
- llvm::Value *ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
- llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
+ llvm::Value *ArgValue = VE->isMicrosoftABI() ?
+ CGF.EmitMSVAListRef(VE->getSubExpr()) :
+ CGF.EmitVAListRef(VE->getSubExpr());
+ llvm::Value *ArgPtr = VE->isMicrosoftABI() ?
+ CGF.EmitMSVAArg(ArgValue, VE->getType()) :
+ CGF.EmitVAArg(ArgValue, VE->getType());
if (!ArgPtr) {
// If EmitVAArg fails, we fall back to the LLVM instruction.
Index: lib/CodeGen/CGCall.cpp
===================================================================
--- lib/CodeGen/CGCall.cpp
+++ lib/CodeGen/CGCall.cpp
@@ -3645,6 +3645,24 @@
/* VarArg handling */
+llvm::Value *CodeGenFunction::EmitMSVAArg(llvm::Value *VAListAddr,
+ QualType Ty) {
+ llvm::Type *BPP = Int8PtrPtrTy;
+ llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap");
+ llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur");
+ llvm::Type *PTy =
+ llvm::PointerType::getUnqual(ConvertType(Ty));
+ llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy);
+
+ uint64_t Offset =
+ llvm::RoundUpToAlignment(getContext().getTypeSize(Ty) / 8, 8);
+ llvm::Value *NextAddr =
+ Builder.CreateGEP(Addr, llvm::ConstantInt::get(Int32Ty, Offset), "ap.next");
+ Builder.CreateStore(NextAddr, VAListAddrAsBPP);
+
+ return AddrTyped;
+}
+
llvm::Value *CodeGenFunction::EmitVAArg(llvm::Value *VAListAddr, QualType Ty) {
return CGM.getTypes().getABIInfo().EmitVAArg(VAListAddr, Ty, *this);
}
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -256,6 +256,14 @@
return CGF.Builder.CreateExtractValue(Tmp, 0);
}
+Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) {
+ llvm::Type *ArgType = Int8PtrTy;
+ if (ArgValue->getType() != ArgType)
+ ArgValue = Builder.CreateBitCast(ArgValue, ArgType);
+ Intrinsic::ID Inst = IsStart ? Intrinsic::vastart : Intrinsic::vaend;
+ return Builder.CreateCall(CGM.getIntrinsic(Inst), ArgValue);
+}
+
RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
unsigned BuiltinID, const CallExpr *E,
ReturnValueSlot ReturnValue) {
@@ -279,19 +287,11 @@
case Builtin::BI__builtin_stdarg_start:
case Builtin::BI__builtin_va_start:
case Builtin::BI__va_start:
- case Builtin::BI__builtin_va_end: {
- Value *ArgValue = (BuiltinID == Builtin::BI__va_start)
- ? EmitScalarExpr(E->getArg(0))
- : EmitVAListRef(E->getArg(0));
- llvm::Type *DestType = Int8PtrTy;
- if (ArgValue->getType() != DestType)
- ArgValue = Builder.CreateBitCast(ArgValue, DestType,
- ArgValue->getName().data());
-
- Intrinsic::ID inst = (BuiltinID == Builtin::BI__builtin_va_end) ?
- Intrinsic::vaend : Intrinsic::vastart;
- return RValue::get(Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue));
- }
+ case Builtin::BI__builtin_va_end:
+ return RValue::get(EmitVAStartEnd(BuiltinID == Builtin::BI__va_start ?
+ EmitScalarExpr(E->getArg(0)) :
+ EmitVAListRef(E->getArg(0)),
+ BuiltinID != Builtin::BI__builtin_va_end));
case Builtin::BI__builtin_va_copy: {
Value *DstPtr = EmitVAListRef(E->getArg(0));
Value *SrcPtr = EmitVAListRef(E->getArg(1));
@@ -5937,6 +5937,28 @@
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)),
+ 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.
+ llvm::Type *BPP = Int8PtrPtrTy;
+
+ Value *DestAddr = Builder.CreateBitCast(EmitMSVAListRef(E->getArg(0)), BPP,
+ "cp");
+ Value *SrcAddr = Builder.CreateBitCast(EmitMSVAListRef(E->getArg(1)), BPP,
+ "ap");
+
+ Value *ArgPtr = Builder.CreateLoad(Int8PtrTy, SrcAddr, "ap.val");
+ return Builder.CreateStore(ArgPtr, DestAddr);
+ }
+
SmallVector<Value*, 4> Ops;
// Find out if any arguments are required to be integer constant expressions.
Index: lib/Basic/Targets.cpp
===================================================================
--- lib/Basic/Targets.cpp
+++ lib/Basic/Targets.cpp
@@ -3847,6 +3847,9 @@
// Use fp2ret for _Complex long double.
ComplexLongDoubleUsesFP2Ret = true;
+ // Make __builtin_ms_va_list available.
+ HasBuiltinMSVaList = true;
+
// x86-64 has atomics up to 16 bytes.
MaxAtomicPromoteWidth = 128;
MaxAtomicInlineWidth = 128;
Index: lib/Basic/TargetInfo.cpp
===================================================================
--- lib/Basic/TargetInfo.cpp
+++ lib/Basic/TargetInfo.cpp
@@ -77,6 +77,7 @@
RegParmMax = 0;
SSERegParmMax = 0;
HasAlignMac68kSupport = false;
+ HasBuiltinMSVaList = false;
// Default to no types using fpret.
RealTypeUsesObjCFPRet = 0;
Index: lib/AST/ASTDiagnostic.cpp
===================================================================
--- lib/AST/ASTDiagnostic.cpp
+++ lib/AST/ASTDiagnostic.cpp
@@ -132,7 +132,8 @@
break;
// Don't desugar va_list.
- if (QualType(Ty,0) == Context.getBuiltinVaListType())
+ if (QualType(Ty,0) == Context.getBuiltinVaListType() ||
+ QualType(Ty,0) == Context.getBuiltinMSVaListType())
break;
// Otherwise, do a single-step desugar.
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -732,8 +732,9 @@
SubstTemplateTemplateParmPacks(this_()),
GlobalNestedNameSpecifier(nullptr), Int128Decl(nullptr),
UInt128Decl(nullptr), Float128StubDecl(nullptr),
- BuiltinVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr),
- ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
+ BuiltinVaListDecl(nullptr), BuiltinMSVaListDecl(nullptr),
+ ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr),
+ ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr),
CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr),
FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr),
ucontext_tDecl(nullptr), BlockDescriptorType(nullptr),
@@ -6007,10 +6008,19 @@
// __builtin_va_list Construction Functions
//===----------------------------------------------------------------------===//
-static TypedefDecl *CreateCharPtrBuiltinVaListDecl(const ASTContext *Context) {
- // typedef char* __builtin_va_list;
+static TypedefDecl *CreateCharPtrNamedVaListDecl(const ASTContext *Context,
+ StringRef Name) {
+ // typedef char* __builtin[_ms]_va_list;
QualType T = Context->getPointerType(Context->CharTy);
- return Context->buildImplicitTypedef(T, "__builtin_va_list");
+ return Context->buildImplicitTypedef(T, Name);
+}
+
+static TypedefDecl *CreateMSVaListDecl(const ASTContext *Context) {
+ return CreateCharPtrNamedVaListDecl(Context, "__builtin_ms_va_list");
+}
+
+static TypedefDecl *CreateCharPtrBuiltinVaListDecl(const ASTContext *Context) {
+ return CreateCharPtrNamedVaListDecl(Context, "__builtin_va_list");
}
static TypedefDecl *CreateVoidPtrBuiltinVaListDecl(const ASTContext *Context) {
@@ -6346,6 +6356,13 @@
return VaListTagDecl;
}
+TypedefDecl *ASTContext::getBuiltinMSVaListDecl() const {
+ if (!BuiltinMSVaListDecl)
+ BuiltinMSVaListDecl = CreateMSVaListDecl(this);
+
+ return BuiltinMSVaListDecl;
+}
+
void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) {
assert(ObjCConstantStringType.isNull() &&
"'NSConstantString' type already set!");
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -934,15 +934,18 @@
/// \brief The internal '__va_list_tag' struct, if any.
PREDEF_DECL_VA_LIST_TAG = 10,
+ /// \brief The internal '__builtin_ms_va_list' typedef.
+ PREDEF_DECL_BUILTIN_MS_VA_LIST_ID = 11,
+
/// \brief The extern "C" context.
- PREDEF_DECL_EXTERN_C_CONTEXT_ID = 11,
+ PREDEF_DECL_EXTERN_C_CONTEXT_ID = 12,
};
/// \brief The number of declaration IDs that are predefined.
///
/// For more information about predefined declarations, see the
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
- const unsigned int NUM_PREDEF_DECL_IDS = 12;
+ const unsigned int NUM_PREDEF_DECL_IDS = 13;
/// \brief Record code for a list of local redeclarations of a declaration.
const unsigned int LOCAL_REDECLARATIONS = 50;
Index: include/clang/Basic/TargetInfo.h
===================================================================
--- include/clang/Basic/TargetInfo.h
+++ include/clang/Basic/TargetInfo.h
@@ -90,6 +90,8 @@
unsigned RealTypeUsesObjCFPRet : 3;
unsigned ComplexLongDoubleUsesFP2Ret : 1;
+ unsigned HasBuiltinMSVaList : 1;
+
// TargetInfo Constructor. Default initializes all fields.
TargetInfo(const llvm::Triple &T);
@@ -525,6 +527,10 @@
/// with this target.
virtual BuiltinVaListKind getBuiltinVaListKind() const = 0;
+ /// Returns whether or not type \c __builtin_ms_va_list type is
+ /// available on this target.
+ bool hasBuiltinMSVaList() const { return HasBuiltinMSVaList; }
+
/// \brief Returns whether the passed in string is a valid clobber in an
/// inline asm statement.
///
Index: include/clang/Basic/BuiltinsX86.def
===================================================================
--- include/clang/Basic/BuiltinsX86.def
+++ include/clang/Basic/BuiltinsX86.def
@@ -30,6 +30,11 @@
// 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/AST/Expr.h
===================================================================
--- include/clang/AST/Expr.h
+++ include/clang/AST/Expr.h
@@ -3699,33 +3699,38 @@
}
};
-/// VAArgExpr, used for the builtin function __builtin_va_arg.
+/// Represents a call to the builtin function \c __builtin_va_arg.
class VAArgExpr : public Expr {
- Stmt *Val;
- TypeSourceInfo *TInfo;
+ Stmt * Val;
+ llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfo;
SourceLocation BuiltinLoc, RParenLoc;
public:
VAArgExpr(SourceLocation BLoc, Expr* e, TypeSourceInfo *TInfo,
- SourceLocation RPLoc, QualType t)
+ SourceLocation RPLoc, QualType t, bool IsMS = false)
: Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary,
t->isDependentType(), false,
(TInfo->getType()->isInstantiationDependentType() ||
e->isInstantiationDependent()),
(TInfo->getType()->containsUnexpandedParameterPack() ||
e->containsUnexpandedParameterPack())),
- Val(e), TInfo(TInfo),
+ Val(e), TInfo(TInfo, IsMS),
BuiltinLoc(BLoc),
RParenLoc(RPLoc) { }
- /// \brief Create an empty __builtin_va_arg expression.
- explicit VAArgExpr(EmptyShell Empty) : Expr(VAArgExprClass, Empty) { }
+ /// Create an empty __builtin_va_arg expression.
+ explicit VAArgExpr(EmptyShell Empty, bool IsMS = false)
+ : Expr(VAArgExprClass, Empty), Val(0), TInfo(0, IsMS) { }
const Expr *getSubExpr() const { return cast<Expr>(Val); }
Expr *getSubExpr() { return cast<Expr>(Val); }
void setSubExpr(Expr *E) { Val = E; }
- TypeSourceInfo *getWrittenTypeInfo() const { return TInfo; }
- void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo = TI; }
+ /// Returns whether this is really a Win64 ABI va_arg expression.
+ bool isMicrosoftABI() const { return TInfo.getInt(); }
+ void setIsMicrosoftABI(bool IsMS) { TInfo.setInt(IsMS); }
+
+ TypeSourceInfo *getWrittenTypeInfo() const { return TInfo.getPointer(); }
+ void setWrittenTypeInfo(TypeSourceInfo *TI) { TInfo.setPointer(TI); }
SourceLocation getBuiltinLoc() const { return BuiltinLoc; }
void setBuiltinLoc(SourceLocation L) { BuiltinLoc = L; }
Index: include/clang/AST/ASTContext.h
===================================================================
--- include/clang/AST/ASTContext.h
+++ include/clang/AST/ASTContext.h
@@ -216,6 +216,9 @@
/// __builtin_va_list type.
mutable TypedefDecl *BuiltinVaListDecl;
+ /// The typedef for the predefined \c __builtin_ms_va_list type.
+ mutable TypedefDecl *BuiltinMSVaListDecl;
+
/// \brief The typedef for the predefined \c id type.
mutable TypedefDecl *ObjCIdDecl;
@@ -1576,6 +1579,15 @@
/// for some targets.
Decl *getVaListTagDecl() const;
+ /// Retrieve the C type declaration corresponding to the predefined
+ /// \c __builtin_ms_va_list type.
+ TypedefDecl *getBuiltinMSVaListDecl() const;
+
+ /// Retrieve the type of the \c __builtin_ms_va_list type.
+ QualType getBuiltinMSVaListType() const {
+ return getTypeDeclType(getBuiltinMSVaListDecl());
+ }
+
/// \brief Return a type with additional \c const, \c volatile, or
/// \c restrict qualifiers.
QualType getCVRQualifiedType(QualType T, unsigned CVR) const {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits