[cfe-commits] r131368 - in /cfe/trunk: include/clang/AST/Decl.h lib/AST/Decl.cpp lib/CodeGen/CGCXX.cpp lib/CodeGen/CGClass.cpp test/CodeGenCXX/mangle-subst-std.cpp test/CodeGenCXX/skip-vtable-pointer-initialization.cpp

Anders Carlsson andersca at mac.com
Sat May 14 16:26:09 PDT 2011


Author: andersca
Date: Sat May 14 18:26:09 2011
New Revision: 131368

URL: http://llvm.org/viewvc/llvm-project?rev=131368&view=rev
Log:
When emitting the destructor for a class with a vtable, if we can determine
that the destructor body is trivial and that all member variables also have either
trivial destructors or trivial destructor bodies, we don't need to initialize the
vtable pointers since no virtual member functions will be called on the destructor.

Fixes PR9181.


Added:
    cfe/trunk/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
Modified:
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/CodeGen/CGCXX.cpp
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=131368&r1=131367&r2=131368&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Sat May 14 18:26:09 2011
@@ -1515,6 +1515,10 @@
     return hasBody(Definition);
   }
 
+  /// hasTrivialBody - Returns whether the function has a trivial body that does
+  /// not require any specific codegen.
+  bool hasTrivialBody() const;
+
   /// isDefined - Returns true if the function is defined at all, including
   /// a deleted definition. Except for the behavior when the function is
   /// deleted, behaves like hasBody.

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=131368&r1=131367&r2=131368&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Sat May 14 18:26:09 2011
@@ -1422,6 +1422,20 @@
   return false;
 }
 
+bool FunctionDecl::hasTrivialBody() const
+{
+  Stmt *S = getBody();
+  if (!S) {
+    // Since we don't have a body for this function, we don't know if it's
+    // trivial or not.
+    return false;
+  }
+
+  if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
+    return true;
+  return false;
+}
+
 bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const {
   for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) {
     if (I->IsDeleted || I->Body || I->IsLateTemplateParsed) {

Modified: cfe/trunk/lib/CodeGen/CGCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCXX.cpp?rev=131368&r1=131367&r2=131368&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCXX.cpp Sat May 14 18:26:09 2011
@@ -28,17 +28,6 @@
 using namespace clang;
 using namespace CodeGen;
 
-/// Determines whether the given function has a trivial body that does
-/// not require any specific codegen.
-static bool HasTrivialBody(const FunctionDecl *FD) {
-  Stmt *S = FD->getBody();
-  if (!S)
-    return true;
-  if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty())
-    return true;
-  return false;
-}
-
 /// Try to emit a base destructor as an alias to its primary
 /// base-class destructor.
 bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
@@ -47,7 +36,7 @@
 
   // If the destructor doesn't have a trivial body, we have to emit it
   // separately.
-  if (!HasTrivialBody(D))
+  if (!D->hasTrivialBody())
     return true;
 
   const CXXRecordDecl *Class = D->getParent();

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=131368&r1=131367&r2=131368&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Sat May 14 18:26:09 2011
@@ -741,6 +741,38 @@
     EmitMemberInitializer(*this, ClassDecl, MemberInitializers[I], CD, Args);
 }
 
+/// CanSkipVTablePointerInitialization - Check whether we need to initialize
+/// any vtable pointers before calling this destructor.
+static bool CanSkipVTablePointerInitialization(ASTContext &Context,
+                                           const CXXDestructorDecl *Dtor) {
+  if (!Dtor->hasTrivialBody())
+    return false;
+
+  // Check the fields.
+  const CXXRecordDecl *ClassDecl = Dtor->getParent();
+  for (CXXRecordDecl::field_iterator I = ClassDecl->field_begin(),
+       E = ClassDecl->field_end(); I != E; ++I) {
+    const FieldDecl *Field = *I;
+    
+    QualType FieldBaseElementType = 
+      Context.getBaseElementType(Field->getType());
+
+    const RecordType *RT = FieldBaseElementType->getAs<RecordType>();
+    if (!RT)
+      continue;
+    
+    CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
+    if (FieldClassDecl->hasTrivialDestructor())
+      continue;
+    if (FieldClassDecl->getDestructor()->hasTrivialBody())
+      continue;
+
+    return false;
+  }
+
+  return true;
+}
+
 /// EmitDestructorBody - Emits the body of the current destructor.
 void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
   const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CurGD.getDecl());
