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