Hi rjmccall,

For non-dynamic classes (no virtual bases), member data pointers are
simple offsets from the base of the record.  Dynamic classes use an
aggregate for member data pointers and are therefore currently
unsupported.

Unlike Itanium, the ms ABI uses 0 to represent null for polymorphic
classes.  Non-polymorphic classes use -1 like Itanium, since 0 is a
valid field offset.

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

Files:
  lib/CodeGen/CGCXXABI.cpp
  lib/CodeGen/CGCXXABI.h
  lib/CodeGen/ItaniumCXXABI.cpp
  lib/CodeGen/MicrosoftCXXABI.cpp
  test/CodeGenCXX/microsoft-abi-member-pointers.cpp
Index: lib/CodeGen/CGCXXABI.cpp
===================================================================
--- lib/CodeGen/CGCXXABI.cpp
+++ lib/CodeGen/CGCXXABI.cpp
@@ -19,18 +19,16 @@
 
 CGCXXABI::~CGCXXABI() { }
 
-static void ErrorUnsupportedABI(CodeGenFunction &CGF,
-                                StringRef S) {
+void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) {
   DiagnosticsEngine &Diags = CGF.CGM.getDiags();
   unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error,
                                           "cannot yet compile %0 in this ABI");
   Diags.Report(CGF.getContext().getFullLoc(CGF.CurCodeDecl->getLocation()),
                DiagID)
     << S;
 }
 
-static llvm::Constant *GetBogusMemberPointer(CodeGenModule &CGM,
-                                             QualType T) {
+llvm::Constant *CGCXXABI::GetBogusMemberPointer(QualType T) {
   return llvm::Constant::getNullValue(CGM.getTypes().ConvertType(T));
 }
 
@@ -67,12 +65,12 @@
                                                    const CastExpr *E,
                                                    llvm::Value *Src) {
   ErrorUnsupportedABI(CGF, "member function pointer conversions");
-  return GetBogusMemberPointer(CGM, E->getType());
+  return GetBogusMemberPointer(E->getType());
 }
 
 llvm::Constant *CGCXXABI::EmitMemberPointerConversion(const CastExpr *E,
                                                       llvm::Constant *Src) {
-  return GetBogusMemberPointer(CGM, E->getType());
+  return GetBogusMemberPointer(E->getType());
 }
 
 llvm::Value *
@@ -95,22 +93,22 @@
 
 llvm::Constant *
 CGCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
-  return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+  return GetBogusMemberPointer(QualType(MPT, 0));
 }
 
 llvm::Constant *CGCXXABI::EmitMemberPointer(const CXXMethodDecl *MD) {
-  return GetBogusMemberPointer(CGM,
+  return GetBogusMemberPointer(
                          CGM.getContext().getMemberPointerType(MD->getType(),
                                          MD->getParent()->getTypeForDecl()));
 }
 
 llvm::Constant *CGCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
                                                 CharUnits offset) {
-  return GetBogusMemberPointer(CGM, QualType(MPT, 0));
+  return GetBogusMemberPointer(QualType(MPT, 0));
 }
 
 llvm::Constant *CGCXXABI::EmitMemberPointer(const APValue &MP, QualType MPT) {
-  return GetBogusMemberPointer(CGM, MPT);
+  return GetBogusMemberPointer(MPT);
 }
 
 bool CGCXXABI::isZeroInitializable(const MemberPointerType *MPT) {
Index: lib/CodeGen/CGCXXABI.h
===================================================================
--- lib/CodeGen/CGCXXABI.h
+++ lib/CodeGen/CGCXXABI.h
@@ -42,9 +42,11 @@
 protected:
   CodeGenModule &CGM;
   OwningPtr<MangleContext> MangleCtx;
+  llvm::IntegerType *PtrDiffTy;
 
   CGCXXABI(CodeGenModule &CGM)
-    : CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()) {}
+    : CGM(CGM), MangleCtx(CGM.getContext().createMangleContext()),
+      PtrDiffTy(0) {}
 
 protected:
   ImplicitParamDecl *&getThisDecl(CodeGenFunction &CGF) {
@@ -54,6 +56,22 @@
     return CGF.CXXABIThisValue;
   }
 
