[cfe-commits] r95965 - in /cfe/trunk: lib/CodeGen/CGVtable.cpp test/CodeGenCXX/vtable-layout.cpp

Anders Carlsson andersca at mac.com
Thu Feb 11 21:25:37 PST 2010


Author: andersca
Date: Thu Feb 11 23:25:12 2010
New Revision: 95965

URL: http://llvm.org/viewvc/llvm-project?rev=95965&view=rev
Log:
More work on vtable layout. We can now layout vtables with primary bases.

Modified:
    cfe/trunk/lib/CodeGen/CGVtable.cpp
    cfe/trunk/test/CodeGenCXX/vtable-layout.cpp

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Thu Feb 11 23:25:12 2010
@@ -99,6 +99,17 @@
   return TypeConversionRequiresAdjustment(Ctx, DerivedDecl, BaseDecl);
 }
 
+static bool
+ReturnTypeConversionRequiresAdjustment(ASTContext &Context,
+                                       const CXXMethodDecl *DerivedMD,
+                                       const CXXMethodDecl *BaseMD) {
+  const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>();
+  const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>();
+
+  return TypeConversionRequiresAdjustment(Context, DerivedFT->getResultType(), 
+                                          BaseFT->getResultType());
+}
+
 namespace {
 
 /// FinalOverriders - Contains the final overrider member functions for all
@@ -248,6 +259,9 @@
                                        OverriddenMD)];
       assert(Overrider && "Did not find existing overrider!");
 
+      assert(!ReturnTypeConversionRequiresAdjustment(Context, NewMD, 
+                                                     OverriddenMD) &&
+             "FIXME: Covariant return types not handled yet!");
       // Set the new overrider.
       Overrider = NewMD;
       
@@ -470,12 +484,17 @@
 
 /// VtableBuilder - Class for building vtable layout information.
 class VtableBuilder {
+public:
+  /// PrimaryBasesSetTy - A set of direct and indirect primary bases.
+  typedef llvm::SmallPtrSet<const CXXRecordDecl *, 8> PrimaryBasesSetTy;
+
+private:
   /// MostDerivedClass - The most derived class for which we're building this
   /// vtable.
   const CXXRecordDecl *MostDerivedClass;
 
   /// Context - The ASTContext which we will use for layout information.
-  const ASTContext &Context;
+  ASTContext &Context;
   
   /// FinalOverriders - The final overriders of the most derived class.
   FinalOverriders Overriders;
@@ -486,42 +505,85 @@
   /// AddressPoints - Address points for the vtable being built.
   CGVtableInfo::AddressPointsMapTy AddressPoints;
 
+  void layoutVirtualMemberFunctions(BaseSubobject Base,
+                                    PrimaryBasesSetTy &PrimaryBases);
+  
   /// layoutSimpleVtable - A test function that will layout very simple vtables
   /// without any bases. Just used for testing for now.
-  void layoutSimpleVtable(const CXXRecordDecl *RD);
+  void layoutSimpleVtable(BaseSubobject Base);
   
 public:
   VtableBuilder(const CXXRecordDecl *MostDerivedClass)
     : MostDerivedClass(MostDerivedClass), 
     Context(MostDerivedClass->getASTContext()), Overriders(MostDerivedClass) { 
 
-    layoutSimpleVtable(MostDerivedClass);      
+    layoutSimpleVtable(BaseSubobject(MostDerivedClass, 0));
   }
 
   /// dumpLayout - Dump the vtable layout.
   void dumpLayout(llvm::raw_ostream&);
 };
 
