Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -2717,7 +2717,8 @@ uint64_t Size = getContext().getTypeSize(Ty); - if (const RecordType *RT = Ty->getAs()) { + const RecordType *RT = Ty->getAs(); + if (RT) { if (IsReturnType) { if (isRecordReturnIndirect(RT, getCXXABI())) return ABIArgInfo::getIndirect(0, false); @@ -2733,15 +2734,31 @@ if (Size == 128 && getTarget().getTriple().isWindowsGNUEnvironment()) return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); + } + + if (const auto *MPT = Ty->getAs()) { + // If the member pointer is not an aggregate, pass it directly. + if (getTarget().getCXXABI().isMicrosoft()) { + // For Microsoft, check with the inheritance model. + const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(), + RD->getMSInheritanceModel())) + return ABIArgInfo::getDirect(); + } else { + // For Itanium, data pointers are simple and function pointers are big. + if (MPT->isMemberDataPointer()) + return ABIArgInfo::getDirect(); + } + } + if (RT || Ty->isMemberPointerType()) { // MS x64 ABI requirement: "Any argument that doesn't fit in 8 bytes, or is // not 1, 2, 4, or 8 bytes, must be passed by reference." - if (Size <= 64 && - (Size & (Size - 1)) == 0) - return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), - Size)); + if (Size > 64 || !llvm::isPowerOf2_64(Size)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); - return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + // Otherwise, coerce it to a small integer. + return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); } if (Ty->isPromotableIntegerType()) Index: test/CodeGenCXX/member-function-pointer-calls.cpp =================================================================== --- test/CodeGenCXX/member-function-pointer-calls.cpp +++ test/CodeGenCXX/member-function-pointer-calls.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -O3 -o - | FileCheck %s +// RUN: %clang_cc1 %s -triple=x86_64-windows-gnu -emit-llvm -o - | FileCheck %s -check-prefix MINGW64 struct A { virtual int vf1() { return 1; } virtual int vf2() { return 2; } @@ -10,6 +11,8 @@ // CHECK-LABEL: define i32 @_Z2g1v() // CHECK: ret i32 1 +// MINGW64-LABEL: define i32 @_Z2g1v() +// MINGW64: call i32 @_Z1fP1AMS_FivE(%struct.A* %{{.*}}, { i64, i64 }* %{{.*}}) int g1() { A a; return f(&a, &A::vf1); @@ -17,6 +20,8 @@ // CHECK-LABEL: define i32 @_Z2g2v() // CHECK: ret i32 2 +// MINGW64-LABEL: define i32 @_Z2g2v() +// MINGW64: call i32 @_Z1fP1AMS_FivE(%struct.A* %{{.*}}, { i64, i64 }* %{{.*}}) int g2() { A a; return f(&a, &A::vf2); Index: test/CodeGenCXX/microsoft-abi-member-pointers.cpp =================================================================== --- test/CodeGenCXX/microsoft-abi-member-pointers.cpp +++ test/CodeGenCXX/microsoft-abi-member-pointers.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 | FileCheck %s +// RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=x86_64-pc-win32 | FileCheck %s -check-prefix=X64 // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -fms-extensions -verify // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -triple=i386-pc-win32 -DINCOMPLETE_VIRTUAL -DMEMFUN -fms-extensions -verify // FIXME: Test x86_64 member pointers when codegen no longer asserts on records @@ -235,6 +236,10 @@ // CHECK: %[[and1:.*]] = and i1 %[[and0]], %[[cmp2]] // CHECK: ret i1 %[[and1]] // CHECK: } + +// Pass this large type indirectly. +// X64-LABEL: define zeroext i1 @"\01?nullTestDataUnspecified@@ +// X64: ({ i32, i32, i32 }*) } bool nullTestFunctionUnspecified(void (Unspecified::*mp)()) { @@ -271,6 +276,11 @@ // CHECK: %[[v12:.*]] = load i32* %[[v11]] // CHECK: ret i32 %[[v12]] // CHECK: } + +// A two-field data memptr on x64 gets coerced to i64 and is passed in a +// register or memory. +// X64-LABEL: define i32 @"\01?loadDataMemberPointerVirtual@@YAHPEAUVirtual@@PEQ1@H@Z" +// X64: (%struct.Virtual* %o, i64 %memptr.coerce) } int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) { @@ -312,6 +322,11 @@ // CHECK: call x86_thiscallcc void %{{.*}}(%{{.*}} %{{.*}}) // CHECK: ret void // CHECK: } + +// X64-LABEL: define void @"\01?callMemberPointerSingle@@ +// X64: (%struct.Single* %o, i8* %memptr) +// X64: bitcast i8* %{{[^ ]*}} to void (%struct.Single*)* +// X64: ret void } void callMemberPointerMultiple(Multiple *o, void (Multiple::*memptr)()) { @@ -358,6 +373,9 @@ // CHECK-NOT: icmp // CHECK: ret i1 %[[r]] // CHECK: } + +// X64-LABEL: define zeroext i1 @"\01?compareSingleFunctionMemptr@@ +// X64: (i8* %{{[^,]*}}, i8* %{{[^)]*}}) } bool compareNeqSingleFunctionMemptr(void (Single::*l)(), void (Single::*r)()) { @@ -393,6 +411,9 @@ // CHECK: %{{.*}} = and i1 %[[bits_or_null]], %[[cmp0]] // CHECK: ret i1 %{{.*}} // CHECK: } + +// X64-LABEL: define zeroext i1 @"\01?unspecFuncMemptrEq@@ +// X64: ({ i8*, i32, i32, i32 }*, { i8*, i32, i32, i32 }*) } bool unspecFuncMemptrNeq(void (Unspecified::*l)(), void (Unspecified::*r)()) { @@ -435,6 +456,9 @@ // CHECK: and i1 // CHECK: ret i1 // CHECK: } + +// X64-LABEL: define zeroext i1 @"\01?unspecDataMemptrEq@@ +// X64: ({ i32, i32, i32 }*, { i32, i32, i32 }*) } void (Multiple::*convertB2FuncToMultiple(void (B2::*mp)()))() {