+  // It's a little silly for us to cache this.
+  llvm::IntegerType *getPtrDiffTy() {
+    if (!PtrDiffTy) {
+      QualType T = getContext().getPointerDiffType();
+      llvm::Type *Ty = CGM.getTypes().ConvertType(T);
+      PtrDiffTy = cast<llvm::IntegerType>(Ty);
+    }
+    return PtrDiffTy;
+  }
+
+  /// Issue a diagnostic about unsupported features in the ABI.
+  void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S);
+
+  /// Get a null value for unsupported member pointers.
+  llvm::Constant *GetBogusMemberPointer(QualType T);
+
   // FIXME: Every place that calls getVTT{Decl,Value} is something
   // that needs to be abstracted properly.
   ImplicitParamDecl *&getVTTDecl(CodeGenFunction &CGF) {
Index: lib/CodeGen/ItaniumCXXABI.cpp
===================================================================
--- lib/CodeGen/ItaniumCXXABI.cpp
+++ lib/CodeGen/ItaniumCXXABI.cpp
@@ -34,24 +34,12 @@
 
 namespace {
 class ItaniumCXXABI : public CodeGen::CGCXXABI {
-private:
-  llvm::IntegerType *PtrDiffTy;
 protected:
   bool IsARM;
 
-  // It's a little silly for us to cache this.
-  llvm::IntegerType *getPtrDiffTy() {
-    if (!PtrDiffTy) {
-      QualType T = getContext().getPointerDiffType();
-      llvm::Type *Ty = CGM.getTypes().ConvertType(T);
-      PtrDiffTy = cast<llvm::IntegerType>(Ty);
-    }
-    return PtrDiffTy;
-  }
-
 public:
   ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
-    CGCXXABI(CGM), PtrDiffTy(0), IsARM(IsARM) { }
+    CGCXXABI(CGM), IsARM(IsARM) { }
 
   bool isZeroInitializable(const MemberPointerType *MPT);
 
Index: lib/CodeGen/MicrosoftCXXABI.cpp
===================================================================
--- lib/CodeGen/MicrosoftCXXABI.cpp
+++ lib/CodeGen/MicrosoftCXXABI.cpp
@@ -109,6 +109,28 @@
                                    llvm::Value *allocPtr,
                                    CharUnits cookieSize);
   static bool needThisReturn(GlobalDecl GD);
+
+private:
+  llvm::Constant *
+  getNullMemberDataPointer(const MemberPointerType *MPT);
+
+public:
+  virtual llvm::Constant *EmitNullMemberPointer(const MemberPointerType *MPT);
+
+  virtual llvm::Constant *EmitMemberDataPointer(const MemberPointerType *MPT,
+                                                CharUnits offset);
+
+  virtual llvm::Value *
+  EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+                             llvm::Value *MemPtr,
+                             const MemberPointerType *MPT);
+
+  virtual llvm::Value *
+  EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+                               llvm::Value *Base,
+                               llvm::Value *MemPtr,
+                               const MemberPointerType *MPT);
+
 };
 
 }
@@ -351,6 +373,96 @@
   CGF.EmitCXXGlobalVarDeclInit(D, DeclPtr, PerformInit);
 }
 