-void VtableBuilder::layoutSimpleVtable(const CXXRecordDecl *RD) {
-  assert(!RD->getNumBases() && 
-         "We don't support layout for vtables with bases right now!");
-  
-  // First, add the offset to top.
-  Components.push_back(VtableComponent::MakeOffsetToTop(0));
-  
-  // Next, add the RTTI.
-  Components.push_back(VtableComponent::MakeRTTI(RD));
-  
-  // Record the address point.
-  AddressPoints.insert(std::make_pair(BaseSubobject(RD, 0), Components.size()));
+/// OverridesMethodInPrimaryBase - Checks whether whether this virtual member 
+/// function overrides a member function in a direct or indirect primary base.
+/// Returns the overridden member function, or null if none was found.
+static const CXXMethodDecl * 
+OverridesMethodInPrimaryBase(const CXXMethodDecl *MD,
+                             VtableBuilder::PrimaryBasesSetTy &PrimaryBases) {
+  for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(),
+       E = MD->end_overridden_methods(); I != E; ++I) {
+    const CXXMethodDecl *OverriddenMD = *I;
+    const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
+    assert(OverriddenMD->isCanonicalDecl() &&
+           "Should have the canonical decl of the overridden RD!");
+    
+    if (PrimaryBases.count(OverriddenRD))
+      return OverriddenMD;
+  }
+      
+  return 0;
+}
+
+void 
+VtableBuilder::layoutVirtualMemberFunctions(BaseSubobject Base,
+                                            PrimaryBasesSetTy &PrimaryBases) {
+  const CXXRecordDecl *RD = Base.getBase();
+
+  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+
+  if (const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase()) {
+    if (Layout.getPrimaryBaseWasVirtual())
+      assert(false && "FIXME: Handle vbases here.");
+    else
+      assert(Layout.getBaseClassOffset(PrimaryBase) == 0 &&
+             "Primary base should have a zero offset!");
+    
+    layoutVirtualMemberFunctions(BaseSubobject(PrimaryBase, 0), PrimaryBases);
+    
+    if (!PrimaryBases.insert(PrimaryBase))
+      assert(false && "Found a duplicate primary base!");
+  }
 
   // Now go through all virtual member functions and add them.
   for (CXXRecordDecl::method_iterator I = RD->method_begin(),
        E = RD->method_end(); I != E; ++I) {
     const CXXMethodDecl *MD = *I;
-    
+  
     if (!MD->isVirtual())
       continue;
+
+    // Get the final overrider.
+    const CXXMethodDecl *Overrider = Overriders.getOverrider(Base, MD);
+
+    // Check if this virtual member function overrides a method in a primary
+    // base. If this is the case, and the return type doesn't require adjustment
+    // then we can just use the member function from the primary base.
+    if (OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+      assert(!ReturnTypeConversionRequiresAdjustment(Context, Overrider, MD) &&
+             "FIXME: Handle covariant thunks!");
+      
+      continue;
+    }
     
     if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
       // Add both the complete destructor and the deleting destructor.
@@ -534,6 +596,42 @@
   }
 }
 
+void VtableBuilder::layoutSimpleVtable(BaseSubobject Base) {
+  const CXXRecordDecl *RD = Base.getBase();
+  
+  // First, add the offset to top.
+  Components.push_back(VtableComponent::MakeOffsetToTop(0));
+  
+  // Next, add the RTTI.
+  Components.push_back(VtableComponent::MakeRTTI(RD));
+  
+  // Record the address point.
+  // FIXME: Record the address point for all primary bases.
+  AddressPoints.insert(std::make_pair(Base, Components.size()));
+
+  // Now go through all virtual member functions and add them.
+  PrimaryBasesSetTy PrimaryBases;
+  layoutVirtualMemberFunctions(Base, PrimaryBases);
+
+  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+  const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
+
+  // Traverse bases.
+  for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(),
+       E = RD->bases_end(); I != E; ++I) {
+    const CXXRecordDecl *BaseDecl = 
+      cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
+    
+    // Ignore the primary base.
+    if (BaseDecl == PrimaryBase)
+      continue;
+    
+    assert(!I->isVirtual() && "FIXME: Handle virtual bases");
+    
+    assert(false && "FIXME: Handle secondary virtual tables!");
+  }
+}
+
 /// dumpLayout - Dump the vtable layout.
 void VtableBuilder::dumpLayout(llvm::raw_ostream& Out) {
   
@@ -1726,7 +1824,7 @@
 
   // Collect all the primary bases, so we can check whether methods override
   // a method from the base.
-  llvm::SmallPtrSet<const CXXRecordDecl *, 5> PrimaryBases;
+  VtableBuilder::PrimaryBasesSetTy PrimaryBases;
   for (ASTRecordLayout::primary_base_info_iterator
        I = Layout.primary_base_begin(), E = Layout.primary_base_end();
        I != E; ++I)
@@ -1745,42 +1843,30 @@
     bool ShouldAddEntryForMethod = true;
     
     // Check if this method overrides a method in the primary base.
-    for (CXXMethodDecl::method_iterator i = MD->begin_overridden_methods(),
-         e = MD->end_overridden_methods(); i != e; ++i) {
-      const CXXMethodDecl *OverriddenMD = *i;
-      const CXXRecordDecl *OverriddenRD = OverriddenMD->getParent();
-      assert(OverriddenMD->isCanonicalDecl() &&
-             "Should have the canonical decl of the overridden RD!");
-      
-      if (PrimaryBases.count(OverriddenRD)) {
-        // Check if converting from the return type of the method to the 
-        // return type of the overridden method requires conversion.
-        QualType ReturnType = 
-          MD->getType()->getAs<FunctionType>()->getResultType();
-        QualType OverriddenReturnType =
-          OverriddenMD->getType()->getAs<FunctionType>()->getResultType();
-        
-        if (!TypeConversionRequiresAdjustment(CGM.getContext(), 
-                                            ReturnType, OverriddenReturnType)) {
-          // This index is shared between the index in the vtable of the primary
-          // base class.
-          if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
-            const CXXDestructorDecl *OverriddenDD = 
-              cast<CXXDestructorDecl>(OverriddenMD);
-            
-            // Add both the complete and deleting entries.
-            MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = 
-              getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
-            MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = 
-              getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
-          } else {
-            MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
-          }
+    if (const CXXMethodDecl *OverriddenMD = 
+          OverridesMethodInPrimaryBase(MD, PrimaryBases)) {
+      // Check if converting from the return type of the method to the 
+      // return type of the overridden method requires conversion.
+      if (!ReturnTypeConversionRequiresAdjustment(CGM.getContext(), 
+                                                  MD, OverriddenMD)) {
+        // This index is shared between the index in the vtable of the primary
+        // base class.
+        if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) {
+          const CXXDestructorDecl *OverriddenDD = 
+            cast<CXXDestructorDecl>(OverriddenMD);
           
-          // We don't need to add an entry for this method.
-          ShouldAddEntryForMethod = false;
-          break;
-        }        
+          // Add both the complete and deleting entries.
+          MethodVtableIndices[GlobalDecl(DD, Dtor_Complete)] = 
+            getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Complete));
+          MethodVtableIndices[GlobalDecl(DD, Dtor_Deleting)] = 
+            getMethodVtableIndex(GlobalDecl(OverriddenDD, Dtor_Deleting));
+        } else {
+          MethodVtableIndices[MD] = getMethodVtableIndex(OverriddenMD);
+        }
+        
+        // We don't need to add an entry for this method.
+        ShouldAddEntryForMethod = false;
+        break;
       }
     }
     

