mirror of https://github.com/microsoft/clang.git
Support __builtin_ms_va_list.
Summary: This change adds support for `__builtin_ms_va_list`, a GCC extension for variadic `ms_abi` functions. The existing `__builtin_va_list` support is inadequate for this because `va_list` is defined differently in the Win64 ABI vs. the System V/AMD64 ABI. Depends on D1622. Reviewers: rsmith, rnk, rjmccall CC: cfe-commits Differential Revision: http://reviews.llvm.org/D1623 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247941 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
15522c723b
commit
69b5694b76
|
@ -216,6 +216,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
|
|||
/// __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;
|
||||
|
||||
|
@ -1579,6 +1582,15 @@ public:
|
|||
/// 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 {
|
||||
|
|
|
@ -3699,33 +3699,35 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// 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;
|
||||
llvm::PointerIntPair<TypeSourceInfo *, 1, bool> TInfo;
|
||||
SourceLocation BuiltinLoc, RParenLoc;
|
||||
public:
|
||||
VAArgExpr(SourceLocation BLoc, Expr* e, TypeSourceInfo *TInfo,
|
||||
SourceLocation RPLoc, QualType t)
|
||||
: Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary,
|
||||
t->isDependentType(), false,
|
||||
(TInfo->getType()->isInstantiationDependentType() ||
|
||||
e->isInstantiationDependent()),
|
||||
(TInfo->getType()->containsUnexpandedParameterPack() ||
|
||||
e->containsUnexpandedParameterPack())),
|
||||
Val(e), TInfo(TInfo),
|
||||
BuiltinLoc(BLoc),
|
||||
RParenLoc(RPLoc) { }
|
||||
VAArgExpr(SourceLocation BLoc, Expr *e, TypeSourceInfo *TInfo,
|
||||
SourceLocation RPLoc, QualType t, bool IsMS)
|
||||
: Expr(VAArgExprClass, t, VK_RValue, OK_Ordinary, t->isDependentType(),
|
||||
false, (TInfo->getType()->isInstantiationDependentType() ||
|
||||
e->isInstantiationDependent()),
|
||||
(TInfo->getType()->containsUnexpandedParameterPack() ||
|
||||
e->containsUnexpandedParameterPack())),
|
||||
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)
|
||||
: Expr(VAArgExprClass, Empty), Val(0), TInfo(0, false) {}
|
||||
|
||||
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; }
|
||||
|
|
|
@ -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", "")
|
||||
|
|
|
@ -7102,6 +7102,10 @@ def note_empty_body_on_separate_line : Note<
|
|||
|
||||
def err_va_start_used_in_non_variadic_function : Error<
|
||||
"'va_start' used in function with fixed args">;
|
||||
def err_va_start_used_in_wrong_abi_function : Error<
|
||||
"'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 warn_second_parameter_of_va_start_not_last_named_argument : Warning<
|
||||
"second parameter of 'va_start' not last named argument">, InGroup<Varargs>;
|
||||
def warn_va_start_of_reference_type_is_undefined : Warning<
|
||||
|
@ -7216,6 +7220,8 @@ def err_64_bit_builtin_32_bit_tgt : Error<
|
|||
"this builtin is only available on 64-bit targets">;
|
||||
def err_ppc_builtin_only_on_pwr7 : Error<
|
||||
"this builtin is only valid on POWER7 or later CPUs">;
|
||||
def err_x86_builtin_32_bit_tgt : Error<
|
||||
"this builtin is only available on x86-64 targets">;
|
||||
|
||||
def err_builtin_longjmp_unsupported : Error<
|
||||
"__builtin_longjmp is not supported for the current target">;
|
||||
|
|
|
@ -90,6 +90,8 @@ protected:
|
|||
unsigned RealTypeUsesObjCFPRet : 3;
|
||||
unsigned ComplexLongDoubleUsesFP2Ret : 1;
|
||||
|
||||
unsigned HasBuiltinMSVaList : 1;
|
||||
|
||||
// TargetInfo Constructor. Default initializes all fields.
|
||||
TargetInfo(const llvm::Triple &T);
|
||||
|
||||
|
@ -526,6 +528,10 @@ public:
|
|||
/// 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.
|
||||
///
|
||||
|
|
|
@ -8832,8 +8832,10 @@ private:
|
|||
bool CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
|
||||
bool CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
|
||||
bool CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
|
||||
|
||||
|
||||
bool SemaBuiltinVAStartImpl(CallExpr *TheCall);
|
||||
bool SemaBuiltinVAStart(CallExpr *TheCall);
|
||||
bool SemaBuiltinMSVAStart(CallExpr *TheCall);
|
||||
bool SemaBuiltinVAStartARM(CallExpr *Call);
|
||||
bool SemaBuiltinUnorderedCompare(CallExpr *TheCall);
|
||||
bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs);
|
||||
|
|
|
@ -933,29 +933,29 @@ namespace clang {
|
|||
/// it is created.
|
||||
enum PredefinedDeclIDs {
|
||||
/// \brief The NULL declaration.
|
||||
PREDEF_DECL_NULL_ID = 0,
|
||||
|
||||
PREDEF_DECL_NULL_ID = 0,
|
||||
|
||||
/// \brief The translation unit.
|
||||
PREDEF_DECL_TRANSLATION_UNIT_ID = 1,
|
||||
|
||||
|
||||
/// \brief The Objective-C 'id' type.
|
||||
PREDEF_DECL_OBJC_ID_ID = 2,
|
||||
|
||||
|
||||
/// \brief The Objective-C 'SEL' type.
|
||||
PREDEF_DECL_OBJC_SEL_ID = 3,
|
||||
|
||||
|
||||
/// \brief The Objective-C 'Class' type.
|
||||
PREDEF_DECL_OBJC_CLASS_ID = 4,
|
||||
|
||||
|
||||
/// \brief The Objective-C 'Protocol' type.
|
||||
PREDEF_DECL_OBJC_PROTOCOL_ID = 5,
|
||||
|
||||
|
||||
/// \brief The signed 128-bit integer type.
|
||||
PREDEF_DECL_INT_128_ID = 6,
|
||||
|
||||
/// \brief The unsigned 128-bit integer type.
|
||||
PREDEF_DECL_UNSIGNED_INT_128_ID = 7,
|
||||
|
||||
|
||||
/// \brief The internal 'instancetype' typedef.
|
||||
PREDEF_DECL_OBJC_INSTANCETYPE_ID = 8,
|
||||
|
||||
|
@ -965,15 +965,18 @@ namespace clang {
|
|||
/// \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;
|
||||
|
|
|
@ -733,8 +733,9 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM,
|
|||
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),
|
||||
|
@ -6039,10 +6040,19 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
|
|||
// __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) {
|
||||
|
@ -6378,6 +6388,13 @@ Decl *ASTContext::getVaListTagDecl() const {
|
|||
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!");
|
||||
|
|
|
@ -132,7 +132,8 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) {
|
|||
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.
|
||||
|
|
|
@ -77,6 +77,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
|
|||
RegParmMax = 0;
|
||||
SSERegParmMax = 0;
|
||||
HasAlignMac68kSupport = false;
|
||||
HasBuiltinMSVaList = false;
|
||||
|
||||
// Default to no types using fpret.
|
||||
RealTypeUsesObjCFPRet = 0;
|
||||
|
|
|
@ -3894,6 +3894,9 @@ public:
|
|||
// 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;
|
||||
|
|
|
@ -85,6 +85,12 @@ namespace clang {
|
|||
CodeGen::Address VAListAddr,
|
||||
QualType Ty) const = 0;
|
||||
|
||||
/// Emit the target dependent code to load a value of
|
||||
/// \arg Ty from the \c __builtin_ms_va_list pointed to by \arg VAListAddr.
|
||||
virtual CodeGen::Address EmitMSVAArg(CodeGen::CodeGenFunction &CGF,
|
||||
CodeGen::Address VAListAddr,
|
||||
QualType Ty) const;
|
||||
|
||||
virtual bool isHomogeneousAggregateBaseType(QualType Ty) const;
|
||||
|
||||
virtual bool isHomogeneousAggregateSmallEnough(const Type *Base,
|
||||
|
|
|
@ -278,6 +278,16 @@ static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF,
|
|||
return CGF.Builder.CreateExtractValue(Tmp, 0);
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) {
|
||||
llvm::Type *DestType = Int8PtrTy;
|
||||
if (ArgValue->getType() != DestType)
|
||||
ArgValue =
|
||||
Builder.CreateBitCast(ArgValue, DestType, ArgValue->getName().data());
|
||||
|
||||
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) {
|
||||
|
@ -301,19 +311,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
|
|||
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)).getPointer();
|
||||
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)).getPointer(),
|
||||
BuiltinID != Builtin::BI__builtin_va_end));
|
||||
case Builtin::BI__builtin_va_copy: {
|
||||
Value *DstPtr = EmitVAListRef(E->getArg(0)).getPointer();
|
||||
Value *SrcPtr = EmitVAListRef(E->getArg(1)).getPointer();
|
||||
|
@ -5896,6 +5899,31 @@ BuildVector(ArrayRef<llvm::Value*> Ops) {
|
|||
|
||||
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.
|
||||
|
|
|
@ -3594,6 +3594,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
|
|||
|
||||
/* VarArg handling */
|
||||
|
||||
Address CodeGenFunction::EmitVAArg(Address VAListAddr, QualType Ty) {
|
||||
Address CodeGenFunction::EmitVAArg(VAArgExpr *VE, Address &VAListAddr) {
|
||||
VAListAddr = VE->isMicrosoftABI()
|
||||
? EmitMSVAListRef(VE->getSubExpr())
|
||||
: EmitVAListRef(VE->getSubExpr());
|
||||
QualType Ty = VE->getType();
|
||||
if (VE->isMicrosoftABI())
|
||||
return CGM.getTypes().getABIInfo().EmitMSVAArg(*this, VAListAddr, Ty);
|
||||
return CGM.getTypes().getABIInfo().EmitVAArg(*this, VAListAddr, Ty);
|
||||
}
|
||||
|
|
|
@ -960,8 +960,8 @@ void AggExprEmitter::VisitChooseExpr(const ChooseExpr *CE) {
|
|||
}
|
||||
|
||||
void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
|
||||
Address ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
|
||||
Address ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
|
||||
Address ArgValue = Address::invalid();
|
||||
Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
|
||||
|
||||
if (!ArgPtr.isValid()) {
|
||||
// If EmitVAArg fails, we fall back to the LLVM instruction.
|
||||
|
|
|
@ -1011,8 +1011,8 @@ ComplexPairTy ComplexExprEmitter::VisitInitListExpr(InitListExpr *E) {
|
|||
}
|
||||
|
||||
ComplexPairTy ComplexExprEmitter::VisitVAArgExpr(VAArgExpr *E) {
|
||||
Address ArgValue = CGF.EmitVAListRef(E->getSubExpr());
|
||||
Address ArgPtr = CGF.EmitVAArg(ArgValue, E->getType());
|
||||
Address ArgValue = Address::invalid();
|
||||
Address ArgPtr = CGF.EmitVAArg(E, ArgValue);
|
||||
|
||||
if (!ArgPtr.isValid()) {
|
||||
CGF.ErrorUnsupported(E, "complex va_arg expression");
|
||||
|
|
|
@ -3357,8 +3357,9 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) {
|
|||
if (Ty->isVariablyModifiedType())
|
||||
CGF.EmitVariablyModifiedType(Ty);
|
||||
|
||||
Address ArgValue = CGF.EmitVAListRef(VE->getSubExpr());
|
||||
Address ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType());
|
||||
Address ArgValue = Address::invalid();
|
||||
Address ArgPtr = CGF.EmitVAArg(VE, ArgValue);
|
||||
|
||||
llvm::Type *ArgTy = ConvertType(VE->getType());
|
||||
|
||||
// If EmitVAArg fails, we fall back to the LLVM instruction.
|
||||
|
|
|
@ -1718,6 +1718,10 @@ Address CodeGenFunction::EmitVAListRef(const Expr* E) {
|
|||
return EmitLValue(E).getAddress();
|
||||
}
|
||||
|
||||
Address CodeGenFunction::EmitMSVAListRef(const Expr *E) {
|
||||
return EmitLValue(E).getAddress();
|
||||
}
|
||||
|
||||
void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E,
|
||||
llvm::Constant *Init) {
|
||||
assert (Init && "Invalid DeclRefExpr initializer!");
|
||||
|
|
|
@ -1655,6 +1655,11 @@ public:
|
|||
// or the value of the expression, depending on how va_list is defined.
|
||||
Address 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.
|
||||
Address 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);
|
||||
|
@ -1752,11 +1757,23 @@ public:
|
|||
/// to -1 in accordance with the Itanium C++ ABI.
|
||||
void EmitNullInitialization(Address DestPtr, 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.
|
||||
/// 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);
|
||||
|
||||
/// Generate code to get an argument from the passed in pointer
|
||||
/// and update it accordingly.
|
||||
/// \param VE The \c VAArgExpr for which to generate code.
|
||||
/// \param VAListAddr Receives a reference to the \c va_list as emitted by
|
||||
/// either \c EmitVAListRef or \c EmitMSVAListRef.
|
||||
/// \returns A pointer to the argument.
|
||||
// FIXME: We should be able to get rid of this method and use the va_arg
|
||||
// instruction in LLVM instead once it works well enough.
|
||||
Address EmitVAArg(Address VAListAddr, QualType Ty);
|
||||
Address EmitVAArg(VAArgExpr *VE, Address &VAListAddr);
|
||||
|
||||
/// emitArrayLength - Compute the length of an array, even if it's a
|
||||
/// VLA, and drill down to the base element type.
|
||||
|
|
|
@ -61,6 +61,11 @@ ABIInfo::getNaturalAlignIndirectInReg(QualType Ty, bool Realign) const {
|
|||
/*ByRef*/ false, Realign);
|
||||
}
|
||||
|
||||
Address ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
||||
QualType Ty) const {
|
||||
return Address::invalid();
|
||||
}
|
||||
|
||||
ABIInfo::~ABIInfo() {}
|
||||
|
||||
static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT,
|
||||
|
@ -1734,6 +1739,8 @@ public:
|
|||
|
||||
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
||||
QualType Ty) const override;
|
||||
Address EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
||||
QualType Ty) const override;
|
||||
|
||||
bool has64BitPointers() const {
|
||||
return Has64BitPointers;
|
||||
|
@ -3266,6 +3273,14 @@ Address X86_64ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|||
return ResAddr;
|
||||
}
|
||||
|
||||
Address X86_64ABIInfo::EmitMSVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
||||
QualType Ty) const {
|
||||
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
|
||||
CGF.getContext().getTypeInfoInChars(Ty),
|
||||
CharUnits::fromQuantity(8),
|
||||
/*allowHigherAlign*/ false);
|
||||
}
|
||||
|
||||
ABIArgInfo WinX86_64ABIInfo::classify(QualType Ty, unsigned &FreeSSERegs,
|
||||
bool IsReturnType) const {
|
||||
|
||||
|
|
|
@ -249,6 +249,12 @@ void Sema::Initialize() {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -1037,6 +1037,8 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
|
|||
default: return false;
|
||||
case X86::BI__builtin_cpu_supports:
|
||||
return SemaBuiltinCpuSupports(TheCall);
|
||||
case X86::BI__builtin_ms_va_start:
|
||||
return SemaBuiltinMSVAStart(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:
|
||||
|
@ -2317,9 +2319,10 @@ bool Sema::CheckObjCString(Expr *Arg) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// SemaBuiltinVAStart - Check the arguments to __builtin_va_start for validity.
|
||||
/// Emit an error and return true on failure, return false on success.
|
||||
bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
|
||||
/// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start'
|
||||
/// for validity. Emit an error and return true on failure; return false
|
||||
/// on success.
|
||||
bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
|
||||
Expr *Fn = TheCall->getCallee();
|
||||
if (TheCall->getNumArgs() > 2) {
|
||||
Diag(TheCall->getArg(2)->getLocStart(),
|
||||
|
@ -2397,6 +2400,48 @@ bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
|
|||
return false;
|
||||
}
|
||||
|
||||
/// Check the arguments to '__builtin_va_start' for validity, and that
|
||||
/// it was called from a function of the native ABI.
|
||||
/// Emit an error and return true on failure; return false on success.
|
||||
bool Sema::SemaBuiltinVAStart(CallExpr *TheCall) {
|
||||
// On x86-64 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 (Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64) {
|
||||
unsigned OS = Context.getTargetInfo().getTriple().getOS();
|
||||
clang::CallingConv CC = CC_C;
|
||||
if (const FunctionDecl *FD = getCurFunctionDecl())
|
||||
CC = FD->getType()->getAs<FunctionType>()->getCallConv();
|
||||
if ((OS == llvm::Triple::Win32 && CC == CC_X86_64SysV) ||
|
||||
(OS != llvm::Triple::Win32 && CC == CC_X86_64Win64))
|
||||
return Diag(TheCall->getCallee()->getLocStart(),
|
||||
diag::err_va_start_used_in_wrong_abi_function)
|
||||
<< (OS != llvm::Triple::Win32);
|
||||
}
|
||||
return SemaBuiltinVAStartImpl(TheCall);
|
||||
}
|
||||
|
||||
/// Check the arguments to '__builtin_ms_va_start' for validity, and that
|
||||
/// it was called from a Win64 ABI function.
|
||||
/// Emit an error and return true on failure; return false on success.
|
||||
bool Sema::SemaBuiltinMSVAStart(CallExpr *TheCall) {
|
||||
// This only makes sense for x86-64.
|
||||
const llvm::Triple &TT = Context.getTargetInfo().getTriple();
|
||||
Expr *Callee = TheCall->getCallee();
|
||||
if (TT.getArch() != llvm::Triple::x86_64)
|
||||
return Diag(Callee->getLocStart(), diag::err_x86_builtin_32_bit_tgt);
|
||||
// Don't allow this in System V ABI functions.
|
||||
clang::CallingConv CC = CC_C;
|
||||
if (const FunctionDecl *FD = getCurFunctionDecl())
|
||||
CC = FD->getType()->getAs<FunctionType>()->getCallConv();
|
||||
if (CC == CC_X86_64SysV ||
|
||||
(TT.getOS() != llvm::Triple::Win32 && CC != CC_X86_64Win64))
|
||||
return Diag(Callee->getLocStart(),
|
||||
diag::err_ms_va_start_used_in_sysv_function);
|
||||
return SemaBuiltinVAStartImpl(TheCall);
|
||||
}
|
||||
|
||||
bool Sema::SemaBuiltinVAStartARM(CallExpr *Call) {
|
||||
// void __va_start(va_list *ap, const char *named_addr, size_t slot_size,
|
||||
// const char *named_addr);
|
||||
|
|
|
@ -11671,43 +11671,57 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
|
|||
Expr *E, TypeSourceInfo *TInfo,
|
||||
SourceLocation RPLoc) {
|
||||
Expr *OrigExpr = E;
|
||||
bool IsMS = false;
|
||||
|
||||
// It might be a __builtin_ms_va_list. (But don't ever mark a va_arg()
|
||||
// as Microsoft ABI on an actual Microsoft platform, where
|
||||
// __builtin_ms_va_list and __builtin_va_list are the same.)
|
||||
if (!E->isTypeDependent() && Context.getTargetInfo().hasBuiltinMSVaList() &&
|
||||
Context.getTargetInfo().getBuiltinVaListKind() != TargetInfo::CharPtrBuiltinVaList) {
|
||||
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(),
|
||||
|
@ -11749,7 +11763,7 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
|
|||
}
|
||||
|
||||
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) {
|
||||
|
|
|
@ -6270,6 +6270,9 @@ static Decl *getPredefinedDecl(ASTContext &Context, PredefinedDeclIDs ID) {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -830,6 +830,7 @@ void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) {
|
|||
E->setWrittenTypeInfo(GetTypeSourceInfo(Record, Idx));
|
||||
E->setBuiltinLoc(ReadSourceLocation(Record, Idx));
|
||||
E->setRParenLoc(ReadSourceLocation(Record, Idx));
|
||||
E->setIsMicrosoftABI(Record[Idx++]);
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) {
|
||||
|
|
|
@ -4084,6 +4084,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef,
|
|||
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
|
||||
|
|
|
@ -771,6 +771,7 @@ void ASTStmtWriter::VisitVAArgExpr(VAArgExpr *E) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,145 @@
|
|||
// 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()
|
||||
// FREEBSD: call x86_64_win64cc void @f1()
|
||||
// WIN64: call void @f1()
|
||||
f2();
|
||||
// FREEBSD: call void @f2()
|
||||
// WIN64: call x86_64_sysvcc void @f2()
|
||||
// FREEBSD: call void @f2()
|
||||
// WIN64: call x86_64_sysvcc void @f2()
|
||||
}
|
||||
// FREEBSD: declare x86_64_win64cc void @f1()
|
||||
// FREEBSD: declare void @f2()
|
||||
// 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: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
|
||||
// FREEBSD-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*
|
||||
double _Complex c = __builtin_va_arg(ap, double _Complex);
|
||||
// FREEBSD: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
|
||||
// FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
|
||||
// FREEBSD-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
|
||||
// WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
|
||||
struct foo d = __builtin_va_arg(ap, struct foo);
|
||||
// FREEBSD: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
|
||||
// FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
|
||||
// FREEBSD-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
|
||||
// WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
|
||||
__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: %[[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*
|
||||
double _Complex c = __builtin_va_arg(ap, double _Complex);
|
||||
// WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
|
||||
struct foo d = __builtin_va_arg(ap, struct foo);
|
||||
// WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
|
||||
__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
|
||||
}
|
||||
|
||||
// Verify that using a Win64 va_list from a System V function works.
|
||||
void __attribute__((sysv_abi)) f6(__builtin_ms_va_list ap) {
|
||||
// FREEBSD-LABEL: define void @f6
|
||||
// FREEBSD: store i8* %ap, i8** %[[AP:.*]]
|
||||
// WIN64-LABEL: define x86_64_sysvcc void @f6
|
||||
// WIN64: store i8* %ap, i8** %[[AP:.*]]
|
||||
int b = __builtin_va_arg(ap, int);
|
||||
// FREEBSD: %[[AP_CUR:.*]] = load i8*, i8** %[[AP]]
|
||||
// FREEBSD-NEXT: %[[AP_NEXT:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR]], i64 8
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT]], i8** %[[AP]]
|
||||
// FREEBSD-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*
|
||||
double _Complex c = __builtin_va_arg(ap, double _Complex);
|
||||
// FREEBSD: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
|
||||
// FREEBSD-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
|
||||
// FREEBSD-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
|
||||
// WIN64: %[[AP_CUR2:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT2:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR2]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT2]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR2]] to { double, double }*
|
||||
struct foo d = __builtin_va_arg(ap, struct foo);
|
||||
// FREEBSD: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
|
||||
// FREEBSD-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
|
||||
// FREEBSD-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
|
||||
// FREEBSD-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
|
||||
// WIN64: %[[AP_CUR3:.*]] = load i8*, i8** %[[AP]]
|
||||
// WIN64-NEXT: %[[AP_NEXT3:.*]] = getelementptr inbounds i8, i8* %[[AP_CUR3]], i64 16
|
||||
// WIN64-NEXT: store i8* %[[AP_NEXT3]], i8** %[[AP]]
|
||||
// WIN64-NEXT: bitcast i8* %[[AP_CUR3]] to %[[STRUCT_FOO]]*
|
||||
__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:.*]]
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -11,3 +11,9 @@ char *g0(char** argv, int argc) { return argv[argc]; }
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -10,8 +10,13 @@ typedef __SIZE_TYPE__ size_t;
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -6,3 +6,10 @@ char *f (char * (*g) (char **, int), char **p, ...) {
|
|||
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));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify %s -triple x86_64-pc-win32
|
||||
|
||||
void __attribute__((sysv_abi)) foo(int a, ...) {
|
||||
__builtin_va_list ap;
|
||||
__builtin_va_start(ap, a); // expected-error {{'va_start' used in System V ABI function}}
|
||||
}
|
|
@ -0,0 +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}}
|
||||
}
|
|
@ -6,3 +6,75 @@ void f1() {
|
|||
(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 f2(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)) 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); // no-warning
|
||||
(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'}}
|
||||
}
|
||||
|
||||
void __attribute__((ms_abi)) g10(int a, ...) {
|
||||
__builtin_va_list ap;
|
||||
__builtin_va_start(ap, a); // expected-error {{'va_start' used in Win64 ABI function}}
|
||||
}
|
||||
|
|
|
@ -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 @@ template<typename VaList, typename ArgType>
|
|||
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 __attribute__((ms_abi)) 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 __attribute__((ms_abi)) 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}}
|
||||
|
|
Loading…
Reference in New Issue