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

Anders Carlsson andersca at mac.com
Tue Mar 9 18:33:41 PST 2010


Author: andersca
Date: Tue Mar  9 20:33:41 2010
New Revision: 98127

URL: http://llvm.org/viewvc/llvm-project?rev=98127&view=rev
Log:
Improve vcall offset handling in construction vtables. With this we layout the construction vtables from the ABI examples correctly.

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

Modified: cfe/trunk/lib/CodeGen/CGVtable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVtable.cpp?rev=98127&r1=98126&r2=98127&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGVtable.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGVtable.cpp Tue Mar  9 20:33:41 2010
@@ -60,10 +60,13 @@
     /// Method - The method decl of the overrider.
     const CXXMethodDecl *Method;
 
-    /// Offset - the base offset of the overrider relative to the layout class.
-    int64_t Offset;
+    /// Offset - the base offset of the overrider in the layout class.
+    uint64_t Offset;
     
-    OverriderInfo() : Method(0), Offset(0) { }
+    /// OldOffset - FIXME: Remove this.
+    int64_t OldOffset;
+    
+    OverriderInfo() : Method(0), Offset(0), OldOffset(0) { }
   };
 
 private:
@@ -71,6 +74,16 @@
   /// are stored.
   const CXXRecordDecl *MostDerivedClass;
   
+  /// MostDerivedClassOffset - If we're building final overriders for a 
+  /// construction vtable, this holds the offset from the layout class to the
+  /// most derived class.
+  const uint64_t MostDerivedClassOffset;
+
+  /// LayoutClass - The class we're using for layout information. Will be 
+  /// different than the most derived class if the final overriders are for a
+  /// construction vtable.  
+  const CXXRecordDecl *LayoutClass;  
+
   ASTContext &Context;
   
   /// MostDerivedClassLayout - the AST record layout of the most derived class.
@@ -122,11 +135,13 @@
   /// subobject (and all its direct and indirect bases).
   void ComputeFinalOverriders(BaseSubobject Base,
                               bool BaseSubobjectIsVisitedVBase,
+                              uint64_t OffsetInLayoutClass,
                               SubobjectOffsetsMapTy &Offsets);
   
   /// AddOverriders - Add the final overriders for this base subobject to the
   /// map of final overriders.  
-  void AddOverriders(BaseSubobject Base, SubobjectOffsetsMapTy &Offsets);
+  void AddOverriders(BaseSubobject Base,uint64_t OffsetInLayoutClass,
+                     SubobjectOffsetsMapTy &Offsets);
 
   /// PropagateOverrider - Propagate the NewMD overrider to all the functions 
   /// that OldMD overrides. For example, if we have:
@@ -139,6 +154,7 @@
   /// C::f.
   void PropagateOverrider(const CXXMethodDecl *OldMD,
                           BaseSubobject NewBase,
+                          uint64_t OverriderOffsetInLayoutClass,
                           const CXXMethodDecl *NewMD,
                           SubobjectOffsetsMapTy &Offsets);
   
@@ -146,7 +162,9 @@
                                     SubobjectOffsetsMapTy &Offsets);
 
 public:
-  explicit FinalOverriders(const CXXRecordDecl *MostDerivedClass);
+  FinalOverriders(const CXXRecordDecl *MostDerivedClass,
+                  uint64_t MostDerivedClassOffset,
+                  const CXXRecordDecl *LayoutClass);
 
   /// getOverrider - Get the final overrider for the given method declaration in
   /// the given base subobject.
@@ -181,15 +199,19 @@
 
 #define DUMP_OVERRIDERS 0
 
-FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass)
+FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass,
+                                 uint64_t MostDerivedClassOffset,
+                                 const CXXRecordDecl *LayoutClass)
   : MostDerivedClass(MostDerivedClass), 
+  MostDerivedClassOffset(MostDerivedClassOffset), LayoutClass(LayoutClass),
   Context(MostDerivedClass->getASTContext()),
   MostDerivedClassLayout(Context.getASTRecordLayout(MostDerivedClass)) {
     
   // Compute the final overriders.
   SubobjectOffsetsMapTy Offsets;
   ComputeFinalOverriders(BaseSubobject(MostDerivedClass, 0), 
-                         /*BaseSubobjectIsVisitedVBase=*/false, Offsets);
+                         /*BaseSubobjectIsVisitedVBase=*/false, 
+                         MostDerivedClassOffset, Offsets);
   VisitedVirtualBases.clear();
 
 #if DUMP_OVERRIDERS
