[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