diff options
Diffstat (limited to 'llvm/lib/Transforms')
| -rw-r--r-- | llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 222 |
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(); } |

