[cfe-commits] r96605 - in /cfe/trunk: lib/CodeGen/CGClass.cpp lib/CodeGen/CodeGenFunction.cpp test/CodeGenCXX/virtual-base-destructor-call.cpp test/CodeGenCXX/virtual-destructor-calls.cpp

John McCall rjmccall at apple.com
Thu Feb 18 11:59:28 PST 2010


Author: rjmccall
Date: Thu Feb 18 13:59:28 2010
New Revision: 96605

URL: http://llvm.org/viewvc/llvm-project?rev=96605&view=rev
Log:
Make deleting and complete dtor variants defer to other dtor variants by
calling them as subroutines.  This triggers whenever the alias optimization
doesn't, i.e. when the dtor has linkonce linkage or there are virtual bases
or it's the deleting dtor.


Modified:
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp
    cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Thu Feb 18 13:59:28 2010
@@ -477,12 +477,21 @@
   
   const CXXRecordDecl *RD = cast<CXXMethodDecl>(CGF.CurFuncDecl)->getParent();
   const CXXRecordDecl *Base = cast<CXXMethodDecl>(GD.getDecl())->getParent();
-  
+
   llvm::Value *VTT;
 
-  uint64_t SubVTTIndex = 
-    CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
-  assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
+  uint64_t SubVTTIndex;
+
+  // If the record matches the base, this is the complete ctor/dtor
+  // variant calling the base variant in a class with virtual bases.
+  if (RD == Base) {
+    assert(!CGVtableInfo::needsVTTParameter(CGF.CurGD) &&
+           "doing no-op VTT offset in base dtor/ctor?");
+    SubVTTIndex = 0;
+  } else {
+    SubVTTIndex = CGF.CGM.getVtableInfo().getSubVTTIndex(RD, Base);
+    assert(SubVTTIndex != 0 && "Sub-VTT index must be greater than zero!");
+  }
   
   if (CGVtableInfo::needsVTTParameter(CGF.CurGD)) {
     // A VTT parameter was passed to the constructor, use it.
@@ -962,7 +971,6 @@
 /// EmitDtorEpilogue - Emit all code that comes at the end of class's
 /// destructor. This is to call destructors on members and base classes
 /// in reverse order of their construction.
-/// FIXME: This needs to take a CXXDtorType.
 void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
                                        CXXDtorType DtorType) {
   assert(!DD->isTrivial() &&
@@ -970,6 +978,44 @@
 
   const CXXRecordDecl *ClassDecl = DD->getParent();
 
+  // In a deleting destructor, we've already called the complete
+  // destructor as a subroutine, so we just have to delete the
+  // appropriate value.
+  if (DtorType == Dtor_Deleting) {
+    assert(DD->getOperatorDelete() && 
+           "operator delete missing - EmitDtorEpilogue");
+    EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
+                   getContext().getTagDeclType(ClassDecl));
+    return;
+  }
+
+  // For complete destructors, we've already called the base
+  // destructor (in GenerateBody), so we just need to destruct all the
+  // virtual bases.
+  if (DtorType == Dtor_Complete) {
+    // Handle virtual bases.
+    for (CXXRecordDecl::reverse_base_class_const_iterator I = 
+           ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend();
+              I != E; ++I) {
+      const CXXBaseSpecifier &Base = *I;
+      CXXRecordDecl *BaseClassDecl
+        = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
+    
+      // Ignore trivial destructors.
+      if (BaseClassDecl->hasTrivialDestructor())
+        continue;
+      const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
+      llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
+                                                       true,
+                                                       ClassDecl,
+                                                       BaseClassDecl);
+      EmitCXXDestructorCall(D, Dtor_Base, V);
+    }
+    return;
+  }
+
+  assert(DtorType == Dtor_Base);
+
   // Collect the fields.
   llvm::SmallVector<const FieldDecl *, 16> FieldDecls;
   for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
@@ -1042,37 +1088,6 @@
                                            /*NullCheckValue=*/false);
     EmitCXXDestructorCall(D, Dtor_Base, V);
   }
