diff options
author | Hiroshi Yamauchi <yamauchi@google.com> | 2020-01-30 13:05:31 -0800 |
---|---|---|
committer | Hiroshi Yamauchi <yamauchi@google.com> | 2020-02-10 13:43:16 -0800 |
commit | bb383ae6120d42fa645fc1b4ea540d8d4f13a29a (patch) | |
tree | 42a5301d3eafba500447d5b0e8be9f468c2c4d7b /llvm/lib/Transforms/Utils/CallPromotionUtils.cpp | |
parent | 6b2979c12300b90a1e69791d43ee9cff14f4265e (diff) | |
download | llvm-bb383ae6120d42fa645fc1b4ea540d8d4f13a29a.zip llvm-bb383ae6120d42fa645fc1b4ea540d8d4f13a29a.tar.gz llvm-bb383ae6120d42fa645fc1b4ea540d8d4f13a29a.tar.bz2 |
[CallPromotionUtils] Add tryPromoteCall.
Summary: It attempts to devirtualize a call on alloca through vtable loads.
Reviewers: davidxl
Subscribers: mgorny, Prazek, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D71308
Diffstat (limited to 'llvm/lib/Transforms/Utils/CallPromotionUtils.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/CallPromotionUtils.cpp | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp index f04d76e..09cd537 100644 --- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp +++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/CallPromotionUtils.h" +#include "llvm/Analysis/Loads.h" +#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -458,4 +460,60 @@ Instruction *llvm::promoteCallWithIfThenElse(CallSite CS, Function *Callee, return promoteCall(CallSite(NewInst), Callee); } +bool llvm::tryPromoteCall(CallSite &CS) { + assert(!CS.getCalledFunction()); + Module *M = CS.getCaller()->getParent(); + const DataLayout &DL = M->getDataLayout(); + Value *Callee = CS.getCalledValue(); + + LoadInst *VTableEntryLoad = dyn_cast<LoadInst>(Callee); + if (!VTableEntryLoad) + return false; // Not a vtable entry load. + Value *VTableEntryPtr = VTableEntryLoad->getPointerOperand(); + APInt VTableOffset(DL.getTypeSizeInBits(VTableEntryPtr->getType()), 0); + Value *VTableBasePtr = VTableEntryPtr->stripAndAccumulateConstantOffsets( + DL, VTableOffset, /* AllowNonInbounds */ true); + LoadInst *VTablePtrLoad = dyn_cast<LoadInst>(VTableBasePtr); + if (!VTablePtrLoad) + return false; // Not a vtable load. + Value *Object = VTablePtrLoad->getPointerOperand(); + APInt ObjectOffset(DL.getTypeSizeInBits(Object->getType()), 0); + Value *ObjectBase = Object->stripAndAccumulateConstantOffsets( + DL, ObjectOffset, /* AllowNonInbounds */ true); + if (!(isa<AllocaInst>(ObjectBase) && ObjectOffset == 0)) + // Not an Alloca or the offset isn't zero. + return false; + + // Look for the vtable pointer store into the object by the ctor. + BasicBlock::iterator BBI(VTablePtrLoad); + Value *VTablePtr = FindAvailableLoadedValue( + VTablePtrLoad, VTablePtrLoad->getParent(), BBI, 0, nullptr, nullptr); + if (!VTablePtr) + return false; // No vtable found. + APInt VTableOffsetGVBase(DL.getTypeSizeInBits(VTablePtr->getType()), 0); + Value *VTableGVBase = VTablePtr->stripAndAccumulateConstantOffsets( + DL, VTableOffsetGVBase, /* AllowNonInbounds */ true); + GlobalVariable *GV = dyn_cast<GlobalVariable>(VTableGVBase); + if (!(GV && GV->isConstant() && GV->hasDefinitiveInitializer())) + // Not in the form of a global constant variable with an initializer. + return false; + + Constant *VTableGVInitializer = GV->getInitializer(); + APInt VTableGVOffset = VTableOffsetGVBase + VTableOffset; + if (!(VTableGVOffset.getActiveBits() <= 64)) + return false; // Out of range. + Constant *Ptr = getPointerAtOffset(VTableGVInitializer, + VTableGVOffset.getZExtValue(), + *M); + if (!Ptr) + return false; // No constant (function) pointer found. + Function *DirectCallee = dyn_cast<Function>(Ptr->stripPointerCasts()); + if (!DirectCallee) + return false; // No function pointer found. + + // Success. + promoteCall(CS, DirectCallee); + return true; +} + #undef DEBUG_TYPE |