r180985 - [ms-cxxabi] Emit non-virtual member function pointers

Reid Kleckner reid at kleckner.net
Thu May 2 18:15:11 PDT 2013


Author: rnk
Date: Thu May  2 20:15:11 2013
New Revision: 180985

URL: http://llvm.org/viewvc/llvm-project?rev=180985&view=rev
Log:
[ms-cxxabi] Emit non-virtual member function pointers

Without any conversion, this is pretty straightforward.  Most of the
fields can be zeros.  The order is:

- field offset or pointer
- nonvirtual adjustment (for MI functions)
- vbptr offset (for unspecified)
- virtual adjustment offset (for virtual inheritance)

Differential Revision: http://llvm-reviews.chandlerc.com/D699

Modified:
    cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
    cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp

Modified: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp?rev=180985&r1=180984&r2=180985&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp (original)
+++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp Thu May  2 20:15:11 2013
@@ -139,6 +139,12 @@ private:
                                  llvm::Value *VirtualBaseAdjustmentOffset,
                                  llvm::Value *VBPtrOffset /* optional */);
 
+  /// \brief Emits a full member pointer with the fields common to data and
+  /// function member pointers.
+  llvm::Constant *EmitFullMemberPointer(llvm::Constant *FirstField,
+                                        bool IsMemberFunction,
+                                        const CXXRecordDecl *RD);
+
 public:
   virtual llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
 
@@ -148,6 +154,8 @@ public:
 
   virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
                                                 CharUnits offset);
+  virtual llvm::Constant *EmitMemberPointer(const CXXMethodDecl *MD);
+  virtual llvm::Constant *EmitMemberPointer(const APValue &MP, QualType MPT);
 
   virtual llvm::Value *EmitMemberPointerComparison(CodeGenFunction &CGF,
                                                    llvm::Value *L,
@@ -427,10 +435,9 @@ static bool hasOnlyOneField(MSInheritanc
 
 // Only member pointers to functions need a this adjustment, since it can be
 // combined with the field offset for data pointers.
-static bool hasNonVirtualBaseAdjustmentField(const MemberPointerType *MPT,
+static bool hasNonVirtualBaseAdjustmentField(bool IsMemberFunction,
                                              MSInheritanceModel Inheritance) {
-  return (MPT->isMemberFunctionPointer() &&
-          Inheritance >= MSIM_Multiple);
+  return (IsMemberFunction && Inheritance >= MSIM_Multiple);
 }
 
 static bool hasVirtualBaseAdjustmentField(MSInheritanceModel Inheritance) {
@@ -472,9 +479,10 @@ MicrosoftCXXABI::ConvertMemberPointerTyp
   else
     fields.push_back(CGM.IntTy);  // FieldOffset
 
-  if (hasVBPtrOffsetField(Inheritance))
+  if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
+                                       Inheritance))
     fields.push_back(CGM.IntTy);
-  if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
+  if (hasVBPtrOffsetField(Inheritance))
     fields.push_back(CGM.IntTy);
   if (hasVirtualBaseAdjustmentField(Inheritance))
     fields.push_back(CGM.IntTy);  // VirtualBaseAdjustmentOffset
@@ -500,9 +508,10 @@ GetNullMemberPointerFields(const MemberP
       fields.push_back(getAllOnesInt());  // FieldOffset
   }
 
-  if (hasVBPtrOffsetField(Inheritance))
+  if (hasNonVirtualBaseAdjustmentField(MPT->isMemberFunctionPointer(),
+                                       Inheritance))
     fields.push_back(getZeroInt());
-  if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
+  if (hasVBPtrOffsetField(Inheritance))
     fields.push_back(getZeroInt());
   if (hasVirtualBaseAdjustmentField(Inheritance))
     fields.push_back(getAllOnesInt());
@@ -520,27 +529,87 @@ MicrosoftCXXABI::EmitNullMemberPointer(c
 }
 
 llvm::Constant *
-MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
-                                       CharUnits offset) {
-  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField,
+                                       bool IsMemberFunction,
+                                       const CXXRecordDecl *RD)
+{
   MSInheritanceModel Inheritance = RD->getMSInheritanceModel();
+
+  // Single inheritance class member pointer are represented as scalars instead
+  // of aggregates.
+  if (hasOnlyOneField(Inheritance))
+    return FirstField;
+
   llvm::SmallVector<llvm::Constant *, 4> fields;
-  fields.push_back(llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()));
+  fields.push_back(FirstField);
+
+  if (hasNonVirtualBaseAdjustmentField(IsMemberFunction, Inheritance))
+    fields.push_back(getZeroInt());
+
   if (hasVBPtrOffsetField(Inheritance)) {
     int64_t VBPtrOffset =
       getContext().getASTRecordLayout(RD).getVBPtrOffset().getQuantity();
+    if (VBPtrOffset == -1)
+      VBPtrOffset = 0;
     fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBPtrOffset));
   }