-
-  // If we're emitting a base destructor, we don't want to emit calls to the
-  // virtual bases.
-  if (DtorType == Dtor_Base)
-    return;
-  
-  // Handle virtual bases.
-  for (CXXRecordDecl::reverse_base_class_const_iterator I = 
-       ClassDecl->vbases_rbegin(), E = ClassDecl->vbases_rend(); I != E; ++I) {
-    const CXXBaseSpecifier &Base = *I;
-    CXXRecordDecl *BaseClassDecl
-      = cast<CXXRecordDecl>(Base.getType()->getAs<RecordType>()->getDecl());
-    
-    // Ignore trivial destructors.
-    if (BaseClassDecl->hasTrivialDestructor())
-      continue;
-    const CXXDestructorDecl *D = BaseClassDecl->getDestructor(getContext());
-    llvm::Value *V = GetAddressOfBaseOfCompleteClass(LoadCXXThis(),
-                                                     true,
-                                                     ClassDecl,
-                                                     BaseClassDecl);
-    EmitCXXDestructorCall(D, Dtor_Base, V);
-  }
-    
-  // If we have a deleting destructor, emit a call to the delete operator.
-  if (DtorType == Dtor_Deleting) {
-    assert(DD->getOperatorDelete() && 
-           "operator delete missing - EmitDtorEpilogue");
-    EmitDeleteCall(DD->getOperatorDelete(), LoadCXXThis(),
-                   getContext().getTagDeclType(ClassDecl));
-  }
 }
 
 /// EmitCXXAggrConstructorCall - This routine essentially creates a (nested)

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

==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Feb 18 13:59:28 2010
@@ -248,39 +248,69 @@
   Stmt *Body = FD->getBody();
   assert((Body || FD->isImplicit()) && "non-implicit function def has no body");
 
+  bool SkipBody = false; // should get jump-threaded
+
   // Emit special ctor/dtor prologues.
-  llvm::BasicBlock *DtorEpilogue = 0;
   if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) {
+    // Emit the constructor prologue, i.e. the base and member initializers.
     EmitCtorPrologue(CD, GD.getCtorType());
+
+    // TODO: for complete, non-varargs variants, we can get away with
+    // just emitting the vbase initializers, then calling the base
+    // constructor.
+
   } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
-    DtorEpilogue = createBasicBlock("dtor.epilogue");
+    // In all cases, if there's an exception in the body (or delegate)
+    // we'll still need to run the epilogue.
+    llvm::BasicBlock *DtorEpilogue = createBasicBlock("dtor.epilogue");
     PushCleanupBlock(DtorEpilogue);
 
-    InitializeVtablePtrs(DD->getParent());
+    // If this is the deleting variant, invoke the complete variant;
+    // the epilogue will call the appropriate operator delete().
+    if (GD.getDtorType() == Dtor_Deleting) {
+      EmitCXXDestructorCall(DD, Dtor_Complete, LoadCXXThis());
+      SkipBody = true;
+
+    // If this is the complete variant, just invoke the base variant;
+    // the epilogue will destruct the virtual bases.
+    } else if (GD.getDtorType() == Dtor_Complete) {
+      EmitCXXDestructorCall(DD, Dtor_Base, LoadCXXThis());
+      SkipBody = true;
+
+    // Otherwise, we're in the base variant, so we need to ensure the
+    // vtable ptrs are right before emitting the body.
+    } else {
+      InitializeVtablePtrs(DD->getParent());
+    }
   }
 
   // Emit the body of the function.