@@ -199,18 +221,19 @@
   // Also dump the base offsets (for now).
   for (SubobjectOffsetsMapTy::const_iterator I = Offsets.begin(),
        E = Offsets.end(); I != E; ++I) {
-    const OffsetVectorTy& OffsetVector = I->second;
+    const OffsetSetVectorTy& OffsetSetVector = I->second;
 
     llvm::errs() << "Base offsets for ";
     llvm::errs() << I->first->getQualifiedNameAsString() << '\n';
 
-    for (unsigned I = 0, E = OffsetVector.size(); I != E; ++I)
-      llvm::errs() << "  " << I << " - " << OffsetVector[I] << '\n';
+    for (unsigned I = 0, E = OffsetSetVector.size(); I != E; ++I)
+      llvm::errs() << "  " << I << " - " << OffsetSetVector[I] / 8 << '\n';
   }
 #endif
 }
 
 void FinalOverriders::AddOverriders(BaseSubobject Base,
+                                    uint64_t OffsetInLayoutClass,
                                     SubobjectOffsetsMapTy &Offsets) {
   const CXXRecordDecl *RD = Base.getBase();
 
@@ -222,13 +245,14 @@
       continue;
 
     // First, propagate the overrider.
-    PropagateOverrider(MD, Base, MD, Offsets);
+    PropagateOverrider(MD, Base, OffsetInLayoutClass, MD, Offsets);
 
     // Add the overrider as the final overrider of itself.
     OverriderInfo& Overrider = OverridersMap[std::make_pair(Base, MD)];
     assert(!Overrider.Method && "Overrider should not exist yet!");
 
-    Overrider.Offset = Base.getBaseOffset();
+    Overrider.OldOffset = Base.getBaseOffset();
+    Overrider.Offset = OffsetInLayoutClass;
     Overrider.Method = MD;
   }
 }
@@ -346,6 +370,7 @@
 
 void FinalOverriders::PropagateOverrider(const CXXMethodDecl *OldMD,
                                          BaseSubobject NewBase,
+                                         uint64_t OverriderOffsetInLayoutClass,
                                          const CXXMethodDecl *NewMD,
                                          SubobjectOffsetsMapTy &Offsets) {
   for (CXXMethodDecl::method_iterator I = OldMD->begin_overridden_methods(),
@@ -389,11 +414,13 @@
       }
 
       // Set the new overrider.
-      Overrider.Offset = NewBase.getBaseOffset();
+      Overrider.Offset = OverriderOffsetInLayoutClass;
+      Overrider.OldOffset = NewBase.getBaseOffset();
       Overrider.Method = NewMD;
       
       // And propagate it further.
-      PropagateOverrider(OverriddenMD, NewBase, NewMD, Offsets);
+      PropagateOverrider(OverriddenMD, NewBase, OverriderOffsetInLayoutClass,
+                         NewMD, Offsets);
     }
   }
 }
@@ -416,6 +443,7 @@
 
 void FinalOverriders::ComputeFinalOverriders(BaseSubobject Base,
                                              bool BaseSubobjectIsVisitedVBase,
+                                             uint64_t OffsetInLayoutClass,
                                              SubobjectOffsetsMapTy &Offsets) {
   const CXXRecordDecl *RD = Base.getBase();
   const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
@@ -433,12 +461,20 @@
     
     bool IsVisitedVirtualBase = BaseSubobjectIsVisitedVBase;
     uint64_t BaseOffset;
+    uint64_t BaseOffsetInLayoutClass;
     if (I->isVirtual()) {
       if (!VisitedVirtualBases.insert(BaseDecl))
         IsVisitedVirtualBase = true;
       BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl);
+      
+      const ASTRecordLayout &LayoutClassLayout =
+        Context.getASTRecordLayout(LayoutClass);
+      BaseOffsetInLayoutClass = 
+        LayoutClassLayout.getVBaseClassOffset(BaseDecl);
     } else {
       BaseOffset = Layout.getBaseClassOffset(BaseDecl) + Base.getBaseOffset();
+      BaseOffsetInLayoutClass = Layout.getBaseClassOffset(BaseDecl) +
+        OffsetInLayoutClass;
     }
     
     // Compute the final overriders for this base.
