r207817 - Win64: Pass member pointers larger than 8 bytes by reference
Reid Kleckner
reid at kleckner.net
Thu May 1 17:51:20 PDT 2014
Author: rnk
Date: Thu May 1 19:51:20 2014
New Revision: 207817
URL: http://llvm.org/viewvc/llvm-project?rev=207817&view=rev
Log:
Win64: Pass member pointers larger than 8 bytes by reference
The Win64 ABI docs on MSDN say that arguments bigger than 8 bytes are
passed by reference. Prior to this change, we were only applying this
logic to RecordType arguments. This affects both the Itanium and
Microsoft C++ ABIs.
Reviewers: majnemer
Differential Revision: http://reviews.llvm.org/D3587
Modified:
cfe/trunk/lib/CodeGen/TargetInfo.cpp
cfe/trunk/test/CodeGenCXX/member-function-pointer-calls.cpp
cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=207817&r1=207816&r2=207817&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Thu May 1 19:51:20 2014
@@ -2717,7 +2717,8 @@ ABIArgInfo WinX86_64ABIInfo::classify(Qu
uint64_t Size = getContext().getTypeSize(Ty);
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
+ const RecordType *RT = Ty->getAs<RecordType>();
+ if (RT) {
if (IsReturnType) {
if (isRecordReturnIndirect(RT, getCXXABI()))
return ABIArgInfo::getIndirect(0, false);
@@ -2733,15 +2734,31 @@ ABIArgInfo WinX86_64ABIInfo::classify(Qu
if (Size == 128 && getTarget().getTriple().isWindowsGNUEnvironment())
return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(),
Size));
+ }
+
+ if (const auto *MPT = Ty->getAs<MemberPointerType>()) {
+ // 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())
Modified: cfe/trunk/test/CodeGenCXX/member-function-pointer-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/member-function-pointer-calls.cpp?rev=207817&r1=207816&r2=207817&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/member-function-pointer-calls.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/member-function-pointer-calls.cpp Thu May 1 19:51:20 2014
@@ -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 @@ int f(A* a, int (A::*fp)()) {
// 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 @@ int g1() {
// 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);
Modified: cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp?rev=207817&r1=207816&r2=207817&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp Thu May 1 19:51:20 2014
@@ -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 @@ bool nullTestDataUnspecified(int Unspeci
// CHECK: %[[and1:.*]] = or 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 @@ int loadDataMemberPointerVirtual(Virtual
// 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 at H@Z"
+// X64: (%struct.Virtual* %o, i64 %memptr.coerce)
}
int loadDataMemberPointerUnspecified(Unspecified *o, int Unspecified::*memptr) {
@@ -312,6 +322,11 @@ void callMemberPointerSingle(Single *o,
// 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 @@ bool compareSingleFunctionMemptr(void (S
// 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 @@ bool unspecFuncMemptrEq(void (Unspecifie
// 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 @@ bool unspecDataMemptrEq(int Unspecified:
// 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)()))() {
More information about the cfe-commits
mailing list