diff options
| author | Peter Collingbourne <peter@pcc.me.uk> | 2016-06-25 00:23:04 +0000 |
|---|---|---|
| committer | Peter Collingbourne <peter@pcc.me.uk> | 2016-06-25 00:23:04 +0000 |
| commit | 0312f614b1bfdad55c1832ee37d6d4b738ea70cf (patch) | |
| tree | fe32499f559708bbe83f63a35aa420c91b882594 /llvm/lib/Analysis | |
| parent | 6ad3d05b681b36f6ecc98523257d154053e4116d (diff) | |
| download | bcm5719-llvm-0312f614b1bfdad55c1832ee37d6d4b738ea70cf.tar.gz bcm5719-llvm-0312f614b1bfdad55c1832ee37d6d4b738ea70cf.zip | |
IR: Introduce llvm.type.checked.load intrinsic.
This intrinsic safely loads a function pointer from a virtual table pointer
using type metadata. This intrinsic is used to implement control flow integrity
in conjunction with virtual call optimization. The virtual call optimization
pass will optimize away llvm.type.checked.load intrinsics associated with
devirtualized calls, thereby removing the type check in cases where it is
not needed to enforce the control flow integrity constraint.
This patch also introduces the capability to copy type metadata between
global variables, and teaches the virtual call optimization pass to do so.
Differential Revision: http://reviews.llvm.org/D21121
llvm-svn: 273756
Diffstat (limited to 'llvm/lib/Analysis')
| -rw-r--r-- | llvm/lib/Analysis/TypeMetadataUtils.cpp | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/llvm/lib/Analysis/TypeMetadataUtils.cpp b/llvm/lib/Analysis/TypeMetadataUtils.cpp index 750cce33856..8d173d77fb6 100644 --- a/llvm/lib/Analysis/TypeMetadataUtils.cpp +++ b/llvm/lib/Analysis/TypeMetadataUtils.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Analysis/TypeMetadataUtils.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" @@ -21,15 +22,17 @@ using namespace llvm; // Search for virtual calls that call FPtr and add them to DevirtCalls. static void findCallsAtConstantOffset(SmallVectorImpl<DevirtCallSite> &DevirtCalls, - Value *FPtr, uint64_t Offset) { + bool *HasNonCallUses, Value *FPtr, uint64_t Offset) { for (const Use &U : FPtr->uses()) { Value *User = U.getUser(); if (isa<BitCastInst>(User)) { - findCallsAtConstantOffset(DevirtCalls, User, Offset); + findCallsAtConstantOffset(DevirtCalls, HasNonCallUses, User, Offset); } else if (auto CI = dyn_cast<CallInst>(User)) { DevirtCalls.push_back({Offset, CI}); } else if (auto II = dyn_cast<InvokeInst>(User)) { DevirtCalls.push_back({Offset, II}); + } else if (HasNonCallUses) { + *HasNonCallUses = true; } } } @@ -44,7 +47,7 @@ findLoadCallsAtConstantOffset(Module *M, if (isa<BitCastInst>(User)) { findLoadCallsAtConstantOffset(M, DevirtCalls, User, Offset); } else if (isa<LoadInst>(User)) { - findCallsAtConstantOffset(DevirtCalls, User, Offset); + findCallsAtConstantOffset(DevirtCalls, nullptr, User, Offset); } else if (auto GEP = dyn_cast<GetElementPtrInst>(User)) { // Take into account the GEP offset. if (VPtr == GEP->getPointerOperand() && GEP->hasAllConstantIndices()) { @@ -57,7 +60,7 @@ findLoadCallsAtConstantOffset(Module *M, } } -void llvm::findDevirtualizableCalls( +void llvm::findDevirtualizableCallsForTypeTest( SmallVectorImpl<DevirtCallSite> &DevirtCalls, SmallVectorImpl<CallInst *> &Assumes, CallInst *CI) { assert(CI->getCalledFunction()->getIntrinsicID() == Intrinsic::type_test); @@ -80,3 +83,36 @@ void llvm::findDevirtualizableCalls( findLoadCallsAtConstantOffset(M, DevirtCalls, CI->getArgOperand(0)->stripPointerCasts(), 0); } + +void llvm::findDevirtualizableCallsForTypeCheckedLoad( + SmallVectorImpl<DevirtCallSite> &DevirtCalls, + SmallVectorImpl<Instruction *> &LoadedPtrs, + SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses, CallInst *CI) { + assert(CI->getCalledFunction()->getIntrinsicID() == + Intrinsic::type_checked_load); + + auto *Offset = dyn_cast<ConstantInt>(CI->getArgOperand(1)); + if (!Offset) { + HasNonCallUses = true; + return; + } + + for (Use &U : CI->uses()) { + auto CIU = U.getUser(); + if (auto EVI = dyn_cast<ExtractValueInst>(CIU)) { + if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 0) { + LoadedPtrs.push_back(EVI); + continue; + } + if (EVI->getNumIndices() == 1 && EVI->getIndices()[0] == 1) { + Preds.push_back(EVI); + continue; + } + } + HasNonCallUses = true; + } + + for (Value *LoadedPtr : LoadedPtrs) + findCallsAtConstantOffset(DevirtCalls, &HasNonCallUses, LoadedPtr, + Offset->getZExtValue()); +} |

