When calling a virtual member function on a base class and the most derived class is marked 'final', we can devirtualize the call.
llvm-svn: 124524
This commit is contained in:
parent
a376b53695
commit
1ae64c5a9d
|
@ -53,16 +53,39 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD,
|
|||
Callee, ReturnValue, Args, MD);
|
||||
}
|
||||
|
||||
static const CXXRecordDecl *getMostDerivedClassDecl(const Expr *Base) {
|
||||
QualType DerivedType = Base->IgnoreParenCasts()->getType();
|
||||
if (const PointerType *PTy = DerivedType->getAs<PointerType>())
|
||||
DerivedType = PTy->getPointeeType();
|
||||
|
||||
return cast<CXXRecordDecl>(DerivedType->castAs<RecordType>()->getDecl());
|
||||
}
|
||||
|
||||
/// canDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given
|
||||
/// expr can be devirtualized.
|
||||
static bool canDevirtualizeMemberFunctionCalls(ASTContext &Context,
|
||||
const Expr *Base,
|
||||
const CXXMethodDecl *MD) {
|
||||
|
||||
// Cannot divirtualize in kext mode.
|
||||
// When building with -fapple-kext, all calls must go through the vtable since
|
||||
// the kernel linker can do runtime patching of vtables.
|
||||
if (Context.getLangOptions().AppleKext)
|
||||
return false;
|
||||
|
||||
// If the most derived class is marked final, we know that no subclass can
|
||||
// override this member function and so we can devirtualize it. For example:
|
||||
//
|
||||
// struct A { virtual void f(); }
|
||||
// struct B final : A { };
|
||||
//
|
||||
// void f(B *b) {
|
||||
// b->f();
|
||||
// }
|
||||
//
|
||||
const CXXRecordDecl *MostDerivedClassDecl = getMostDerivedClassDecl(Base);
|
||||
if (MostDerivedClassDecl->hasAttr<FinalAttr>())
|
||||
return true;
|
||||
|
||||
// If the member function is marked 'final', we know that it can't be
|
||||
// overridden and can therefore devirtualize it.
|
||||
if (MD->hasAttr<FinalAttr>())
|
||||
|
|
|
@ -23,3 +23,17 @@ namespace Test2 {
|
|||
return a->f();
|
||||
}
|
||||
}
|
||||
|
||||
namespace Test3 {
|
||||
struct A {
|
||||
virtual int f();
|
||||
};
|
||||
|
||||
struct B final : A { };
|
||||
|
||||
// CHECK: define i32 @_ZN5Test31fEPNS_1BE
|
||||
int f(B *b) {
|
||||
// CHECK: call i32 @_ZN5Test31A1fEv
|
||||
return b->f();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue