[cfe-commits] r83426 - in /cfe/trunk: lib/CodeGen/CGCXX.cpp lib/CodeGen/CGCXXClass.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/virtual-base-cast.cpp

Anders Carlsson andersca at mac.com
Tue Oct 6 15:43:30 PDT 2009


Author: andersca
Date: Tue Oct  6 17:43:30 2009
New Revision: 83426

URL: http://llvm.org/viewvc/llvm-project?rev=83426&view=rev
Log:
Change GetAddressCXXOfBaseClass to use CXXBasePaths for calculating base class offsets. Fix the code to handle virtual bases as well.

Added:
    cfe/trunk/test/CodeGenCXX/virtual-base-cast.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGCXXClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=83426&r1=83425&r2=83426&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Tue Oct  6 17:43:30 2009
@@ -782,8 +782,8 @@
       return i->second;
     // FIXME: temporal botch, is this data here, by the time we need it?
 
-    // FIXME: Locate the containing virtual base first.
-    return 42;
+    assert(false && "FIXME: Locate the containing virtual base first");
+    return 0;
   }
 
   bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m,
@@ -888,18 +888,26 @@
       const CXXRecordDecl *RD = i->first;
       int64_t Offset = i->second;
       for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
-           ++mi)
-        if (mi->isVirtual()) {
-          const CXXMethodDecl *MD = *mi;
+           ++mi) {
+        if (!mi->isVirtual())
+          continue;
+
+        const CXXMethodDecl *MD = *mi;
+        llvm::Constant *m = 0;
+//        if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
+//          m = wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
+//        else {
           const FunctionProtoType *FPT = 
             MD->getType()->getAs<FunctionProtoType>();
           const llvm::Type *Ty =
             CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
                                            FPT->isVariadic());
           
-          llvm::Constant *m = wrap(CGM.GetAddrOfFunction(MD, Ty));
-          OverrideMethod(MD, m, MorallyVirtual, Offset);
-        }
+          m = wrap(CGM.GetAddrOfFunction(MD, Ty));
+//        }
+
+        OverrideMethod(MD, m, MorallyVirtual, Offset);
+      }
     }
   }
 
@@ -1323,6 +1331,36 @@
 }
 
 llvm::Value *