+// A null member data pointer is represented as -1 if the class is not
+// polymorphic, and 0 otherwise.
+llvm::Constant *
+MicrosoftCXXABI::getNullMemberDataPointer(const MemberPointerType *MPT) {
+  assert(MPT->isMemberDataPointer());
+  llvm::Constant *Zero = llvm::ConstantInt::get(getPtrDiffTy(), 0);
+  llvm::Constant *AllOnes = llvm::Constant::getAllOnesValue(getPtrDiffTy());
+  const CXXRecordDecl *RD =
+    cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+  if (RD->getNumVBases() == 0) {
+    if (RD->isPolymorphic())
+      return Zero;
+    return AllOnes;
+  }
+  // The null representation is {field: 0, vbtable: -1}.
+  // FIXME: In the Itanium ABI, member data pointers are always scalars.
+  // Returning this aggregate will assert until we change codegen.
+  assert(RD->getNumVBases() == 0 && "implement dynamic class member pointers");
+  llvm::Constant *Values[2] = { Zero, AllOnes };
+  return llvm::ConstantStruct::getAnon(Values);
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitNullMemberPointer(const MemberPointerType *MPT) {
+  if (MPT->isMemberDataPointer())
+    return getNullMemberDataPointer(MPT);
+  // FIXME: Implement function member pointers.
+  return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Constant *
+MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT,
+                                       CharUnits offset) {
+  const CXXRecordDecl *RD =
+    cast<CXXRecordDecl>(MPT->getClass()->getAs<RecordType>()->getDecl());
+  // Member data pointers are plain offsets when no virtual bases are involved.
+  if (RD->getNumVBases() == 0)
+    return llvm::ConstantInt::get(getPtrDiffTy(), offset.getQuantity());
+  // FIXME: Emit a pair of {vbtable offset, field offset} when we know vbtable
+  // layout.
+  return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberPointerIsNotNull(CodeGenFunction &CGF,
+                                            llvm::Value *MemPtr,
+                                            const MemberPointerType *MPT) {
+  CGBuilderTy &Builder = CGF.Builder;
+
+  // For member data pointers, this is just a check against -1 or 0.
+  if (MPT->isMemberDataPointer()) {
+    assert(MemPtr->getType() == getPtrDiffTy());
+    llvm::Constant *Val = getNullMemberDataPointer(MPT);
+    return Builder.CreateICmpNE(MemPtr, Val, "memptr.tobool");
+  }
+
+  // FIXME: Implement function member pointers.
+  ErrorUnsupportedABI(CGF, "function member pointer tests");
+  return GetBogusMemberPointer(QualType(MPT, 0));
+}
+
+llvm::Value *
+MicrosoftCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF,
+                                              llvm::Value *Base,
+                                              llvm::Value *MemPtr,
+                                              const MemberPointerType *MPT) {
+  unsigned AS = Base->getType()->getPointerAddressSpace();
+  llvm::Type *PType =
+      CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS);
+
+  if (MPT->isMemberFunctionPointer()) {
+    ErrorUnsupportedABI(CGF, "function member pointer address");
+    return llvm::Constant::getNullValue(PType);
+  }
+  if (MemPtr->getType() != getPtrDiffTy()) {
+    // If it's not a ptrdiff_t, then it's an aggregate.
+    ErrorUnsupportedABI(CGF, "non-scalar member pointers");
+    return llvm::Constant::getNullValue(PType);
+  }
+
+  // Simply add the offset with GEP and i8*.
+  CGBuilderTy &Builder = CGF.Builder;
+  Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS));
+  llvm::Value *Addr = Builder.CreateInBoundsGEP(Base, MemPtr, "memptr.offset");
+
+  // Cast the address to the appropriate pointer type, adopting the
+  // address space of the base pointer.
+  return Builder.CreateBitCast(Addr, PType);
+}
+
 CGCXXABI *clang::CodeGen::CreateMicrosoftCXXABI(CodeGenModule &CGM) {
   return new MicrosoftCXXABI(CGM);
 }
Index: test/CodeGenCXX/microsoft-abi-member-pointers.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -emit-llvm %s -o - -cxx-abi microsoft -triple=i386-pc-win32 | FileCheck %s
+
+struct POD {
+  int a;
+  int b;
+};
+
+void podMemPtrs() {
+  int POD::*memptr;
+  memptr = &POD::a;
+  // CHECK: store i32 0,
+  memptr = &POD::b;
+  // CHECK: store i32 4,
+  if (memptr)
+    memptr = 0;
+  // Null is -1.
+  // CHECK: icmp ne i32 %{{.*}}, -1
+  // CHECK: store i32 -1,
+}
+
+struct Polymorphic {
+  virtual void myVirtual();
+  int a;
+  int b;
+};
+
+void polymorphicMemPtrs() {
+  int Polymorphic::*memptr;
+  memptr = &Polymorphic::a;
+  // CHECK: store i32 4,
+  memptr = &Polymorphic::b;
+  // CHECK: store i32 8,
+  if (memptr)
+    memptr = 0;
+  // Null is zero.
+  // CHECK: icmp ne i32 %{{.*}}, 0
+  // CHECK: store i32 0,
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to