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) {
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) {
}
}
}
+
+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;
+}
+
/// 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