diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/CodeGen/CGCall.cpp | 45 | ||||
| -rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp | 31 |
2 files changed, 53 insertions, 23 deletions
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 5ccb8bdf2c0..44fd4d8b597 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2859,28 +2859,33 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (ArgMemory) { llvm::Value *Arg = ArgMemory; - llvm::Type *LastParamTy = - IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1); - if (Arg->getType() != LastParamTy) { + if (CallInfo.isVariadic()) { + // When passing non-POD arguments by value to variadic functions, we will + // end up with a variadic prototype and an inalloca call site. In such + // cases, we can't do any parameter mismatch checks. Give up and bitcast + // the callee. + unsigned CalleeAS = + cast<llvm::PointerType>(Callee->getType())->getAddressSpace(); + Callee = Builder.CreateBitCast( + Callee, getTypes().GetFunctionType(CallInfo)->getPointerTo(CalleeAS)); + } else { + llvm::Type *LastParamTy = + IRFuncTy->getParamType(IRFuncTy->getNumParams() - 1); + if (Arg->getType() != LastParamTy) { #ifndef NDEBUG - // Assert that these structs have equivalent element types. - llvm::StructType *FullTy = CallInfo.getArgStruct(); - llvm::StructType *Prefix = cast<llvm::StructType>( - cast<llvm::PointerType>(LastParamTy)->getElementType()); - - // For variadic functions, the caller might supply a larger struct than - // the callee expects, and that's OK. - assert(Prefix->getNumElements() == FullTy->getNumElements() || - (CallInfo.isVariadic() && - Prefix->getNumElements() <= FullTy->getNumElements())); - - for (llvm::StructType::element_iterator PI = Prefix->element_begin(), - PE = Prefix->element_end(), - FI = FullTy->element_begin(); - PI != PE; ++PI, ++FI) - assert(*PI == *FI); + // Assert that these structs have equivalent element types. + llvm::StructType *FullTy = CallInfo.getArgStruct(); + llvm::StructType *DeclaredTy = cast<llvm::StructType>( + cast<llvm::PointerType>(LastParamTy)->getElementType()); + assert(DeclaredTy->getNumElements() == FullTy->getNumElements()); + for (llvm::StructType::element_iterator DI = DeclaredTy->element_begin(), + DE = DeclaredTy->element_end(), + FI = FullTy->element_begin(); + DI != DE; ++DI, ++FI) + assert(*DI == *FI); #endif - Arg = Builder.CreateBitCast(Arg, LastParamTy); + Arg = Builder.CreateBitCast(Arg, LastParamTy); + } } Args.push_back(Arg); } diff --git a/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp index 33619216e88..6a0a8601c0c 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-byval-vararg.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s +// RUN: %clang_cc1 -Wno-non-pod-varargs -emit-llvm %s -o - -triple=i686-pc-win32 -mconstructor-aliases -fno-rtti | FileCheck %s #include <stdarg.h> @@ -19,9 +19,34 @@ int foo(A a, ...) { return sum; } +// CHECK-LABEL: define i32 @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca, ...) + int main() { return foo(A(3), 1, 2, 3); } // CHECK-LABEL: define i32 @main() -// CHECK: %[[argmem_cast:[^ ]*]] = bitcast <{ %struct.A, i32, i32, i32 }>* %argmem to <{ %struct.A }>* -// CHECK: call i32 (<{ %struct.A }>*, ...)* @"\01?foo@@YAHUA@@ZZ"(<{ %struct.A }>* inalloca %[[argmem_cast]]) +// CHECK: %[[argmem:[^ ]*]] = alloca inalloca <{ %struct.A, i32, i32, i32 }> +// CHECK: call i32 {{.*bitcast.*}}@"\01?foo@@YAHUA@@ZZ"{{.*}}(<{ %struct.A, i32, i32, i32 }>* inalloca %[[argmem]]) + +void varargs_zero(...); +void varargs_one(int, ...); +void varargs_two(int, int, ...); +void varargs_three(int, int, int, ...); +void call_var_args() { + A x(3); + varargs_zero(x); + varargs_one(1, x); + varargs_two(1, 2, x); + varargs_three(1, 2, 3, x); +} + +// CHECK-LABEL: define void @"\01?call_var_args@@YAXXZ"() +// CHECK: call void {{.*bitcast.*varargs_zero.*}}(<{ %struct.A }>* inalloca %{{.*}}) +// CHECK: call void {{.*bitcast.*varargs_one.*}}(<{ i32, %struct.A }>* inalloca %{{.*}}) +// CHECK: call void {{.*bitcast.*varargs_two.*}}(<{ i32, i32, %struct.A }>* inalloca %{{.*}}) +// CHECK: call void {{.*bitcast.*varargs_three.*}}(<{ i32, i32, i32, %struct.A }>* inalloca %{{.*}}) + +// CHECK-LABEL: declare void @"\01?varargs_zero@@YAXZZ"(...) +// CHECK-LABEL: declare void @"\01?varargs_one@@YAXHZZ"(i32, ...) +// CHECK-LABEL: declare void @"\01?varargs_two@@YAXHHZZ"(i32, i32, ...) +// CHECK-LABEL: declare void @"\01?varargs_three@@YAXHHHZZ"(i32, i32, i32, ...) |

