Implement lowering of va_arg in clang directly. (This is 32-bit X86 only for now).

llvm-svn: 58681
This commit is contained in:
Anders Carlsson 2008-11-04 05:30:00 +00:00
parent 4961890c07
commit 13abd7e98b
4 changed files with 55 additions and 4 deletions

View File

@ -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) {

View File

@ -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) {

View File

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

View File

@ -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