+CodeGenFunction::GetVirtualCXXBaseClassOffset(llvm::Value *This,
+                                              const CXXRecordDecl *ClassDecl,
+                                           const CXXRecordDecl *BaseClassDecl) {
+  // FIXME: move to Context
+  if (vtableinfo == 0)
+    vtableinfo = new VtableInfo(CGM);
+  
+  const llvm::Type *Int8PtrTy = 
+    llvm::Type::getInt8Ty(VMContext)->getPointerTo();
+
+  llvm::Value *VTablePtr = Builder.CreateBitCast(This, 
+                                                 Int8PtrTy->getPointerTo());
+  VTablePtr = Builder.CreateLoad(VTablePtr, "vtable");
+
+  llvm::Value *VBaseOffsetPtr = 
+    Builder.CreateConstGEP1_64(VTablePtr, 
+                               vtableinfo->VBlookup(ClassDecl, BaseClassDecl),
+                               "vbase.offset.ptr");
+  const llvm::Type *PtrDiffTy = 
+    ConvertType(getContext().getPointerDiffType());
+  
+  VBaseOffsetPtr = Builder.CreateBitCast(VBaseOffsetPtr, 
+                                         PtrDiffTy->getPointerTo());
+                                         
+  llvm::Value *VBaseOffset = Builder.CreateLoad(VBaseOffsetPtr, "vbase.offset");
+  
+  return VBaseOffset;
+}
+
+llvm::Value *
 CodeGenFunction::BuildVirtualCall(const CXXMethodDecl *MD, llvm::Value *&This,
                                   const llvm::Type *Ty) {
   // FIXME: If we know the dynamic type, we don't have to do a virtual dispatch.

Modified: cfe/trunk/lib/CodeGen/CGCXXClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXXClass.cpp?rev=83426&r1=83425&r2=83426&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXXClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXXClass.cpp Tue Oct  6 17:43:30 2009
@@ -12,61 +12,35 @@
 //===----------------------------------------------------------------------===//
 
 #include "CodeGenFunction.h"
+#include "clang/AST/CXXInheritance.h"
 #include "clang/AST/RecordLayout.h"
+
 using namespace clang;
 using namespace CodeGen;
 
-static bool
-GetNestedPaths(llvm::SmallVectorImpl<const CXXRecordDecl *> &NestedBasePaths,
-               const CXXRecordDecl *ClassDecl,
-               const CXXRecordDecl *BaseClassDecl) {
-  for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
-      e = ClassDecl->bases_end(); i != e; ++i) {
-    if (i->isVirtual())
-      continue;
-    const CXXRecordDecl *Base =
-      cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-    if (Base == BaseClassDecl) {
-      NestedBasePaths.push_back(BaseClassDecl);
-      return true;
-    }
-  }
-  // BaseClassDecl not an immediate base of ClassDecl.
-  for (CXXRecordDecl::base_class_const_iterator i = ClassDecl->bases_begin(),
-       e = ClassDecl->bases_end(); i != e; ++i) {
-    if (i->isVirtual())
-      continue;
-    const CXXRecordDecl *Base =
-      cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
-    if (GetNestedPaths(NestedBasePaths, Base, BaseClassDecl)) {
-      NestedBasePaths.push_back(Base);
-      return true;
-    }
-  }
-  return false;
-}
+static uint64_t 
+ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths,
+                                 unsigned Start) {
+  uint64_t Offset = 0;
+
+  const CXXBasePath &Path = Paths.front();
+  for (unsigned i = Start, e = Path.size(); i != e; ++i) {
+    const CXXBasePathElement& Element = Path[i];
 
-static uint64_t ComputeBaseClassOffset(ASTContext &Context,
-                                       const CXXRecordDecl *ClassDecl,
-                                       const CXXRecordDecl *BaseClassDecl) {
-    uint64_t Offset = 0;
-
-    llvm::SmallVector<const CXXRecordDecl *, 16> NestedBasePaths;
-    GetNestedPaths(NestedBasePaths, ClassDecl, BaseClassDecl);
-    assert(NestedBasePaths.size() > 0 &&
-           "AddressCXXOfBaseClass - inheritence path failed");
-    NestedBasePaths.push_back(ClassDecl);
-    
-    for (unsigned i = NestedBasePaths.size() - 1; i > 0; i--) {
-        const CXXRecordDecl *DerivedClass = NestedBasePaths[i];
-        const CXXRecordDecl *BaseClass = NestedBasePaths[i-1];
-        const ASTRecordLayout &Layout = 
-            Context.getASTRecordLayout(DerivedClass);
-        
-        Offset += Layout.getBaseClassOffset(BaseClass) / 8;
-    }
+    // Get the layout.
+    const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class);
+    
+    const CXXBaseSpecifier *BS = Element.Base;
+    assert(!BS->isVirtual() && "Should not see virtual bases here!");
+    
+    const CXXRecordDecl *Base = 
+      cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl());
     
-    return Offset;
+    // Add the offset.
+    Offset += Layout.getBaseClassOffset(Base) / 8;
+  }
+
+  return Offset;
 }
 
 llvm::Constant *
@@ -75,12 +49,15 @@
   if (ClassDecl == BaseClassDecl)
     return 0;
 
-  QualType BTy =
-    getContext().getCanonicalType(
-      getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
+  CXXBasePaths Paths(/*FindAmbiguities=*/false,
+                     /*RecordPaths=*/true, /*DetectVirtual=*/false);
+  if (!const_cast<CXXRecordDecl *>(ClassDecl)->
+        isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+    assert(false && "Class must be derived from the passed in base class!");
+    return 0;
+  }
 
-  uint64_t Offset = ComputeBaseClassOffset(getContext(), 
-                                           ClassDecl, BaseClassDecl);
+  uint64_t Offset = ComputeNonVirtualBaseClassOffset(getContext(), Paths, 0);
   if (!Offset)
     return 0;
 
@@ -90,19 +67,63 @@
   return llvm::ConstantInt::get(PtrDiffTy, Offset);
 }
 
