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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@58681 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index acce366..c4a33245 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -242,3 +242,38 @@
     }
   }         
 }
+
+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;
+}
+