summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-12-22 22:22:35 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2016-12-22 22:22:35 +0000
commit27d4c9b71b426742197174b7415e166f3272975a (patch)
treea4c23ae4c3eba250901ab47ca41bdd4024853e35 /llvm/lib/Transforms
parente477fb95916117b4e7414c4ed90f4b1dd4a03a60 (diff)
downloadbcm5719-llvm-27d4c9b71b426742197174b7415e166f3272975a.tar.gz
bcm5719-llvm-27d4c9b71b426742197174b7415e166f3272975a.zip
[cfi] Emit jump tables as a function-level inline asm.
Use a dummy private function with inline asm calls instead of module level asm blocks for CFI jumptables. The main advantage is that now jumptable codegen can be affected by the function attributes (like target_cpu on ARM). Module level asm gets the default subtarget based on the target triple, which is often not good enough. This change also uses asm constraints/arguments to reference jumptable targets and aliases directly. We no longer do asm name mangling in an IR pass. Differential Revision: https://reviews.llvm.org/D28012 llvm-svn: 290384
Diffstat (limited to 'llvm/lib/Transforms')
-rw-r--r--llvm/lib/Transforms/IPO/LowerTypeTests.cpp222
1 files changed, 90 insertions, 132 deletions
diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
index 753eb4c31e7..2948878cffc 100644
--- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
+++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp
@@ -23,9 +23,9 @@
#include "llvm/IR/GlobalObject.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/Mangler.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/Pass.h"
@@ -243,6 +243,7 @@ class LowerTypeTestsModule {
bool LinkerSubsectionsViaSymbols;
Triple::ArchType Arch;
+ Triple::OSType OS;
Triple::ObjectFormatType ObjectFormat;
IntegerType *Int1Ty = Type::getInt1Ty(M.getContext());
@@ -260,7 +261,6 @@ class LowerTypeTestsModule {
std::vector<ByteArrayInfo> ByteArrayInfos;
- Mangler Mang;
Function *WeakInitializerFn = nullptr;
BitSetInfo
@@ -281,9 +281,8 @@ class LowerTypeTestsModule {
ArrayRef<GlobalTypeMember *> Globals);
unsigned getJumpTableEntrySize();
Type *getJumpTableEntryType();
- void createJumpTableEntry(raw_ostream &OS, Function *Dest, unsigned Distance);
- void createJumpTableAlias(raw_ostream &OS, Function *Dest,
- GlobalVariable *JumpTable, unsigned Distance);
+ void createJumpTableEntry(raw_ostream &AsmOS, raw_ostream &ConstraintOS,
+ SmallVectorImpl<Value *> &AsmArgs, Function *Dest);
void verifyTypeMDNode(GlobalObject *GO, MDNode *Type);
void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
ArrayRef<GlobalTypeMember *> Functions);
@@ -299,6 +298,8 @@ class LowerTypeTestsModule {
void findGlobalVariableUsersOf(Constant *C,
SmallSetVector<GlobalVariable *, 8> &Out);
+ void createJumpTable(Function *F, ArrayRef<GlobalTypeMember *> Functions);
+
public:
LowerTypeTestsModule(Module &M);
bool lower();
@@ -691,80 +692,27 @@ unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
}
}
-static bool isValidAsmUnquotedName(StringRef Name) {
- if (Name.empty())
- return false;
-
- for (char C : Name) {
- if (!((C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') ||
- (C >= '0' && C <= '9') || C == '_' || C == '$' || C == '.' ||
- C == '@'))
- return false;
- }
-
- return true;
-}
-
-// Create a constant representing a jump table entry for the target. This
-// consists of an instruction sequence containing a relative branch to Dest. The
-// constant will be laid out at address Src+(Len*Distance) where Len is the
-// target-specific jump table entry size.
-void LowerTypeTestsModule::createJumpTableEntry(raw_ostream &OS, Function *Dest,
- unsigned Distance) {
- // FIXME: replace IR Mangler with TargetLoweringObjectFile interface.
- // A private instance of Mangler we use here can not deal with unnamed
- // symbols, as it may create colliding labels. Thankfully(?), the use of
- // inline asm requires us to give names to all affected functions anyway.
- assert(Dest->hasName() && "jumptable targets can not be anonymous");
- SmallString<16> Name;
- Mang.getNameWithPrefix(Name, Dest, /* CannotUsePrivateLabel */ false);
-
- if (!isValidAsmUnquotedName(Name)) {
- // We are going to emit a function call as textual asm. Escaped strings
- // in such expressions are not well supported.
- report_fatal_error(
- "CFI-ICall does not allow special characters in a function name.");
- }
+// Create a jump table entry for the target. This consists of an instruction
+// sequence containing a relative branch to Dest. Appends inline asm text,
+// constraints and arguments to AsmOS, ConstraintOS and AsmArgs.
+void LowerTypeTestsModule::createJumpTableEntry(
+ raw_ostream &AsmOS, raw_ostream &ConstraintOS,
+ SmallVectorImpl<Value *> &AsmArgs, Function *Dest) {
+ unsigned ArgIndex = AsmArgs.size();
if (Arch == Triple::x86 || Arch == Triple::x86_64) {
- OS << "jmp " << Name << "@plt\n";
- OS << "int3\nint3\nint3\n";
+ AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n";
+ AsmOS << "int3\nint3\nint3\n";
} else if (Arch == Triple::arm || Arch == Triple::aarch64) {
- OS << "b " << Name << "\n";
+ AsmOS << "b $" << ArgIndex << "\n";
} else if (Arch == Triple::thumb) {
- OS << "b.w " << Name << "\n";
+ AsmOS << "b.w $" << ArgIndex << "\n";
} else {
report_fatal_error("Unsupported architecture for jump tables");
}
-}
-
-void LowerTypeTestsModule::createJumpTableAlias(raw_ostream &OS, Function *Dest,
- GlobalVariable *JumpTable,
- unsigned Distance) {
- assert(Dest->hasName() && "jumptable targets can not be anonymous");
- SmallString<16> Name;
- Mang.getNameWithPrefix(Name, Dest, /* CannotUsePrivateLabel */ false);
-
- if (!isValidAsmUnquotedName(Name)) {
- // We are going to emit a function alias as textual asm. Escaped strings
- // in such expressions are not well supported.
- report_fatal_error(
- "CFI-ICall does not allow special characters in a function name.");
- }
- if (Dest->isWeakForLinker())
- OS << ".weak " << Name << "\n";
- else if (!Dest->hasLocalLinkage())
- OS << ".globl " << Name << "\n";
- OS << ".type " << Name << ", function\n";
- if (Arch == Triple::thumb) {
- OS << ".thumb_set " << Name << ", " << JumpTable->getName() << " + "
- << (getJumpTableEntrySize() * Distance) << "\n";
- } else {
- OS << Name << " = " << JumpTable->getName() << " + "
- << (getJumpTableEntrySize() * Distance) << "\n";
- }
- OS << ".size " << Name << ", " << getJumpTableEntrySize() << "\n";
+ ConstraintOS << (ArgIndex > 0 ? ",s" : "s");
+ AsmArgs.push_back(Dest);
}
Type *LowerTypeTestsModule::getJumpTableEntryType() {
@@ -844,6 +792,52 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
PlaceholderFn->eraseFromParent();
}
+void LowerTypeTestsModule::createJumpTable(
+ Function *F, ArrayRef<GlobalTypeMember *> Functions) {
+ std::string AsmStr, ConstraintStr;
+ raw_string_ostream AsmOS(AsmStr), ConstraintOS(ConstraintStr);
+ SmallVector<Value *, 16> AsmArgs;
+ AsmArgs.reserve(Functions.size() * 2);
+
+ for (unsigned I = 0; I != Functions.size(); ++I)
+ createJumpTableEntry(AsmOS, ConstraintOS, AsmArgs,
+ cast<Function>(Functions[I]->getGlobal()));
+
+ // Try to emit the jump table at the end of the text segment.
+ // Jump table must come after __cfi_check in the cross-dso mode.
+ // FIXME: this magic section name seems to do the trick.
+ F->setSection(ObjectFormat == Triple::MachO
+ ? "__TEXT,__text,regular,pure_instructions"
+ : ".text.cfi");
+ // Align the whole table by entry size.
+ F->setAlignment(getJumpTableEntrySize());
+ // Skip prologue.
+ // Disabled on win32 due to https://llvm.org/bugs/show_bug.cgi?id=28641#c3.
+ // Luckily, this function does not get any prologue even without the
+ // attribute.
+ if (OS != Triple::Win32)
+ F->addFnAttr(llvm::Attribute::Naked);
+ // Thumb jump table assembly needs Thumb2. The following attribute is added by
+ // Clang for -march=armv7.
+ if (Arch == Triple::thumb)
+ F->addFnAttr("target-cpu", "cortex-a8");
+
+ BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", F);
+ IRBuilder<> IRB(BB);
+
+ SmallVector<Type *, 16> ArgTypes;
+ ArgTypes.reserve(AsmArgs.size());
+ for (const auto &Arg : AsmArgs)
+ ArgTypes.push_back(Arg->getType());
+ InlineAsm *JumpTableAsm =
+ InlineAsm::get(FunctionType::get(IRB.getVoidTy(), ArgTypes, false),
+ AsmOS.str(), ConstraintOS.str(),
+ /*hasSideEffects=*/true);
+
+ IRB.CreateCall(JumpTableAsm, AsmArgs);
+ IRB.CreateUnreachable();
+}
+
/// 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(
@@ -933,88 +927,51 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
for (unsigned I = 0; I != Functions.size(); ++I)
GlobalLayout[Functions[I]] = I * EntrySize;
- // Create a constant to hold the jump table.
+ Function *JumpTableFn =
+ Function::Create(FunctionType::get(Type::getVoidTy(M.getContext()),
+ /* IsVarArg */ false),
+ GlobalValue::PrivateLinkage, ".cfi.jumptable", &M);
ArrayType *JumpTableType =
ArrayType::get(getJumpTableEntryType(), Functions.size());
auto JumpTable =
- new GlobalVariable(M, JumpTableType,
- /*isConstant=*/true, GlobalValue::ExternalLinkage,
- nullptr, ".cfi.jumptable");
- JumpTable->setVisibility(GlobalValue::HiddenVisibility);
- lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout);
+ ConstantExpr::getPointerCast(JumpTableFn, JumpTableType->getPointerTo(0));
- std::string AsmStr;
- raw_string_ostream AsmOS(AsmStr);
+ lowerTypeTestCalls(TypeIds, JumpTable, GlobalLayout);
// Build aliases pointing to offsets into the jump table, and replace
// references to the original functions with references to the aliases.
for (unsigned I = 0; I != Functions.size(); ++I) {
Function *F = cast<Function>(Functions[I]->getGlobal());
- // Need a name for the asm label. Normally, unnamed functions get temporary
- // asm labels in TargetLoweringObjectFile but we don't have access to that
- // here.
- if (!F->hasName())
- F->setName("unnamed");
+ Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast(
+ ConstantExpr::getInBoundsGetElementPtr(
+ JumpTableType, JumpTable,
+ ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
+ ConstantInt::get(IntPtrTy, I)}),
+ F->getType());
if (LinkerSubsectionsViaSymbols || F->isDeclarationForLinker()) {
- Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast(
- ConstantExpr::getGetElementPtr(
- JumpTableType, JumpTable,
- ArrayRef<Constant *>{ConstantInt::get(IntPtrTy, 0),
- ConstantInt::get(IntPtrTy, I)}),
- F->getType());
-
- if (F->isWeakForLinker()) {
- AsmOS << ".weak " << F->getName() << "\n";
+
+ if (F->isWeakForLinker())
replaceWeakDeclarationWithJumpTablePtr(F, CombinedGlobalElemPtr);
- } else {
+ else
F->replaceAllUsesWith(CombinedGlobalElemPtr);
- }
} else {
assert(F->getType()->getAddressSpace() == 0);
- createJumpTableAlias(AsmOS, F, JumpTable, I);
-
- Function *DeclAlias =
- Function::Create(cast<FunctionType>(F->getValueType()),
- GlobalValue::ExternalLinkage, "", &M);
- // Since the alias (DeclAlias) is actually a declaration, it can not have
- // internal linkage. Compensate for that by giving it hidden visibility.
- // With this we end up with a GOT relocation against a local symbol.
- DeclAlias->setVisibility(F->hasLocalLinkage()
- ? GlobalValue::HiddenVisibility
- : F->getVisibility());
- DeclAlias->takeName(F);
- // Unnamed functions can not be added to llvm.used.
- F->setName(DeclAlias->getName() + ".cfi");
- F->replaceAllUsesWith(DeclAlias);
+ GlobalAlias *FAlias = GlobalAlias::create(F->getValueType(), 0,
+ F->getLinkage(), "",
+ CombinedGlobalElemPtr, &M);
+ FAlias->setVisibility(F->getVisibility());
+ FAlias->takeName(F);
+ if (FAlias->hasName())
+ F->setName(FAlias->getName() + ".cfi");
+ F->replaceAllUsesWith(FAlias);
}
if (!F->isDeclarationForLinker())
F->setLinkage(GlobalValue::InternalLinkage);
}
- // Try to emit the jump table at the end of the text segment.
- // Jump table must come after __cfi_check in the cross-dso mode.
- // FIXME: this magic section name seems to do the trick.
- AsmOS << ".section " << (ObjectFormat == Triple::MachO
- ? "__TEXT,__text,regular,pure_instructions"
- : ".text.cfi, \"ax\", %progbits")
- << "\n";
- // Align the whole table by entry size.
- AsmOS << ".balign " << EntrySize << "\n";
- if (Arch == Triple::thumb)
- AsmOS << ".thumb_func\n";
- AsmOS << JumpTable->getName() << ":\n";
- for (unsigned I = 0; I != Functions.size(); ++I)
- createJumpTableEntry(AsmOS, cast<Function>(Functions[I]->getGlobal()), I);
-
- M.appendModuleInlineAsm(AsmOS.str());
-
- SmallVector<GlobalValue *, 16> Used;
- Used.reserve(Functions.size());
- for (auto *F : Functions)
- Used.push_back(F->getGlobal());
- appendToUsed(M, Used);
+ createJumpTable(JumpTableFn, Functions);
}
/// Assign a dummy layout using an incrementing counter, tag each function
@@ -1126,6 +1083,7 @@ LowerTypeTestsModule::LowerTypeTestsModule(Module &M) : M(M) {
Triple TargetTriple(M.getTargetTriple());
LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX();
Arch = TargetTriple.getArch();
+ OS = TargetTriple.getOS();
ObjectFormat = TargetTriple.getObjectFormat();
}
OpenPOWER on IntegriCloud