[cfe-commits] r159350 - in /cfe/trunk: lib/CodeGen/CGExprCXX.cpp test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp

Rafael Espindola rafael.espindola at gmail.com
Thu Jun 28 07:28:57 PDT 2012


Author: rafael
Date: Thu Jun 28 09:28:57 2012
New Revision: 159350

URL: http://llvm.org/viewvc/llvm-project?rev=159350&view=rev
Log:
Don't devirtualize calls when we don't have the correct type of the this pointer
handy. It can be done, but we would have to build a derived-to-base cast
during codegen to compute the correct this pointer.

I will handle covariant returns next.

Modified:
    cfe/trunk/lib/CodeGen/CGExprCXX.cpp
    cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp

Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=159350&r1=159349&r2=159350&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Thu Jun 28 09:28:57 2012
@@ -142,6 +142,14 @@
   return false;
 }
 
+static CXXRecordDecl *getCXXRecord(const Expr *E) {
+  QualType T = E->getType();
+  if (const PointerType *PTy = T->getAs<PointerType>())
+    T = PTy->getPointeeType();
+  const RecordType *Ty = T->castAs<RecordType>();
+  return cast<CXXRecordDecl>(Ty->getDecl());
+}
+
 // Note: This function also emit constructor calls to support a MSVC
 // extensions allowing explicit constructor function call.
 RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE,
@@ -174,18 +182,33 @@
   // Compute the object pointer.
   const Expr *Base = ME->getBase();
   bool CanUseVirtualCall = MD->isVirtual() && !ME->hasQualifier();
-  bool Devirtualize = CanUseVirtualCall &&
-    canDevirtualizeMemberFunctionCalls(getContext(), Base, MD);
 
-  const Expr *Inner = Base;
-  if (Devirtualize)
-    Inner = Base->ignoreParenBaseCasts();
+  const CXXMethodDecl *DevirtualizedMethod = NULL;
+  if (CanUseVirtualCall &&
+      canDevirtualizeMemberFunctionCalls(getContext(), Base, MD)) {
+    const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType();
+    DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl);
+    assert(DevirtualizedMethod);
+    const CXXRecordDecl *DevirtualizedClass = DevirtualizedMethod->getParent();
+    const Expr *Inner = Base->ignoreParenBaseCasts();
+    if (getCXXRecord(Inner) == DevirtualizedClass)
+      // If the class of the Inner expression is where the dynamic method
+      // is defined, build the this pointer from it.
+      Base = Inner;
+    else if (getCXXRecord(Base) != DevirtualizedClass) {
+      // If the method is defined in a class that is not the best dynamic
+      // one or the one of the full expression, we would have to build
+      // a derived-to-base cast to compute the correct this pointer, but
+      // we don't have support for that yet, so do a virtual call.
+      DevirtualizedMethod = NULL;
+    }
+  }
 
   llvm::Value *This;
   if (ME->isArrow())
-    This = EmitScalarExpr(Inner);
+    This = EmitScalarExpr(Base);
   else
-    This = EmitLValue(Inner).getAddress();
+    This = EmitLValue(Base).getAddress();
 
 
   if (MD->isTrivial()) {
@@ -233,8 +256,7 @@
   //
   // We also don't emit a virtual call if the base expression has a record type
   // because then we know what the type is.
-  bool UseVirtualCall = CanUseVirtualCall && !Devirtualize;
-  const CXXRecordDecl *MostDerivedClassDecl = Inner->getBestDynamicClassType();
+  bool UseVirtualCall = CanUseVirtualCall && !DevirtualizedMethod;
 
   llvm::Value *Callee;
   if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD)) {
@@ -245,13 +267,11 @@
           MD->isVirtual() &&
           ME->hasQualifier())
         Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
-      else if (!Devirtualize)
+      else if (!DevirtualizedMethod)
         Callee = CGM.GetAddrOfFunction(GlobalDecl(Dtor, Dtor_Complete), Ty);
       else {
-        const CXXMethodDecl *DM =
-          Dtor->getCorrespondingMethodInClass(MostDerivedClassDecl);
-        assert(DM);
-        const CXXDestructorDecl *DDtor = cast<CXXDestructorDecl>(DM);
+        const CXXDestructorDecl *DDtor =
+          cast<CXXDestructorDecl>(DevirtualizedMethod);
         Callee = CGM.GetAddrOfFunction(GlobalDecl(DDtor, Dtor_Complete), Ty);
       }
     }
@@ -265,13 +285,10 @@
         MD->isVirtual() &&
         ME->hasQualifier())
       Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty);
-    else if (!Devirtualize)
+    else if (!DevirtualizedMethod)
       Callee = CGM.GetAddrOfFunction(MD, Ty);
     else {
-      const CXXMethodDecl *DerivedMethod =
-        MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
-      assert(DerivedMethod);
-      Callee = CGM.GetAddrOfFunction(DerivedMethod, Ty);
+      Callee = CGM.GetAddrOfFunction(DevirtualizedMethod, Ty);
     }
   }
 

Modified: cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp?rev=159350&r1=159349&r2=159350&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/devirtualize-virtual-function-calls-final.cpp Thu Jun 28 09:28:57 2012
@@ -80,7 +80,11 @@
 
   // CHECK: define void @_ZN5Test51fEPNS_1CE
   void f(C* d) {
-    // CHECK: call void @_ZN5Test51B1fEv
+    // FIXME: It should be possible to devirtualize this case, but that is
+    // not implemented yet.
+    // CHECK: getelementptr
+    // CHECK-NEXT: %[[FUNC:.*]] = load
+    // CHECK-NEXT: call void %[[FUNC]]
     static_cast<A*>(d)->f();
   }
 }
@@ -133,3 +137,18 @@
     return static_cast<bar*>(z)->f();
   }
 }
+
+namespace Test8 {
+  struct A { virtual ~A() {} };
+  struct B {
+    int b;
+    virtual int foo() { return b; }
+  };
+  struct C final : A, B {  };
+  // CHECK: define i32 @_ZN5Test84testEPNS_1CE
+  int test(C *c) {
+    // CHECK: %[[THIS:.*]] = phi
+    // CHECK-NEXT: call i32 @_ZN5Test81B3fooEv(%"struct.Test8::B"* %[[THIS]])
+    return static_cast<B*>(c)->foo();
+  }
+}





More information about the cfe-commits mailing list