summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/IPO
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-11-11 21:39:26 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-11-11 21:39:26 +0000
commit1fe189d79585b5d1aea84e6c2f3eca781e21f32f (patch)
treed801eb0cc1d5e5e479e622b0115f29d2bc1131e3 /llvm/lib/Transforms/IPO
parentd4372f783b52919c569f3e2007e3ba9edb45c7fb (diff)
downloadbcm5719-llvm-1fe189d79585b5d1aea84e6c2f3eca781e21f32f.tar.gz
bcm5719-llvm-1fe189d79585b5d1aea84e6c2f3eca781e21f32f.zip
[cfi] Fix weak functions handling.
When a function pointer is replaced with a jumptable pointer, special case is needed to preserve the semantics of extern_weak functions. Since a jumptable entry can not be extern_weak, we emulate that behaviour by replacing all references to F (the extern_weak function) with the following expression: F != nullptr ? JumpTablePtr : nullptr. Extra special care is needed for global initializers, since most (or probably all) backends can not lower an initializer that includes this kind of constant expression. Initializers like that are replaced with a global constructor (i.e. a runtime initializer). llvm-svn: 286636
Diffstat (limited to 'llvm/lib/Transforms/IPO')
-rw-r--r--llvm/lib/Transforms/IPO/LowerTypeTests.cpp76
1 files changed, 74 insertions, 2 deletions
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
index 8631886a281..241f475cea9 100644
--- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -14,6 +14,7 @@
#include "llvm/Transforms/IPO/LowerTypeTests.h"
#include "llvm/ADT/EquivalenceClasses.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/Triple.h"
#include "llvm/IR/Constant.h"
@@ -228,6 +229,7 @@ class LowerTypeTestsModule {
std::vector<ByteArrayInfo> ByteArrayInfos;
Mangler Mang;
+ Function *WeakInitializerFn = nullptr;
BitSetInfo
buildBitSet(Metadata *TypeId,
@@ -260,6 +262,11 @@ class LowerTypeTestsModule {
void buildBitSetsFromDisjointSet(ArrayRef<Metadata *> TypeIds,
ArrayRef<GlobalObject *> Globals);
+ void replaceWeakDeclarationWithJumpTablePtr(Function *F, Constant *JT);
+ void moveInitializerToModuleConstructor(GlobalVariable *GV);
+ void findGlobalVariableUsersOf(Constant *C,
+ SmallSetVector<GlobalVariable *, 8> &Out);
+
public:
LowerTypeTestsModule(Module &M);
bool lower();
@@ -733,6 +740,66 @@ void LowerTypeTestsModule::buildBitSetsFromFunctions(
report_fatal_error("Unsupported architecture for jump tables");
}
+void LowerTypeTestsModule::moveInitializerToModuleConstructor(
+ GlobalVariable *GV) {
+ if (WeakInitializerFn == nullptr) {
+ WeakInitializerFn = Function::Create(
+ FunctionType::get(Type::getVoidTy(M.getContext()),
+ /* IsVarArg */ false),
+ GlobalValue::InternalLinkage, "__cfi_global_var_init", &M);
+ BasicBlock *BB =
+ BasicBlock::Create(M.getContext(), "entry", WeakInitializerFn);
+ ReturnInst::Create(M.getContext(), BB);
+ WeakInitializerFn->setSection(
+ ObjectFormat == Triple::MachO
+ ? "__TEXT,__StaticInit,regular,pure_instructions"
+ : ".text.startup");
+ // This code is equivalent to relocation application, and should run at the
+ // earliest possible time (i.e. with the highest priority).
+ appendToGlobalCtors(M, WeakInitializerFn, /* Priority */ 0);
+ }
+
+ IRBuilder<> IRB(WeakInitializerFn->getEntryBlock().getTerminator());
+ GV->setConstant(false);
+ IRB.CreateAlignedStore(GV->getInitializer(), GV, GV->getAlignment());
+ GV->setInitializer(Constant::getNullValue(GV->getValueType()));
+}
+
+void LowerTypeTestsModule::findGlobalVariableUsersOf(
+ Constant *C, SmallSetVector<GlobalVariable *, 8> &Out) {
+ for (auto *U : C->users()){
+ if (auto *GV = dyn_cast<GlobalVariable>(U))
+ Out.insert(GV);
+ else if (auto *C2 = dyn_cast<Constant>(U))
+ findGlobalVariableUsersOf(C2, Out);
+ }
+}
+
+// Replace all uses of F with (F ? JT : 0).
+void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
+ Function *F, Constant *JT) {
+ // The target expression can not appear in a constant initializer on most
+ // (all?) targets. Switch to a runtime initializer.
+ SmallSetVector<GlobalVariable *, 8> GlobalVarUsers;
+ findGlobalVariableUsersOf(F, GlobalVarUsers);
+ for (auto GV : GlobalVarUsers)
+ moveInitializerToModuleConstructor(GV);
+
+ // Can not RAUW F with an expression that uses F. Replace with a temporary
+ // placeholder first.
+ Function *PlaceholderFn =
+ Function::Create(cast<FunctionType>(F->getValueType()),
+ GlobalValue::ExternalWeakLinkage, "", &M);
+ F->replaceAllUsesWith(PlaceholderFn);
+
+ Constant *Target = ConstantExpr::getSelect(
+ ConstantExpr::getICmp(CmpInst::ICMP_NE, F,
+ Constant::getNullValue(F->getType())),
+ JT, Constant::getNullValue(F->getType()));
+ PlaceholderFn->replaceAllUsesWith(Target);
+ PlaceholderFn->eraseFromParent();
+}
+
/// Given a disjoint set of type identifiers and functions, build a jump table
/// for the functions, build the bit sets and lower the llvm.type.test calls.
void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
@@ -850,10 +917,15 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
ConstantInt::get(IntPtrTy, I)}),
Functions[I]->getType());
- Functions[I]->replaceAllUsesWith(CombinedGlobalElemPtr);
- if (Functions[I]->isWeakForLinker())
+
+ if (Functions[I]->isWeakForLinker()) {
AsmOS << ".weak " << Functions[I]->getName() << "\n";
+ replaceWeakDeclarationWithJumpTablePtr(Functions[I],
+ CombinedGlobalElemPtr);
+ } else {
+ Functions[I]->replaceAllUsesWith(CombinedGlobalElemPtr);
+ }
} else {
assert(Functions[I]->getType()->getAddressSpace() == 0);
OpenPOWER on IntegriCloud