diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 28fb9a338d08..e8ab1bbb7f35 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -256,10 +256,14 @@ void AggExprEmitter::VisitConditionalOperator(const ConditionalOperator *E) { void AggExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { llvm::Value *ArgValue = CGF.EmitLValue(VE->getSubExpr()).getAddress(); - llvm::Value *V = Builder.CreateVAArg(ArgValue, CGF.ConvertType(VE->getType())); + llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType()); + + if (!ArgPtr) + CGF.ErrorUnsupported(VE, "aggregate va_arg expression"); + if (DestPtr) // FIXME: volatility - Builder.CreateStore(V, DestPtr); + CGF.EmitAggregateCopy(DestPtr, ArgPtr, VE->getType()); } void AggExprEmitter::EmitNonConstInit(InitListExpr *E) { diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 487cfcc57bfe..a4c65c087f99 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -1149,8 +1149,14 @@ Value *ScalarExprEmitter::VisitOverloadExpr(OverloadExpr *E) { Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) { llvm::Value *ArgValue = EmitLValue(VE->getSubExpr()).getAddress(); - llvm::Value *V = Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); - return V; + llvm::Value *ArgPtr = CGF.EmitVAArg(ArgValue, VE->getType()); + + // If EmitVAArg fails, we fall back to the LLVM instruction. + if (!ArgPtr) + return Builder.CreateVAArg(ArgValue, ConvertType(VE->getType())); + + // FIXME: volatile? + return Builder.CreateLoad(ArgPtr); } Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index acce366ae933..c4a332456161 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -242,3 +242,38 @@ void CodeGenFunction::EmitIndirectSwitches() { } } } + +llvm::Value *CodeGenFunction::EmitVAArg(llvm::Value *VAListAddr, QualType Ty) +{ + // FIXME: This entire method is hardcoded for 32-bit X86. + + const char *TargetPrefix = getContext().Target.getTargetPrefix(); + + if (strcmp(TargetPrefix, "x86") != 0 || + getContext().Target.getPointerWidth(0) != 32) + return 0; + + const llvm::Type *BP = llvm::PointerType::getUnqual(llvm::Type::Int8Ty); + const llvm::Type *BPP = llvm::PointerType::getUnqual(BP); + + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, + "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + llvm::Value *AddrTyped = + Builder.CreateBitCast(Addr, + llvm::PointerType::getUnqual(ConvertType(Ty))); + + uint64_t SizeInBytes = getContext().getTypeSize(Ty) / 8; + const unsigned ArgumentSizeInBytes = 4; + if (SizeInBytes < ArgumentSizeInBytes) + SizeInBytes = ArgumentSizeInBytes; + + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, + llvm::ConstantInt::get(llvm::Type::Int32Ty, SizeInBytes), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + return AddrTyped; +} + diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 797cbf42b258..ccc5008aee11 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -281,6 +281,12 @@ public: /// EmitMemSetToZero - Generate code to memset a value of the given type to 0; void EmitMemSetToZero(llvm::Value *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. + // 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. + llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty); //===--------------------------------------------------------------------===// // Declaration Emission