[cfe-commits] r79587 - in /cfe/trunk: lib/AST/DeclCXX.cpp lib/CodeGen/CGCXX.cpp test/CodeGenCXX/virt.cpp

Mike Stump mrs at apple.com
Thu Aug 20 18:45:00 PDT 2009


Author: mrs
Date: Thu Aug 20 20:45:00 2009
New Revision: 79587

URL: http://llvm.org/viewvc/llvm-project?rev=79587&view=rev
Log:
We now support overriding base functions in vtables.  WIP.

Modified:
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/test/CodeGenCXX/virt.cpp

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=79587&r1=79586&r2=79587&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Aug 20 20:45:00 2009
@@ -332,6 +332,8 @@
                        std::vector<const CXXMethodDecl *> *> 
                        OverriddenMethodsMapTy;
 
+// FIXME: We hate static data.  This doesn't survive PCH saving/loading, and
+// the vtable building code uses it at CG time.
 static OverriddenMethodsMapTy *OverriddenMethods = 0;
 
 void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) {

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Thu Aug 20 20:45:00 2009
@@ -851,14 +851,19 @@
 class VtableBuilder {
   std::vector<llvm::Constant *> &methods;
   llvm::Type *Ptr8Ty;
+  /// Class - The most derived class that this vtable is being built for.
   const CXXRecordDecl *Class;
+  /// BLayout - Layout for the most derived class that this vtable is being
+  /// built for.
   const ASTRecordLayout &BLayout;
   llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary;
   llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
   llvm::Constant *rtti;
   llvm::LLVMContext &VMContext;
   CodeGenModule &CGM;  // Per-module state.
-
+  /// Index - Maps a method decl into a vtable index.  Useful for virtual
+  /// dispatch codegen.
+  llvm::DenseMap<const CXXMethodDecl *, int32_t> Index;
   typedef CXXRecordDecl::method_iterator method_iter;
 public:
   VtableBuilder(std::vector<llvm::Constant *> &meth,
@@ -914,24 +919,69 @@
     }
   }
 
-  void GenerateMethods(const CXXRecordDecl *RD) {
+  void StartNewTable() {
+    SeenVBase.clear();
+  }
+
+  inline uint32_t nottoobig(uint64_t t) {
+    assert(t < (uint32_t)-1ULL || "vtable too big");
+    return t;
+  }
+#if 0
+  inline uint32_t nottoobig(uint32_t t) {
+    return t;
+  }
+#endif
+
+  void AddMethod(const CXXMethodDecl *MD, int32_t FirstIndex) {
+    typedef CXXMethodDecl::method_iterator meth_iter;
+
     llvm::Constant *m;
+    m = CGM.GetAddrOfFunction(GlobalDecl(MD), Ptr8Ty);
+    m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
 
-    for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
-         ++mi) {
-      if (mi->isVirtual()) {
-        m = CGM.GetAddrOfFunction(GlobalDecl(*mi));
-        m = llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
-        methods.push_back(m);
+    // FIXME: Don't like the nested loops.  For very large inheritance
+    // heirarchies we could have a table on the side with the final overridder
+    // and just replace each instance of an overridden method once.  Would be
+    // nice to measure the cost/benefit on real code.
+
+    // If we can find a previously allocated slot for this, reuse it.
+    for (meth_iter mi = MD->begin_overridden_methods(),
+           e = MD->end_overridden_methods();
+         mi != e; ++mi) {
+      const CXXMethodDecl *OMD = *mi;
+      llvm::Constant *om;
+      om = CGM.GetAddrOfFunction(GlobalDecl(OMD), Ptr8Ty);
+      om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
+
+      for (int32_t i = FirstIndex, e = nottoobig(methods.size()); i != e; ++i) {
+        // FIXME: begin_overridden_methods might be too lax, covariance */
+        if (methods[i] == om) {
+          methods[i] = m;
+          Index[MD] = i;
+          return;
+        }
       }
     }
+
+    // else allocate a new slot.
+    Index[MD] = methods.size();
+    methods.push_back(m);
+  }
+
+  void GenerateMethods(const CXXRecordDecl *RD, int32_t FirstIndex) {
+    for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
+         ++mi)
+      if (mi->isVirtual())
+        AddMethod(*mi, FirstIndex);
   }
 
   void GenerateVtableForBase(const CXXRecordDecl *RD,
                              bool forPrimary,
                              bool VBoundary,
                              int64_t Offset,
-                             bool ForVirtualBase) {
+                             bool ForVirtualBase,
+                             int32_t FirstIndex) {
     llvm::Constant *m = llvm::Constant::getNullValue(Ptr8Ty);
 
     if (RD && !RD->isDynamicClass())
@@ -964,7 +1014,7 @@
         IndirectPrimary.insert(PrimaryBase);
       Top = false;
       GenerateVtableForBase(PrimaryBase, true, PrimaryBaseWasVirtual|VBoundary,
-                            Offset, PrimaryBaseWasVirtual);
+                            Offset, PrimaryBaseWasVirtual, FirstIndex);
     }
 
     if (Top) {
@@ -980,7 +1030,7 @@
     }
 
     // And add the virtuals for the class to the primary vtable.
-    GenerateMethods(RD);
+    GenerateMethods(RD, FirstIndex);
 
     // and then the non-virtual bases.
     for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
@@ -991,8 +1041,9 @@
         cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
       if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
         uint64_t o = Offset + Layout.getBaseClassOffset(Base);
-        SeenVBase.clear();
-        GenerateVtableForBase(Base, true, false, o, false);
+        StartNewTable();
+        FirstIndex = methods.size();
+        GenerateVtableForBase(Base, true, false, o, false, FirstIndex);
       }
     }
   }