+static llvm::Value *GetCXXBaseClassOffset(CodeGenFunction &CGF,
+                                          llvm::Value *BaseValue,
+                                          const CXXRecordDecl *ClassDecl,
+                                          const CXXRecordDecl *BaseClassDecl) {
+  CXXBasePaths Paths(/*FindAmbiguities=*/false,
+                     /*RecordPaths=*/true, /*DetectVirtual=*/true);
+  if (!const_cast<CXXRecordDecl *>(ClassDecl)->
+        isDerivedFrom(const_cast<CXXRecordDecl *>(BaseClassDecl), Paths)) {
+    assert(false && "Class must be derived from the passed in base class!");
+    return 0;
+  }
+
+  unsigned Start = 0;
+  llvm::Value *VirtualOffset = 0;
+  if (const RecordType *RT = Paths.getDetectedVirtual()) {
+    const CXXRecordDecl *VBase = cast<CXXRecordDecl>(RT->getDecl());
+    
+    VirtualOffset = 
+      CGF.GetVirtualCXXBaseClassOffset(BaseValue, ClassDecl, VBase);
+    
+    const CXXBasePath &Path = Paths.front();
+    unsigned e = Path.size();
+    for (Start = 0; Start != e; ++Start) {
+      const CXXBasePathElement& Element = Path[Start];
+      
+      if (Element.Class == VBase)
+        break;
+    }
+  }
+  
+  uint64_t Offset = 
+    ComputeNonVirtualBaseClassOffset(CGF.getContext(), Paths, Start);
+  
+  if (!Offset)
+    return VirtualOffset;
+  
+  const llvm::Type *PtrDiffTy = 
+    CGF.ConvertType(CGF.getContext().getPointerDiffType());
+  llvm::Value *NonVirtualOffset = llvm::ConstantInt::get(PtrDiffTy, Offset);
+  
+  if (VirtualOffset)
+    return CGF.Builder.CreateAdd(VirtualOffset, NonVirtualOffset);
+                    
+  return NonVirtualOffset;
+}
+
 llvm::Value *
 CodeGenFunction::GetAddressCXXOfBaseClass(llvm::Value *BaseValue,
                                           const CXXRecordDecl *ClassDecl,
                                           const CXXRecordDecl *BaseClassDecl,
                                           bool NullCheckValue) {
-  llvm::Constant *Offset = CGM.GetCXXBaseClassOffset(ClassDecl, BaseClassDecl);
-  
   QualType BTy =
     getContext().getCanonicalType(
       getContext().getTypeDeclType(const_cast<CXXRecordDecl*>(BaseClassDecl)));
   const llvm::Type *BasePtrTy = llvm::PointerType::getUnqual(ConvertType(BTy));
 
-  if (!Offset) {
+  if (ClassDecl == BaseClassDecl) {
     // Just cast back.
     return Builder.CreateBitCast(BaseValue, BasePtrTy);
   }
@@ -125,10 +146,15 @@
   
   const llvm::Type *Int8PtrTy = 
     llvm::PointerType::getUnqual(llvm::Type::getInt8Ty(VMContext));
+
+  llvm::Value *Offset = 
+    GetCXXBaseClassOffset(*this, BaseValue, ClassDecl, BaseClassDecl);
   
-  // Apply the offset.
-  BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
-  BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+  if (Offset) {
+    // Apply the offset.
+    BaseValue = Builder.CreateBitCast(BaseValue, Int8PtrTy);
+    BaseValue = Builder.CreateGEP(BaseValue, Offset, "add.ptr");
+  }
   
   // Cast back.
   BaseValue = Builder.CreateBitCast(BaseValue, BasePtrTy);

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=83426&r1=83425&r2=83426&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Oct  6 17:43:30 2009
@@ -589,6 +589,11 @@
                                         const CXXRecordDecl *BaseClassDecl,
                                         bool NullCheckValue);
   
+  llvm::Value *
+  GetVirtualCXXBaseClassOffset(llvm::Value *This,
+                               const CXXRecordDecl *ClassDecl,
+                               const CXXRecordDecl *BaseClassDecl);
+    
   void EmitClassAggrMemberwiseCopy(llvm::Value *DestValue,
                                    llvm::Value *SrcValue,
                                    const ArrayType *Array,

Added: cfe/trunk/test/CodeGenCXX/virtual-base-cast.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-base-cast.cpp?rev=83426&view=auto

==============================================================================
--- cfe/trunk/test/CodeGenCXX/virtual-base-cast.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/virtual-base-cast.cpp Tue Oct  6 17:43:30 2009
@@ -0,0 +1,9 @@
+// RUN: clang-cc -emit-llvm-only %s
+
+struct A { virtual ~A(); };
+struct B : A { virtual ~B(); };
+struct C : virtual B { virtual ~C(); };
+
+void f(C *c) {
+  A* a = c;
+}
\ No newline at end of file





More information about the cfe-commits mailing list