summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
authorDmitry Mikulin <dmitry.mikulin@sony.com>2018-05-17 14:29:07 +0000
committerDmitry Mikulin <dmitry.mikulin@sony.com>2018-05-17 14:29:07 +0000
commit3c6b4e35bd513c5421dcdc7a56bc063ccd6d6ae7 (patch)
tree0a373e84c7981c2c0ff1d1fd4ec350f4ad96abd8 /llvm/lib/Transforms
parent85a92c3f0b6068562554d709773f3250b3ff1702 (diff)
downloadbcm5719-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.cpp93
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));
OpenPOWER on IntegriCloud