diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-11-03 18:55:18 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2016-11-03 18:55:18 +0000 |
commit | 4d47937a5393428157049587bb361e36ccd197ca (patch) | |
tree | 5d3e2676f399de8fa7ae88d5ad85ed5d92d747a4 /lib/CodeGen/CGClass.cpp | |
parent | f1b760ebd6aaea8b930aa076a36db0768b80c1f2 (diff) |
Improve obvious-most-derived-type devirtualization:
* if the base is produced by a series of derived-to-base conversions, check
the expression inside them when looking for an expression with a known
dynamic type
* step past MaterializeTemporaryExprs when checking for a known dynamic type
* when checking for a known dynamic type, treat all class prvalues as having
a known dynamic type after skipping all relevant rvalue subobject
adjustments
* treat callees formed by pointer-to-member access for a non-reference member
type like callees formed by member access.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@285954 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGClass.cpp')
-rw-r--r-- | lib/CodeGen/CGClass.cpp | 52 |
1 files changed, 15 insertions, 37 deletions
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 99eb5d5c03..2f5855f89b 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -2842,31 +2842,6 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( cast<llvm::PointerType>(VTable->getType())->getElementType()); } -// FIXME: Ideally Expr::IgnoreParenNoopCasts should do this, but it doesn't do -// quite what we want. -static const Expr *skipNoOpCastsAndParens(const Expr *E) { - while (true) { - if (const ParenExpr *PE = dyn_cast<ParenExpr>(E)) { - E = PE->getSubExpr(); - continue; - } - - if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { - if (CE->getCastKind() == CK_NoOp) { - E = CE->getSubExpr(); - continue; - } - } - if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { - if (UO->getOpcode() == UO_Extension) { - E = UO->getSubExpr(); - continue; - } - } - return E; - } -} - bool CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, const CXXMethodDecl *MD) { @@ -2880,6 +2855,12 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, if (MD->hasAttr<FinalAttr>()) return true; + // If the base expression (after skipping derived-to-base conversions) is a + // class prvalue, then we can devirtualize. + Base = Base->getBestDynamicClassTypeExpr(); + if (Base->isRValue() && Base->getType()->isRecordType()) + return true; + // 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: // @@ -2907,7 +2888,6 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, if (MD->getParent()->hasAttr<FinalAttr>()) return true; - Base = skipNoOpCastsAndParens(Base); if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { // This is a record decl. We know the type and can devirtualize it. @@ -2924,17 +2904,15 @@ CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) return VD->getType()->isRecordType(); - // We can always devirtualize calls on temporary object expressions. - if (isa<CXXConstructExpr>(Base)) - return true; - - // And calls on bound temporaries. - if (isa<CXXBindTemporaryExpr>(Base)) - return true; - - // Check if this is a call expr that returns a record type. - if (const CallExpr *CE = dyn_cast<CallExpr>(Base)) - return CE->getCallReturnType(getContext())->isRecordType(); + // Likewise for calls on an object accessed by a (non-reference) pointer to + // member access. + if (auto *BO = dyn_cast<BinaryOperator>(Base)) { + if (BO->isPtrMemOp()) { + auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>(); + if (MPT->getPointeeType()->isRecordType()) + return true; + } + } // We can't devirtualize the call. return false; |