Modified: cfe/trunk/test/CodeGenCXX/vtable-layout.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout.cpp?rev=95965&r1=95964&r2=95965&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-layout.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-layout.cpp Thu Feb 11 23:25:12 2010
@@ -9,8 +9,8 @@
 struct A {
   virtual void f();
 };
-
 void A::f() { }
+
 }
 
 namespace Test2 {
@@ -36,10 +36,10 @@
   virtual void h();
   virtual A& operator=(const A&);
 };
-
 void A::f() { }
 
 // Another simple vtable dumper test.
+
 // CHECK:     Vtable for 'Test2::B' (6 entries).
 // CHECK-NEXT:  0 | offset_to_top (0)
 // CHECK-NEXT:  1 | Test2::B RTTI
@@ -48,13 +48,68 @@
 // CHECK-NEXT:  3 | void Test2::B::g() [pure]
 // CHECK-NEXT:  4 | Test2::B::~B() [complete] [pure]
 // CHECK-NEXT:  5 | Test2::B::~B() [deleting] [pure]
-
 struct B {
   virtual void f();
   virtual void g() = 0;
   virtual ~B() = 0;
 };
+void B::f() { }
+
+}
+
+namespace Test3 {
 
+// If a function in a derived class overrides a function in a primary base,
+// then the function should not have an entry in the derived class (unless the return
+// value requires adjusting).
+
+// CHECK:      Vtable for 'Test3::A' (3 entries).
+// CHECK-NEXT:   0 | offset_to_top (0)
+// CHECK-NEXT:   1 | Test3::A RTTI
+// CHECK-NEXT:       -- (Test3::A, 0) vtable address --
+// CHECK-NEXT:   2 | void Test3::A::f()
+struct A {
+  virtual void f();
+};
+void A::f() { } 
+
+// CHECK:     Vtable for 'Test3::B' (4 entries).
+// CHECK-NEXT:  0 | offset_to_top (0)
+// CHECK-NEXT:  1 | Test3::B RTTI
+// CHECK-NEXT:      -- (Test3::B, 0) vtable address --
+// CHECK-NEXT:  2 | void Test3::A::f()
+// CHECK-NEXT:  3 | void Test3::B::g()
+struct B : A {
+  virtual void f();
+  virtual void g();
+};
 void B::f() { }
 
+// CHECK:     Vtable for 'Test3::C' (5 entries).
+// CHECK-NEXT:  0 | offset_to_top (0)
+// CHECK-NEXT:  1 | Test3::C RTTI
+// CHECK-NEXT:     -- (Test3::C, 0) vtable address --
+// CHECK-NEXT:  2 | void Test3::A::f()
+// CHECK-NEXT:  3 | void Test3::C::g()
+// CHECK-NEXT:  4 | void Test3::C::h()
+struct C : A {
+  virtual void g();
+  virtual void h();
+};
+void C::g() { }
+
+// CHECK:     Vtable for 'Test3::D' (5 entries).
+// CHECK-NEXT:  0 | offset_to_top (0)
+// CHECK-NEXT:  1 | Test3::D RTTI
+// CHECK-NEXT:     -- (Test3::D, 0) vtable address --
+// CHECK-NEXT:  2 | void Test3::A::f()
+// CHECK-NEXT:  3 | void Test3::B::g()
+// CHECK-NEXT:  4 | void Test3::D::h()
+struct D : B {
+  virtual void f();
+  virtual void g();
+  virtual void h();
+};
+
+void D::f() { } 
 }





More information about the cfe-commits mailing list