-  assert(!hasNonVirtualBaseAdjustmentField(MPT, Inheritance));
-  // The virtual base field starts out zero.  It is adjusted by conversions to
-  // member pointer types of a more derived class.  See http://llvm.org/PR15713
+
+  // The rest of the fields are adjusted by conversions to a more derived class.
   if (hasVirtualBaseAdjustmentField(Inheritance))
     fields.push_back(getZeroInt());
-  if (fields.size() == 1)
-    return fields[0];
+
   return llvm::ConstantStruct::getAnon(fields);
 }
 
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
+                                       CharUnits offset) {
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  llvm::Constant *FirstField =
+    llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity());
+  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/false, RD);
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
+  assert(MD->isInstance() && "Member function must not be static!");
+  MD = MD->getCanonicalDecl();
+  const CXXRecordDecl *RD = MD->getParent();
+  CodeGenTypes &Types = CGM.getTypes();
+
+  llvm::Constant *FirstField;
+  if (MD->isVirtual()) {
+    // FIXME: We have to instantiate a thunk that loads the vftable and jumps to
+    // the right offset.
+    FirstField = llvm::Constant::getNullValue(CGM.VoidPtrTy);
+  } else {
+    const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>();
+    llvm::Type *Ty;
+    // Check whether the function has a computable LLVM signature.
+    if (Types.isFuncTypeConvertible(FPT)) {
+      // The function has a computable LLVM signature; use the correct type.
+      Ty = Types.GetFunctionType(Types.arrangeCXXMethodDeclaration(MD));
+    } else {
+      // Use an arbitrary non-function type to tell GetAddrOfFunction that the
+      // function type is incomplete.
+      Ty = CGM.PtrDiffTy;
+    }
+    FirstField = CGM.GetAddrOfFunction(MD, Ty);
+    FirstField = llvm::ConstantExpr::getBitCast(FirstField, CGM.VoidPtrTy);
+  }
+
+  // The rest of the fields are common with data member pointers.
+  return EmitFullMemberPointer(FirstField, /*IsMemberFunction=*/true, RD);
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
+  // FIXME PR15875: Implement member pointer conversions for Constants.
+  const CXXRecordDecl *RD = MPT->castAs<MemberPointerType>()->getClass()->getAsCXXRecordDecl();
+  return EmitFullMemberPointer(llvm::Constant::getNullValue(CGM.VoidPtrTy),
+                               /*IsMemberFunction=*/true, RD);
+}
+
 /// Member pointers are the same if they're either bitwise identical *or* both
 /// null.  Null-ness for function members is determined by the first field,
 /// while for data member pointers we must compare all fields.
@@ -760,10 +829,10 @@ MicrosoftCXXABI::EmitLoadOfMemberFunctio
     // We need to extract values.
     unsigned I = 0;
     FunctionPointer = Builder.CreateExtractValue(MemPtr, I++);
-    if (hasVBPtrOffsetField(Inheritance))
-      VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
     if (hasNonVirtualBaseAdjustmentField(MPT, Inheritance))
       NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++);
+    if (hasVBPtrOffsetField(Inheritance))
+      VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++);
     if (hasVirtualBaseAdjustmentField(Inheritance))
       VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++);
   }

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=180985&r1=180984&r2=180985&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/microsoft-abi-member-pointers.cpp Thu May  2 20:15:11 2013
@@ -1,13 +1,21 @@
 // RUN: %clang_cc1 -fno-rtti -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
 
 struct B1 {
+  void foo();
   int b;
 };