@@ -1006,9 +1057,10 @@
       if (i->isVirtual() && !IndirectPrimary.count(Base)) {
         // Mark it so we don't output it twice.
         IndirectPrimary.insert(Base);
-        SeenVBase.clear();
+        StartNewTable();
         int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
-        GenerateVtableForBase(Base, false, true, BaseOffset, true);
+        int32_t FirstIndex = methods.size();
+        GenerateVtableForBase(Base, false, true, BaseOffset, true, FirstIndex);
       }
       if (Base->getNumVBases())
         GenerateVtableForVBases(Base, Class);
@@ -1034,7 +1086,7 @@
   VtableBuilder b(methods, RD, CGM);
 
   // First comes the vtables for all the non-virtual bases...
-  b.GenerateVtableForBase(RD, true, false, 0, false);
+  b.GenerateVtableForBase(RD, true, false, 0, false, 0);
 
   // then the vtables for all the virtual bases.
   b.GenerateVtableForVBases(RD, RD);

Modified: cfe/trunk/test/CodeGenCXX/virt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virt.cpp?rev=79587&r1=79586&r2=79587&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/virt.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/virt.cpp Thu Aug 20 20:45:00 2009
@@ -620,6 +620,36 @@
 // CHECK-LP32-NEXT: .long 4294967276
 // CHECK-LP32-NEXT: .long __ZTI8test10_D
 
+struct test11_B {
+  virtual void B1() { }
+  virtual void D() { }
+  virtual void B2() { }
+};
+
+struct test11_D : test11_B {
+  virtual void D1() { }
+  virtual void D() { }
+  virtual void D2() { }
+};
+
+// CHECK-LP32:__ZTV8test11_D:
+// CHECK-LP32-NEXT: .space 4
+// CHECK-LP32-NEXT: .long __ZTI8test11_D
+// CHECK-LP32-NEXT: .long __ZN8test11_B2B1Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D1DEv
+// CHECK-LP32-NEXT: .long __ZN8test11_B2B2Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D2D1Ev
+// CHECK-LP32-NEXT: .long __ZN8test11_D2D2Ev
+
+
+// CHECK-LP64:__ZTV8test11_D:
+// CHECK-LP64-NEXT: .space 8
+// CHECK-LP64-NEXT: .quad __ZTI8test11_D
+// CHECK-LP64-NEXT: .quad __ZN8test11_B2B1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D1DEv
+// CHECK-LP64-NEXT: .quad __ZN8test11_B2B2Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D2D1Ev
+// CHECK-LP64-NEXT: .quad __ZN8test11_D2D2Ev
 
 
 
@@ -702,6 +732,7 @@
 // CHECK-LP64-NEXT: .quad __ZN2D14bar5Ev
 
 
+test11_D d11;
 test10_D d10;
 test9_D d9;
 test8_D d8;





More information about the cfe-commits mailing list