@@ -463,13 +499,14 @@
     // Here, we still want to compute the overriders for A as a base of C, 
     // because otherwise we'll miss that C::g overrides A::f.
     ComputeFinalOverriders(BaseSubobject(BaseDecl, BaseOffset), 
-                           IsVisitedVirtualBase, NewOffsets);                           
+                           IsVisitedVirtualBase, BaseOffsetInLayoutClass, 
+                           NewOffsets);
   }
 
   /// Now add the overriders for this particular subobject.
   /// (We don't want to do this more than once for a virtual base).
   if (!BaseSubobjectIsVisitedVBase)
-    AddOverriders(Base, NewOffsets);
+    AddOverriders(Base, OffsetInLayoutClass, NewOffsets);
   
   // And merge the newly discovered subobject offsets.
   MergeSubobjectOffsets(NewOffsets, Offsets);
@@ -508,7 +545,7 @@
   }
 
   Out << "Final overriders for (" << RD->getQualifiedNameAsString() << ", ";
-  Out << Base.getBaseOffset() << ")\n";
+  Out << Base.getBaseOffset() / 8 << ")\n";
 
   // Now dump the overriders for this base subobject.
   for (CXXRecordDecl::method_iterator I = RD->method_begin(), 
@@ -522,7 +559,7 @@
 
     Out << "  " << MD->getQualifiedNameAsString() << " - (";
     Out << Overrider.Method->getQualifiedNameAsString();
-    Out << ", " << Overrider.Offset << ')';
+    Out << ", " << Overrider.OldOffset / 8 << ", " << Overrider.Offset / 8 << ')';
 
     AdjustmentOffsetsMapTy::const_iterator AI =
       ReturnAdjustments.find(std::make_pair(Base, MD));
@@ -1222,7 +1259,7 @@
     MostDerivedClassOffset(MostDerivedClassOffset), 
     MostDerivedClassIsVirtual(MostDerivedClassIsVirtual), 
     LayoutClass(LayoutClass), Context(MostDerivedClass->getASTContext()), 
-    Overriders(MostDerivedClass) {
+    Overriders(MostDerivedClass, MostDerivedClassOffset, LayoutClass) {
 
     LayoutVtable();
   }
@@ -1269,7 +1306,7 @@
       Overriders.getOverrider(OverriddenBaseSubobject, MD);
     
     // Check if we need an adjustment.
-    if (Overrider.Offset == (int64_t)MethodInfo.BaseOffset)
+    if (Overrider.OldOffset == (int64_t)MethodInfo.BaseOffset)
       continue;
     
     uint64_t VtableIndex = MethodInfo.VtableIndex;
@@ -1284,7 +1321,7 @@
       continue;
 
     BaseSubobject OverriderBaseSubobject(Overrider.Method->getParent(),
-                                         Overrider.Offset);
+                                         Overrider.OldOffset);
 
     // Compute the adjustment offset.
     BaseOffset ThisAdjustmentOffset =

Modified: cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp?rev=98127&r1=98126&r2=98127&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/vtable-layout-abi-examples.cpp Tue Mar  9 20:33:41 2010
@@ -187,3 +187,126 @@
 void D::d() { } 
 
 }