-  if (!Body)
+  if (SkipBody) {
+    // skipped
+  } else if (!Body) {
     SynthesizeImplicitFunctionBody(GD, Fn, Args);
-  else {
+  } else {
     if (isa<CXXTryStmt>(Body))
       OuterTryBlock = cast<CXXTryStmt>(Body);
-
     EmitStmt(Body);
   }
 
-  // Emit special ctor/ctor epilogues.
+  // Emit special ctor/dtor epilogues.
   if (isa<CXXConstructorDecl>(FD)) {
-    // If any of the member initializers are temporaries bound to references
-    // make sure to emit their destructors.
+    // Be sure to emit any cleanup blocks associated with the member
+    // or base initializers, which includes (along the exceptional
+    // path) the destructors for those members and bases that were
+    // fully constructed.
     EmitCleanupBlocks(0);
+
   } else if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(FD)) {
+    // Funnel the previously-pushed cleanup block into the epilogue.
     CleanupBlockInfo Info = PopCleanupBlock();
-    assert(Info.CleanupBlock == DtorEpilogue && "Block mismatch!");
+    EmitBlock(Info.CleanupBlock);
 
-    EmitBlock(DtorEpilogue);
     EmitDtorEpilogue(DD, GD.getDtorType());
-      
+
+    // Go ahead and link in the switch and end blocks.
     if (Info.SwitchBlock)
       EmitBlock(Info.SwitchBlock);
     if (Info.EndBlock)

Modified: cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp?rev=96605&r1=96604&r2=96605&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/virtual-base-destructor-call.cpp Thu Feb 18 13:59:28 2010
@@ -16,4 +16,36 @@
 int main() {
 }
 
-// CHECK: call void @_ZN9basic_iosD2Ev
+// basic_iostream's complete dtor calls its base dtor, then its
+// virtual base's dtor.
+//  CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED1Ev
+//  CHECK: call void @_ZN14basic_iostreamIcED2Ev
+//  CHECK: call void @_ZN9basic_iosD2Ev
+
+// basic_iostream's deleting dtor calls its complete dtor, then
+// operator delete().
+//  CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED0Ev
+//  CHECK: call void @_ZN14basic_iostreamIcED1Ev
+//  CHECK: call void @_ZdlPv
+
+// basic_istream's complete dtor calls the base dtor,
+// then its virtual base's base dtor.
+//  CHECK: define linkonce_odr void @_ZN13basic_istreamIcED1Ev
+//  CHECK: call void @_ZN13basic_istreamIcED2Ev
+//  CHECK: call void @_ZN9basic_iosD2Ev
+
+// basic_istream's deleting dtor calls the complete dtor, then
+// operator delete().
+//  CHECK: define linkonce_odr void @_ZN13basic_istreamIcED0Ev
+//  CHECK: call void @_ZN13basic_istreamIcED1Ev
+//  CHECK: call void @_ZdlPv
+
+// basic_iostream's base dtor calls its non-virtual base dtor.
+//  CHECK: define linkonce_odr void @_ZN14basic_iostreamIcED2Ev
+//  CHECK: call void @_ZN13basic_istreamIcED2Ev
+//  CHECK: }
+
+// basic_istream's base dtor is a no-op.
+//  CHECK: define linkonce_odr void @_ZN13basic_istreamIcED2Ev
+//  CHECK-NOT: call
+//  CHECK: }

Modified: cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp?rev=96605&r1=96604&r2=96605&view=diff

==============================================================================
--- cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/virtual-destructor-calls.cpp Thu Feb 18 13:59:28 2010
@@ -8,15 +8,15 @@
   virtual ~B();
 };
 
-// Complete dtor.
+// Complete dtor: just an alias because there are no virtual bases.
 // CHECK: @_ZN1BD1Ev = alias {{.*}} @_ZN1BD2Ev
 
-// Deleting dtor.
+// Deleting dtor: defers to the complete dtor.
 // CHECK: define void @_ZN1BD0Ev
-// CHECK: call void @_ZN1AD2Ev
-// check: call void @_ZdlPv
+// CHECK: call void @_ZN1BD1Ev
+// CHECK: call void @_ZdlPv
 
-// Base dtor.
+// Base dtor: actually calls A's base dtor.
 // CHECK: define void @_ZN1BD2Ev
 // CHECK: call void @_ZN1AD2Ev
 





More information about the cfe-commits mailing list