[PATCH] [ms-cxxabi] Move MS inheritance model calculation into MemberPointerType

Reid Kleckner rnk at google.com
Thu Mar 28 14:29:19 PDT 2013


Hi rjmccall,

This makes it possible to share code between lib/AST/MicrosoftCXXABI.cpp
and lib/CodeGen/MicrosoftCXXABI.cpp.  No functionality change.

Also adds comments about the layout of the member pointer structs as I
currently understand them.

http://llvm-reviews.chandlerc.com/D590

Files:
  include/clang/AST/Type.h
  lib/AST/MicrosoftCXXABI.cpp

Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h
+++ include/clang/AST/Type.h
@@ -2092,6 +2092,14 @@
   }
 };
 
+/// The inheritance model to use for this member pointer.
+enum MSInheritanceModel {
+  IHM_Single,
+  IHM_Multiple,
+  IHM_Virtual,
+  IHM_Unspecified
+};
+
 /// MemberPointerType - C++ 8.3.3 - Pointers to members
 ///
 class MemberPointerType : public Type, public llvm::FoldingSetNode {
@@ -2127,6 +2135,13 @@
     return !PointeeType->isFunctionProtoType();
   }
 
+  /// Returns the inheritance model used for this member pointer.
+  MSInheritanceModel getMSInheritanceModel() const;
+
+  /// Returns the number of pointer and integer slots used to represent this
+  /// member pointer in the MS C++ ABI.
+  std::pair<unsigned, unsigned> getMSMemberPointerSlots() const;
+
   const Type *getClass() const { return Class; }
 
   bool isSugared() const { return false; }
Index: lib/AST/MicrosoftCXXABI.cpp
===================================================================
--- lib/AST/MicrosoftCXXABI.cpp
+++ lib/AST/MicrosoftCXXABI.cpp
@@ -57,7 +57,7 @@
 // getNumBases() seems to only give us the number of direct bases, and not the
 // total.  This function tells us if we inherit from anybody that uses MI, or if
 // we have a non-primary base class, which uses the multiple inheritance model.
-static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
+bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) {
   while (RD->getNumBases() > 0) {
     if (RD->getNumBases() > 1)
       return true;
@@ -70,60 +70,107 @@
   return false;
 }
 
-std::pair<uint64_t, unsigned>
-MicrosoftCXXABI::getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
-  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
-  const TargetInfo &Target = Context.getTargetInfo();
-
-  assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
-         Target.getTriple().getArch() == llvm::Triple::x86_64);
+MSInheritanceModel MSInheritanceAttrToModel(attr::Kind Kind) {
+  switch (Kind) {
+  default: llvm_unreachable("expected MS inheritance attribute");
+  case attr::SingleInheritance:      return IHM_Single;
+  case attr::MultipleInheritance:    return IHM_Multiple;
+  case attr::VirtualInheritance:     return IHM_Virtual;
+  case attr::UnspecifiedInheritance: return IHM_Unspecified;
+  }
+}
 
+MSInheritanceModel MemberPointerType::getMSInheritanceModel() const {
+  const CXXRecordDecl *RD = this->getClass()->getAsCXXRecordDecl();
   Attr *IA = RD->getAttr<MSInheritanceAttr>();
-  attr::Kind Inheritance;
-  if (IA) {
-    Inheritance = IA->getKind();
-  } else if (RD->getNumVBases() > 0) {
-    Inheritance = attr::VirtualInheritance;
-  } else if (MPT->getPointeeType()->isFunctionType() &&
-             usesMultipleInheritanceModel(RD)) {
-    Inheritance = attr::MultipleInheritance;
-  } else {
-    Inheritance = attr::SingleInheritance;
-  }
+  if (IA)
+    return MSInheritanceAttrToModel(IA->getKind());
+  // If there was no explicit attribute, the record must be defined already, and
+  // we can figure out the inheritance model from its other properties.
+  if (RD->getNumVBases() > 0)
+    return IHM_Virtual;
+  if (this->getPointeeType()->isFunctionType() &&
+      usesMultipleInheritanceModel(RD))
+    return IHM_Multiple;
+  return IHM_Single;
+}
 