+
+namespace Test3 {
+
+// From http://www.codesourcery.com/public/cxx-abi/abi-examples.html#vtable-ctor
+
+struct V1 {
+  int v1;
+  virtual void f();
+};
+
+struct V2 : virtual V1 {
+  int v2;
+  virtual void f();
+};
+
+// CHECK:      Vtable for 'Test3::C' (14 entries).
+// CHECK-NEXT:    0 | vbase_offset (32)
+// CHECK-NEXT:    1 | vbase_offset (16)
+// CHECK-NEXT:    2 | offset_to_top (0)
+// CHECK-NEXT:    3 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::C, 0) vtable address --
+// CHECK-NEXT:    4 | void Test3::C::f()
+// CHECK-NEXT:    5 | vcall_offset (-16)
+// CHECK-NEXT:    6 | offset_to_top (-16)
+// CHECK-NEXT:    7 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::V1, 16) vtable address --
+// CHECK-NEXT:    8 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT:    9 | vcall_offset (-32)
+// CHECK-NEXT:   10 | vbase_offset (-16)
+// CHECK-NEXT:   11 | offset_to_top (-32)
+// CHECK-NEXT:   12 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::V2, 32) vtable address --
+// CHECK-NEXT:   13 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -32 vcall offset offset]
+
+// CHECK:      Construction vtable for ('Test3::V2', 32) in 'Test3::C' (9 entries).
+// CHECK-NEXT:    0 | vcall_offset (0)
+// CHECK-NEXT:    1 | vbase_offset (-16)
+// CHECK-NEXT:    2 | offset_to_top (0)
+// CHECK-NEXT:    3 | Test3::V2 RTTI
+// CHECK-NEXT:        -- (Test3::V2, 32) vtable address --
+// CHECK-NEXT:    4 | void Test3::V2::f()
+// CHECK-NEXT:    5 | vcall_offset (16)
+// CHECK-NEXT:    6 | offset_to_top (16)
+// CHECK-NEXT:    7 | Test3::V2 RTTI
+// CHECK-NEXT:        -- (Test3::V1, 16) vtable address --
+// CHECK-NEXT:    8 | void Test3::V2::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -24 vcall offset offset]
+struct C : virtual V1, virtual V2 {
+  int c;
+  virtual void f();
+};
+void C::f() { }
+
+struct B {
+  int b;
+};
+
+// CHECK:      Vtable for 'Test3::D' (15 entries).
+// CHECK-NEXT:    0 | vbase_offset (40)
+// CHECK-NEXT:    1 | vbase_offset (24)
+// CHECK-NEXT:    2 | offset_to_top (0)
+// CHECK-NEXT:    3 | Test3::D RTTI
+// CHECK-NEXT:        -- (Test3::C, 0) vtable address --
+// CHECK-NEXT:        -- (Test3::D, 0) vtable address --
+// CHECK-NEXT:    4 | void Test3::C::f()
+// CHECK-NEXT:    5 | void Test3::D::g()
+// CHECK-NEXT:    6 | vcall_offset (-24)
+// CHECK-NEXT:    7 | offset_to_top (-24)
+// CHECK-NEXT:    8 | Test3::D RTTI
+// CHECK-NEXT:        -- (Test3::V1, 24) vtable address --
+// CHECK-NEXT:    9 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT:   10 | vcall_offset (-40)
+// CHECK-NEXT:   11 | vbase_offset (-16)
+// CHECK-NEXT:   12 | offset_to_top (-40)
+// CHECK-NEXT:   13 | Test3::D RTTI
+// CHECK-NEXT:        -- (Test3::V2, 40) vtable address --
+// CHECK-NEXT:   14 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -32 vcall offset offset]
+
+// CHECK:      Construction vtable for ('Test3::C', 0) in 'Test3::D' (14 entries).
+// CHECK-NEXT:    0 | vbase_offset (40)
+// CHECK-NEXT:    1 | vbase_offset (24)
+// CHECK-NEXT:    2 | offset_to_top (0)
+// CHECK-NEXT:    3 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::C, 0) vtable address --
+// CHECK-NEXT:    4 | void Test3::C::f()
+// CHECK-NEXT:    5 | vcall_offset (-24)
+// CHECK-NEXT:    6 | offset_to_top (-24)
+// CHECK-NEXT:    7 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::V1, 24) vtable address --
+// CHECK-NEXT:    8 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -24 vcall offset offset]
+// CHECK-NEXT:    9 | vcall_offset (-40)
+// CHECK-NEXT:   10 | vbase_offset (-16)
+// CHECK-NEXT:   11 | offset_to_top (-40)
+// CHECK-NEXT:   12 | Test3::C RTTI
+// CHECK-NEXT:        -- (Test3::V2, 40) vtable address --
+// CHECK-NEXT:   13 | void Test3::C::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -32 vcall offset offset]
+
+// CHECK:      Construction vtable for ('Test3::V2', 40) in 'Test3::D' (9 entries).
+// CHECK-NEXT:    0 | vcall_offset (0)
+// CHECK-NEXT:    1 | vbase_offset (-16)
+// CHECK-NEXT:    2 | offset_to_top (0)
+// CHECK-NEXT:    3 | Test3::V2 RTTI
+// CHECK-NEXT:        -- (Test3::V2, 40) vtable address --
+// CHECK-NEXT:    4 | void Test3::V2::f()
+// CHECK-NEXT:    5 | vcall_offset (16)
+// CHECK-NEXT:    6 | offset_to_top (16)
+// CHECK-NEXT:    7 | Test3::V2 RTTI
+// CHECK-NEXT:        -- (Test3::V1, 24) vtable address --
+// CHECK-NEXT:    8 | void Test3::V2::f()
+// CHECK-NEXT:        [this adjustment: 0 non-virtual, -24 vcall offset offset]
+struct D : B, C {
+  int d;
+  virtual void g();
+};
+void D::g() { }
+
+}





More information about the cfe-commits mailing list