diff options
author | Dmitry Mikulin <dmitry.mikulin@sony.com> | 2018-05-17 14:29:07 +0000 |
---|---|---|
committer | Dmitry Mikulin <dmitry.mikulin@sony.com> | 2018-05-17 14:29:07 +0000 |
commit | 3c6b4e35bd513c5421dcdc7a56bc063ccd6d6ae7 (patch) | |
tree | 0a373e84c7981c2c0ff1d1fd4ec350f4ad96abd8 /llvm/lib/Transforms | |
parent | 85a92c3f0b6068562554d709773f3250b3ff1702 (diff) | |
download | bcm5719-llvm-3c6b4e35bd513c5421dcdc7a56bc063ccd6d6ae7.tar.gz bcm5719-llvm-3c6b4e35bd513c5421dcdc7a56bc063ccd6d6ae7.zip |
In thin and full LTO + CFI, direct function calls may go through jump table
entries to reach the target. Since these calls don't require type checks,
we can short-circuit them to their real targets.
Differential Revision: https://reviews.llvm.org/D46326
llvm-svn: 332610
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r-- | llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 93 |
1 files changed, 82 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index d2545af8502..227bfd1d337 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -429,6 +429,17 @@ class LowerTypeTestsModule { void createJumpTable(Function *F, ArrayRef<GlobalTypeMember *> Functions); + /// replaceCfiUses - Go through the uses list for this definition + /// and make each use point to "V" instead of "this" when the use is outside + /// the block. 'This's use list is expected to have at least one element. + /// Unlike replaceAllUsesWith this function skips blockaddr and direct call + /// uses. + void replaceCfiUses(Value *Old, Value *New); + + /// replaceDirectCalls - Go through the uses list for this definition and + /// replace each use, which is a direct function call. + void replaceDirectCalls(Value *Old, Value *New); + public: LowerTypeTestsModule(Module &M, ModuleSummaryIndex *ExportSummary, const ModuleSummaryIndex *ImportSummary); @@ -967,14 +978,19 @@ void LowerTypeTestsModule::importTypeTest(CallInst *CI) { void LowerTypeTestsModule::importFunction(Function *F, bool isDefinition) { assert(F->getType()->getAddressSpace() == 0); - // Declaration of a local function - nothing to do. - if (F->isDeclarationForLinker() && isDefinition) - return; - GlobalValue::VisibilityTypes Visibility = F->getVisibility(); std::string Name = F->getName(); - Function *FDecl; + if (F->isDeclarationForLinker() && isDefinition) { + Function *RealF = Function::Create(F->getFunctionType(), + GlobalValue::ExternalLinkage, + Name + ".cfi", &M); + RealF->setVisibility(Visibility); + replaceDirectCalls(F, RealF); + return; + } + + Function *FDecl; if (F->isDeclarationForLinker() && !isDefinition) { // Declaration of an external function. FDecl = Function::Create(F->getFunctionType(), GlobalValue::ExternalLinkage, @@ -1014,7 +1030,7 @@ void LowerTypeTestsModule::importFunction(Function *F, bool isDefinition) { if (F->isWeakForLinker()) replaceWeakDeclarationWithJumpTablePtr(F, FDecl); else - F->replaceUsesExceptBlockAddr(FDecl); + replaceCfiUses(F, FDecl); } void LowerTypeTestsModule::lowerTypeTestCalls( @@ -1209,7 +1225,7 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr( Function *PlaceholderFn = Function::Create(cast<FunctionType>(F->getValueType()), GlobalValue::ExternalWeakLinkage, "", &M); - F->replaceAllUsesWith(PlaceholderFn); + replaceCfiUses(F, PlaceholderFn); Constant *Target = ConstantExpr::getSelect( ConstantExpr::getICmp(CmpInst::ICMP_NE, F, @@ -1433,7 +1449,7 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( if (F->isWeakForLinker()) replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr); else - F->replaceAllUsesWith(CombinedGlobalElemPtr); + replaceCfiUses(F, CombinedGlobalElemPtr); } else { assert(F->getType()->getAddressSpace() == 0); @@ -1443,10 +1459,8 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative( FAlias->takeName(F); if (FAlias->hasName()) F->setName(FAlias->getName() + ".cfi"); - F->replaceUsesExceptBlockAddr(FAlias); + replaceCfiUses(F, FAlias); } - if (!F->isDeclarationForLinker()) - F->setLinkage(GlobalValue::InternalLinkage); } createJumpTable(JumpTableFn, Functions); @@ -1602,6 +1616,63 @@ bool LowerTypeTestsModule::runForTesting(Module &M) { return Changed; } +static bool isDirectCall(Use& U) { + auto *Usr = dyn_cast<CallInst>(U.getUser()); + if (Usr) { + CallSite CS(Usr); + if (CS.isCallee(&U)) + return true; + } + return false; +} + +void LowerTypeTestsModule::replaceCfiUses(Value *Old, Value *New) { + SmallSetVector<Constant *, 4> Constants; + auto UI = Old->use_begin(), E = Old->use_end(); + for (; UI != E;) { + Use &U = *UI; + ++UI; + + // Skip block addresses + if (isa<BlockAddress>(U.getUser())) + continue; + + // Skip direct calls + if (isDirectCall(U)) + continue; + + // Must handle Constants specially, we cannot call replaceUsesOfWith on a + // constant because they are uniqued. + if (auto *C = dyn_cast<Constant>(U.getUser())) { + if (!isa<GlobalValue>(C)) { + // Save unique users to avoid processing operand replacement + // more than once. + Constants.insert(C); + continue; + } + } + + U.set(New); + } + + // Process operand replacement of saved constants. + for (auto *C : Constants) + C->handleOperandChange(Old, New); +} + +void LowerTypeTestsModule::replaceDirectCalls(Value *Old, Value *New) { + auto UI = Old->use_begin(), E = Old->use_end(); + for (; UI != E;) { + Use &U = *UI; + ++UI; + + if (!isDirectCall(U)) + continue; + + U.set(New); + } +} + bool LowerTypeTestsModule::lower() { Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); |