-  unsigned PtrSize = Target.getPointerWidth(0);
-  unsigned IntSize = Target.getIntWidth();
-  uint64_t Width;
-  unsigned Align;
-  if (MPT->getPointeeType()->isFunctionType()) {
+// Returns the number of pointer and integer slots used to represent a member
+// pointer in the MS C++ ABI.
+//
+// Member function pointers have the following general form;  however, fields
+// are dropped as permitted (under the MSVC interpretation) by the inheritance
+// model of the actual class.
+//
+//   struct {
+//     // A pointer to the member function to call.  If the member function is
+//     // virtual, this will be a thunk that forwards to the appropriate vftable
+//     // slot.
+//     void *FunctionPointerOrVirtualThunk;
+//
+//     // An offset to add to the address of the vbtable pointer after (possibly)
+//     // selecting the virtual base but before resolving and calling the function.
+//     // Only needed if the class has any virtual bases or bases at a non-zero
+//     // offset.
+//     int NonVirtualBaseAdjustment;
+//
+//     // An offset within the vb-table that selects the virtual base containing
+//     // the member.  Loading from this offset produces a new offset that is
+//     // added to the address of the vb-table pointer to produce the base.
+//     int VirtualBaseAdjustmentOffset;
+//
+//     // The offset of the vb-table pointer within the object.  Only needed for
+//     // incomplete types.
+//     int VBTableOffset;
+//   };
+std::pair<unsigned, unsigned> MemberPointerType::getMSMemberPointerSlots() const {
+  MSInheritanceModel Inheritance = this->getMSInheritanceModel();
+  unsigned Ptrs;
+  unsigned Ints = 0;
+  if (this->isMemberFunctionPointer()) {
     // Member function pointers are a struct of a function pointer followed by a
     // variable number of ints depending on the inheritance model used.  The
     // function pointer is a real function if it is non-virtual and a vftable
     // slot thunk if it is virtual.  The ints select the object base passed for
     // the 'this' pointer.
-    Align = Target.getPointerAlign(0);
+    Ptrs = 1;  // First slot is always a function pointer.
     switch (Inheritance) {
-    case attr::SingleInheritance:      Width = PtrSize;               break;
-    case attr::MultipleInheritance:    Width = PtrSize + 1 * IntSize; break;
-    case attr::VirtualInheritance:     Width = PtrSize + 2 * IntSize; break;
-    case attr::UnspecifiedInheritance: Width = PtrSize + 3 * IntSize; break;
     default: llvm_unreachable("unknown inheritance model");
+    case IHM_Unspecified: ++Ints;  // VBTableOffset
+    case IHM_Virtual:     ++Ints;  // VirtualBaseAdjustmentOffset
+    case IHM_Multiple:    ++Ints;  // NonVirtualBaseAdjustment
+    case IHM_Single:      break;   // Nothing
     }
   } else {
     // Data pointers are an aggregate of ints.  The first int is an offset
     // followed by vbtable-related offsets.
-    Align = Target.getIntAlign();
+    Ptrs = 0;
     switch (Inheritance) {
-    case attr::SingleInheritance:       // Same as multiple inheritance.
-    case attr::MultipleInheritance:     Width = 1 * IntSize; break;
-    case attr::VirtualInheritance:      Width = 2 * IntSize; break;
-    case attr::UnspecifiedInheritance:  Width = 3 * IntSize; break;
     default: llvm_unreachable("unknown inheritance model");
+    case IHM_Unspecified: ++Ints;  // VBTableOffset
+    case IHM_Virtual:     ++Ints;  // VirtualBaseAdjustmentOffset
+    case IHM_Multiple:             // Nothing
+    case IHM_Single:      ++Ints;  // Field offset
     }
   }
-  Width = llvm::RoundUpToAlignment(Width, Align);
+  return std::make_pair(Ptrs, Ints);
+}
 
-  // FIXME: Verify that our alignment matches MSVC.
+std::pair<uint64_t, unsigned>
+MicrosoftCXXABI::getMemberPointerWidthAndAlign(const MemberPointerType *MPT) const {
+  const CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl();
+  const TargetInfo &Target = Context.getTargetInfo();
+  assert(Target.getTriple().getArch() == llvm::Triple::x86 ||
+         Target.getTriple().getArch() == llvm::Triple::x86_64);
+  unsigned Ptrs, Ints;
+  llvm::tie(Ptrs, Ints) = MPT->getMSMemberPointerSlots();
+  // The nominal struct is laid out with pointers followed by ints and aligned
+  // to a pointer width if any are present and an int width otherwise.
+  unsigned PtrSize = Target.getPointerWidth(0);
+  unsigned IntSize = Target.getIntWidth();
+  uint64_t Width = Ptrs * PtrSize + Ints * IntSize;
+  unsigned Align = Ptrs > 0 ? Target.getPointerAlign(0) : Target.getIntAlign();
+  Width = llvm::RoundUpToAlignment(Width, Align);
   return std::make_pair(Width, Align);
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D590.1.patch
Type: text/x-patch
Size: 8052 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130328/30427741/attachment.bin>


More information about the cfe-commits mailing list