@@ -792,7 +824,8 @@
     EnterDtorCleanups(Dtor, Dtor_Base);
 
     // Initialize the vtable pointers before entering the body.
-    InitializeVTablePointers(Dtor->getParent());
+    if (!CanSkipVTablePointerInitialization(getContext(), Dtor))
+        InitializeVTablePointers(Dtor->getParent());
 
     if (isTryBody)
       EmitStmt(cast<CXXTryStmt>(Body)->getTryBlock());

Modified: cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp?rev=131368&r1=131367&r2=131368&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/mangle-subst-std.cpp Sat May 14 18:26:09 2011
@@ -8,8 +8,8 @@
 // CHECK: @_ZTCSd0_Si = linkonce_odr unnamed_addr constant 
 // CHECK: @_ZTCSd16_So = linkonce_odr unnamed_addr constant
 // CHECK: @_ZTTSo = linkonce_odr unnamed_addr constant
-// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant
 // CHECK: @_ZTTSi = linkonce_odr unnamed_addr constant
+// CHECK: @_ZTVSo = linkonce_odr unnamed_addr constant
 // CHECK: @_ZTVSi = linkonce_odr unnamed_addr constant
 namespace std {
   struct A { A(); };

Added: cfe/trunk/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp?rev=131368&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/skip-vtable-pointer-initialization.cpp Sat May 14 18:26:09 2011
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+
+namespace Test1 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial.
+struct A {
+  virtual void f();
+  ~A();
+};
+
+// CHECK: define void @_ZN5Test11AD2Ev
+// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test11AE, i64 0, i64 2), i8***
+A::~A() 
+{
+}
+
+}
+
+namespace Test2 {
+
+// Check that we do initialize the vtable pointer in A::~A() since the destructor body isn't trivial.
+struct A {
+  virtual void f();
+  ~A();
+};
+
+// CHECK: define void @_ZN5Test21AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test21AE, i64 0, i64 2), i8***
+A::~A() {
+  f();
+}
+
+}
+
+namespace Test3 {
+
+// Check that we don't initialize the vtable pointer in A::~A(), since the destructor body is trivial
+// and Field's destructor body is also trivial.
+struct Field {
+  ~Field() { }
+};
+
+struct A {
+  virtual void f();
+  ~A();
+
+  Field field;
+};
+
+// CHECK: define void @_ZN5Test31AD2Ev
+// CHECK-NOT: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test31AE, i64 0, i64 2), i8***
+A::~A() {
+  
+}
+
+}
+
+namespace Test4 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor body
+// isn't trivial.
+
+void f();
+
+struct Field {
+  ~Field() { f(); }
+};
+
+struct A {
+  virtual void f();
+  ~A();
+
+  Field field;
+};
+
+// CHECK: define void @_ZN5Test41AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test41AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
+
+namespace Test5 {
+
+// Check that we do initialize the vtable pointer in A::~A(), since Field's destructor isn't
+// available in this translation unit.
+
+struct Field {
+  ~Field();
+};
+
+struct A {
+  virtual void f();
+  ~A();
+
+  Field field;
+};
+
+// CHECK: define void @_ZN5Test51AD2Ev
+// CHECK: store i8** getelementptr inbounds ([3 x i8*]* @_ZTVN5Test51AE, i64 0, i64 2), i8***
+A::~A()
+{
+}
+
+}
\ No newline at end of file





More information about the cfe-commits mailing list