aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
diff options
context:
space:
mode:
authorHiroshi Yamauchi <yamauchi@google.com>2020-01-30 13:05:31 -0800
committerHiroshi Yamauchi <yamauchi@google.com>2020-02-10 13:43:16 -0800
commitbb383ae6120d42fa645fc1b4ea540d8d4f13a29a (patch)
tree42a5301d3eafba500447d5b0e8be9f468c2c4d7b /llvm/lib/Transforms/Utils/CallPromotionUtils.cpp
parent6b2979c12300b90a1e69791d43ee9cff14f4265e (diff)
downloadllvm-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.cpp58
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