-struct B2 { };
-struct Single : B1 { };
-struct Multiple : B1, B2 { };
+struct B2 {
+  void foo();
+};
+struct Single : B1 {
+  void foo();
+};
+struct Multiple : B1, B2 {
+  void foo();
+};
 struct Virtual : virtual B1 {
   int v;
+  void foo();
 };
 
 struct POD {
@@ -30,7 +38,7 @@ struct NonZeroVBPtr : POD, Virtual {
 
 struct Unspecified;
 
-// Check that we can lower the LLVM types and get the initializers right.
+// Check that we can lower the LLVM types and get the null initializers right.
 int Single     ::*s_d_memptr;
 int Polymorphic::*p_d_memptr;
 int Multiple   ::*m_d_memptr;
@@ -54,6 +62,49 @@ void (Virtual ::*v_f_memptr)();
 // CHECK: @"\01?m_f_memptr@@3P8Multiple@@AEXXZA" = global { i8*, i32 } zeroinitializer, align 4
 // CHECK: @"\01?v_f_memptr@@3P8Virtual@@AEXXZA" = global { i8*, i32, i32 } zeroinitializer, align 4
 
+// We can define Unspecified after locking in the inheritance model.
+struct Unspecified : Virtual {
+  void foo();
+  int u;
+};
+
+struct UnspecWithVBPtr;
+int UnspecWithVBPtr::*forceUnspecWithVBPtr;
+struct UnspecWithVBPtr : B1, virtual B2 {
+  int u;
+  void foo();
+};
+
+// Test emitting non-virtual member pointers in a non-constexpr setting.
+void EmitNonVirtualMemberPointers() {
+  void (Single     ::*s_f_memptr)() = &Single::foo;
+  void (Multiple   ::*m_f_memptr)() = &Multiple::foo;
+  void (Virtual    ::*v_f_memptr)() = &Virtual::foo;
+  void (Unspecified::*u_f_memptr)() = &Unspecified::foo;
+  void (UnspecWithVBPtr::*u2_f_memptr)() = &UnspecWithVBPtr::foo;
+// CHECK: define void @"\01?EmitNonVirtualMemberPointers@@YAXXZ"() #0 {
+// CHECK:   alloca i8*, align 4
+// CHECK:   alloca { i8*, i32 }, align 4
+// CHECK:   alloca { i8*, i32, i32 }, align 4
+// CHECK:   alloca { i8*, i32, i32, i32 }, align 4
+// CHECK:   store i8* bitcast (void (%{{.*}}*)* @"\01?foo at Single@@QAEXXZ" to i8*), i8** %{{.*}}, align 4
+// CHECK:   store { i8*, i32 }
+// CHECK:     { i8* bitcast (void (%{{.*}}*)* @"\01?foo at Multiple@@QAEXXZ" to i8*), i32 0 },
+// CHECK:     { i8*, i32 }* %{{.*}}, align 4
+// CHECK:   store { i8*, i32, i32 }
+// CHECK:     { i8* bitcast (void (%{{.*}}*)* @"\01?foo at Virtual@@QAEXXZ" to i8*), i32 0, i32 0 },
+// CHECK:     { i8*, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i8*, i32, i32, i32 }
+// CHECK:     { i8* bitcast (void (%{{.*}}*)* @"\01?foo at Unspecified@@QAEXXZ" to i8*), i32 0, i32 0, i32 0 },
+// CHECK:     { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   store { i8*, i32, i32, i32 }
+// CHECK:     { i8* bitcast (void (%{{.*}}*)* @"\01?foo at UnspecWithVBPtr@@QAEXXZ" to i8*),
+// CHECK:       i32 0, i32 4, i32 0 },
+// CHECK:     { i8*, i32, i32, i32 }* %{{.*}}, align 4
+// CHECK:   ret void
+// CHECK: }
+}
+
 void podMemPtrs() {
   int POD::*memptr;
   memptr = &POD::a;





More information about the cfe-commits mailing list