diff options
author | Arthur Eubanks <aeubanks@google.com> | 2021-04-22 12:04:14 -0700 |
---|---|---|
committer | Arthur Eubanks <aeubanks@google.com> | 2021-05-27 16:04:19 -0700 |
commit | 8086f9d87ee81aacf829bdad94744a75cf692ebc (patch) | |
tree | fa4085f9d4c627ed99d62d7b1cd8cc1a8786e867 /llvm/lib/Analysis/ConstantFolding.cpp | |
parent | 0fa5aac292b8e1bafb00b55233c78466b06bc323 (diff) | |
download | llvm-8086f9d87ee81aacf829bdad94744a75cf692ebc.zip llvm-8086f9d87ee81aacf829bdad94744a75cf692ebc.tar.gz llvm-8086f9d87ee81aacf829bdad94744a75cf692ebc.tar.bz2 |
[ConstFold] Simplify a load's GEP operand through local aliases
MSVC-style RTTI produces loads through a GEP of a local alias which
itself is a GEP. Currently we aren't able to devirtualize any virtual
calls when MSVC RTTI is enabled.
This patch attempts to simplify a load's GEP operand by calling
SymbolicallyEvaluateGEP() with an option to look through local aliases.
Differential Revision: https://reviews.llvm.org/D101100
Diffstat (limited to 'llvm/lib/Analysis/ConstantFolding.cpp')
-rw-r--r-- | llvm/lib/Analysis/ConstantFolding.cpp | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 7d4fcdc..989379d 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -63,6 +63,11 @@ using namespace llvm; namespace { +Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, + ArrayRef<Constant *> Ops, + const DataLayout &DL, + const TargetLibraryInfo *TLI, + bool ForLoadOperand); //===----------------------------------------------------------------------===// // Constant Folding internal helper functions @@ -690,6 +695,33 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, GV->getInitializer(), CE, Ty, DL)) return V; } + } else { + // Try to simplify GEP if the pointer operand wasn't a GlobalVariable. + // SymbolicallyEvaluateGEP() with `ForLoadOperand = true` can potentially + // simplify the GEP more than it normally would have been, but should only + // be used for const folding loads. + SmallVector<Constant *> Ops; + for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I) + Ops.push_back(cast<Constant>(CE->getOperand(I))); + if (auto *Simplified = dyn_cast_or_null<ConstantExpr>( + SymbolicallyEvaluateGEP(cast<GEPOperator>(CE), Ops, DL, nullptr, + /*ForLoadOperand*/ true))) { + // If the symbolically evaluated GEP is another GEP, we can only const + // fold it if the resulting pointer operand is a GlobalValue. Otherwise + // there is nothing else to simplify since the GEP is already in the + // most simplified form. + if (auto *SimplifiedGEP = dyn_cast<GEPOperator>(Simplified)) { + if (auto *GV = dyn_cast<GlobalVariable>(Simplified->getOperand(0))) { + if (GV->isConstant() && GV->hasDefinitiveInitializer()) { + if (Constant *V = ConstantFoldLoadThroughGEPConstantExpr( + GV->getInitializer(), Simplified, Ty, DL)) + return V; + } + } + } else { + return ConstantFoldLoadFromConstPtr(Simplified, Ty, DL); + } + } } } @@ -835,10 +867,18 @@ Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops, } /// Strip the pointer casts, but preserve the address space information. -Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) { +Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy, + bool ForLoadOperand) { assert(Ptr->getType()->isPointerTy() && "Not a pointer type"); auto *OldPtrTy = cast<PointerType>(Ptr->getType()); Ptr = cast<Constant>(Ptr->stripPointerCasts()); + if (ForLoadOperand) { + while (isa<GlobalAlias>(Ptr) && !cast<GlobalAlias>(Ptr)->isInterposable() && + !cast<GlobalAlias>(Ptr)->getBaseObject()->isInterposable()) { + Ptr = cast<GlobalAlias>(Ptr)->getAliasee(); + } + } + auto *NewPtrTy = cast<PointerType>(Ptr->getType()); ElemTy = NewPtrTy->getPointerElementType(); @@ -855,7 +895,8 @@ Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) { Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, ArrayRef<Constant *> Ops, const DataLayout &DL, - const TargetLibraryInfo *TLI) { + const TargetLibraryInfo *TLI, + bool ForLoadOperand) { const GEPOperator *InnermostGEP = GEP; bool InBounds = GEP->isInBounds(); @@ -903,7 +944,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, DL.getIndexedOffsetInType( SrcElemTy, makeArrayRef((Value * const *)Ops.data() + 1, Ops.size() - 1))); - Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy); + Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand); // If this is a GEP of a GEP, fold it all into a single GEP. while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) { @@ -925,7 +966,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP, Ptr = cast<Constant>(GEP->getOperand(0)); SrcElemTy = GEP->getSourceElementType(); Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps)); - Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy); + Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand); } // If the base value for this address is a literal integer value, fold the @@ -1062,7 +1103,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode, return ConstantFoldCastOperand(Opcode, Ops[0], DestTy, DL); if (auto *GEP = dyn_cast<GEPOperator>(InstOrCE)) { - if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI)) + if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI, + /*ForLoadOperand*/ false)) return C; return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(), Ops[0], |