Index: lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- lib/Transforms/IPO/LowerTypeTests.cpp +++ 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 @@ bool LinkerSubsectionsViaSymbols; Triple::ArchType Arch; + Triple::OSType OS; Triple::ObjectFormatType ObjectFormat; IntegerType *Int1Ty = Type::getInt1Ty(M.getContext()); @@ -260,7 +261,6 @@ std::vector ByteArrayInfos; - Mangler Mang; Function *WeakInitializerFn = nullptr; BitSetInfo @@ -281,9 +281,8 @@ ArrayRef 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 &AsmArgs, Function *Dest); void verifyTypeMDNode(GlobalObject *GO, MDNode *Type); void buildBitSetsFromFunctions(ArrayRef TypeIds, ArrayRef Functions); @@ -299,6 +298,8 @@ void findGlobalVariableUsersOf(Constant *C, SmallSetVector &Out); + void createJumpTable(Function *F, ArrayRef Functions); + public: LowerTypeTestsModule(Module &M); bool lower(); @@ -691,80 +692,27 @@ } } -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 &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 @@ PlaceholderFn->eraseFromParent(); } +void LowerTypeTestsModule::createJumpTable( + Function *F, ArrayRef Functions) { + std::string AsmStr, ConstraintStr; + raw_string_ostream AsmOS(AsmStr), ConstraintOS(ConstraintStr); + SmallVector AsmArgs; + AsmArgs.reserve(Functions.size() * 2); + + for (unsigned I = 0; I != Functions.size(); ++I) + createJumpTableEntry(AsmOS, ConstraintOS, AsmArgs, + cast(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 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 @@ 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(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{ConstantInt::get(IntPtrTy, 0), + ConstantInt::get(IntPtrTy, I)}), + F->getType()); if (LinkerSubsectionsViaSymbols || F->isDeclarationForLinker()) { - Constant *CombinedGlobalElemPtr = ConstantExpr::getBitCast( - ConstantExpr::getGetElementPtr( - JumpTableType, JumpTable, - ArrayRef{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(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(Functions[I]->getGlobal()), I); - - M.appendModuleInlineAsm(AsmOS.str()); - - SmallVector 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 @@ Triple TargetTriple(M.getTargetTriple()); LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX(); Arch = TargetTriple.getArch(); + OS = TargetTriple.getOS(); ObjectFormat = TargetTriple.getObjectFormat(); } Index: test/Transforms/LowerTypeTests/function-disjoint.ll =================================================================== --- test/Transforms/LowerTypeTests/function-disjoint.ll +++ test/Transforms/LowerTypeTests/function-disjoint.ll @@ -5,25 +5,8 @@ target datalayout = "e-p:64:64" -; X64: module asm "f = .cfi.jumptable + 0" - -; X64: module asm ".cfi.jumptable:" -; X64-NEXT: module asm "jmp f.cfi@plt" -; X64-NEXT: module asm "int3" -; X64-NEXT: module asm "int3" -; X64-NEXT: module asm "int3" - -; X64: module asm "g = .cfi.jumptable.1 + 0" - -; X64: module asm ".cfi.jumptable.1:" -; X64-NEXT: module asm "jmp g.cfi@plt" -; X64-NEXT: module asm "int3" -; X64-NEXT: module asm "int3" -; X64-NEXT: module asm "int3" - - -; X64: @.cfi.jumptable = external hidden constant [1 x [8 x i8]] -; X64: @.cfi.jumptable.1 = external hidden constant [1 x [8 x i8]] +; X64: @f = alias void (), void ()* @[[JT0:.*]] +; X64: @g = alias void (), void ()* @[[JT1:.*]] ; WASM32: private constant [0 x i8] zeroinitializer @0 = private unnamed_addr constant [2 x void ()*] [void ()* @f, void ()* @g], align 16 @@ -46,18 +29,21 @@ declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone define i1 @foo(i8* %p) { - ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable to i64) + ; X64: icmp eq i64 {{.*}}, ptrtoint (void ()* @[[JT0]] to i64) ; WASM32: icmp eq i64 {{.*}}, 1 %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") - ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable.1 to i64) + ; X64: icmp eq i64 {{.*}}, ptrtoint (void ()* @[[JT1]] to i64) ; WASM32: icmp eq i64 {{.*}}, 2 %y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2") %z = add i1 %x, %y ret i1 %z } -; X64: declare void @f() -; X64: declare void @g() +; X64: define private void @[[JT0]]() #{{.*}} section ".text.cfi" align 8 { +; X64: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(void ()* @f.cfi) + +; X64: define private void @[[JT1]]() #{{.*}} section ".text.cfi" align 8 { +; X64: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(void ()* @g.cfi) ; WASM32: ![[I0]] = !{i64 1} ; WASM32: ![[I1]] = !{i64 2} \ No newline at end of file Index: test/Transforms/LowerTypeTests/function-ext.ll =================================================================== --- test/Transforms/LowerTypeTests/function-ext.ll +++ test/Transforms/LowerTypeTests/function-ext.ll @@ -4,18 +4,13 @@ ; Tests that we correctly handle external references, including the case where ; all functions in a bitset are external references. -; X64: module asm ".cfi.jumptable:" -; X64-NEXT: module asm "jmp foo@plt" -; X64-NOT: module asm "jmp {{.*}}@plt" - -; X64: @.cfi.jumptable = external hidden constant [1 x [8 x i8]] ; WASM32: private constant [0 x i8] zeroinitializer ; WASM32: declare !type !{{[0-9]+}} void @foo() declare !type !0 void @foo() define i1 @bar(i8* %ptr) { - ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x [8 x i8]]* @.cfi.jumptable to i64) + ; X64: icmp eq i64 {{.*}}, ptrtoint (void ()* @[[JT:.*]] to i64) ; WASM32: sub i64 {{.*}}, 0 ; WASM32: icmp ult i64 {{.*}}, 1 %p = call i1 @llvm.type.test(i8* %ptr, metadata !"void") @@ -27,3 +22,6 @@ !0 = !{i64 0, !"void"} ; WASM-NOT: !{i64 0} ; WASM-NOT: !{i64 1} + +; X64: define private void @[[JT]]() #{{.*}} section ".text.cfi" align {{.*}} { +; X64: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(void ()* @foo) Index: test/Transforms/LowerTypeTests/function-weak.ll =================================================================== --- test/Transforms/LowerTypeTests/function-weak.ll +++ test/Transforms/LowerTypeTests/function-weak.ll @@ -1,13 +1,11 @@ -; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck %s -; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s -; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck %s -; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s +; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefixes=CHECK,X86 %s +; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefixes=CHECK,X86 %s +; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck --check-prefixes=CHECK,ARM %s +; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefixes=CHECK,ARM %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" -; CHECK: module asm ".weak f" - ; CHECK: @x = global void ()* null, align 8 @x = global void ()* @f, align 8 @@ -25,7 +23,6 @@ ; CHECK: @s = global { void ()*, void ()*, i32 } zeroinitializer, align 8 @s = global { void ()*, void ()*, i32 } { void ()* @f, void ()* @f, i32 42 }, align 8 -; CHECK: @.cfi.jumptable = external hidden constant [1 x [{{.*}} x i8]] ; CHECK: @llvm.global_ctors = appending global {{.*}}{ i32 0, void ()* @__cfi_global_var_init ; CHECK: declare !type !0 extern_weak void @f() @@ -34,14 +31,14 @@ ; CHECK: define zeroext i1 @check_f() define zeroext i1 @check_f() { entry: -; CHECK: ret i1 icmp ne (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), void ()* null) +; CHECK: ret i1 icmp ne (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT:.*]], void ()* null), void ()* null) ret i1 icmp ne (void ()* @f, void ()* null) } ; CHECK: define void @call_f() { define void @call_f() { entry: -; CHECK: call void select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null)() +; CHECK: call void select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null)() call void @f() ret void } @@ -53,15 +50,17 @@ ret i1 %x } +; X86: define private void @[[JT]]() #{{.*}} section ".text.cfi" align 8 { +; ARM: define private void @[[JT]]() #{{.*}} section ".text.cfi" align 4 { + ; CHECK: define internal void @__cfi_global_var_init() section ".text.startup" { ; CHECK-NEXT: entry: -; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8 -; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8 -; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), void ()** @x3, align 8 -; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), void ()** @x2, align 8 -; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* bitcast ({{.*}}@.cfi.jumptable to void ()*), void ()* null), void ()** @x, align 8 +; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8 +; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8 +; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x3, align 8 +; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x2, align 8 +; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x, align 8 ; CHECK-NEXT: ret void ; CHECK-NEXT: } - !0 = !{i32 0, !"typeid1"} Index: test/Transforms/LowerTypeTests/function.ll =================================================================== --- test/Transforms/LowerTypeTests/function.ll +++ test/Transforms/LowerTypeTests/function.ll @@ -1,5 +1,7 @@ -; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,NATIVE %s -; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,NATIVE %s +; RUN: opt -S -lowertypetests -mtriple=i686-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,X86-LINUX,NATIVE %s +; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefixes=X86,X86-LINUX,NATIVE %s +; RUN: opt -S -lowertypetests -mtriple=i686-pc-win32 < %s | FileCheck --check-prefixes=X86,X86-WIN32,NATIVE %s +; RUN: opt -S -lowertypetests -mtriple=x86_64-pc-win32 < %s | FileCheck --check-prefixes=X86,X86-WIN32,NATIVE %s ; RUN: opt -S -lowertypetests -mtriple=arm-unknown-linux-gnu < %s | FileCheck --check-prefixes=ARM,NATIVE %s ; RUN: opt -S -lowertypetests -mtriple=thumb-unknown-linux-gnu < %s | FileCheck --check-prefixes=THUMB,NATIVE %s ; RUN: opt -S -lowertypetests -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck --check-prefixes=ARM,NATIVE %s @@ -9,61 +11,18 @@ target datalayout = "e-p:64:64" -; X86: module asm ".globl f" -; X86-NEXT: module asm ".type f, function" -; X86-NEXT: module asm "f = .cfi.jumptable + 0" -; X86-NEXT: module asm ".size f, 8" -; X86-NEXT: module asm ".type g, function" -; X86-NEXT: module asm "g = .cfi.jumptable + 8" -; X86-NEXT: module asm ".size g, 8" -; X86-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits" -; X86-NEXT: module asm ".balign 8" -; X86-NEXT: module asm ".cfi.jumptable:" -; X86-NEXT: module asm "jmp f.cfi@plt" -; X86-NEXT: module asm "int3" -; X86-NEXT: module asm "int3" -; X86-NEXT: module asm "int3" -; X86-NEXT: module asm "jmp g.cfi@plt" -; X86-NEXT: module asm "int3" -; X86-NEXT: module asm "int3" -; X86-NEXT: module asm "int3" - -; ARM: module asm ".globl f" -; ARM-NEXT: module asm ".type f, function" -; ARM-NEXT: module asm "f = .cfi.jumptable + 0" -; ARM-NEXT: module asm ".size f, 4" -; ARM-NEXT: module asm ".type g, function" -; ARM-NEXT: module asm "g = .cfi.jumptable + 4" -; ARM-NEXT: module asm ".size g, 4" -; ARM-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits" -; ARM-NEXT: module asm ".balign 4" -; ARM-NEXT: module asm ".cfi.jumptable:" -; ARM-NEXT: module asm "b f.cfi" -; ARM-NEXT: module asm "b g.cfi" - -; THUMB: module asm ".globl f" -; THUMB-NEXT: module asm ".type f, function" -; THUMB-NEXT: module asm ".thumb_set f, .cfi.jumptable + 0" -; THUMB-NEXT: module asm ".size f, 4" -; THUMB-NEXT: module asm ".type g, function" -; THUMB-NEXT: module asm ".thumb_set g, .cfi.jumptable + 4" -; THUMB-NEXT: module asm ".size g, 4" -; THUMB-NEXT: module asm ".section .text.cfi, \22ax\22, %progbits" -; THUMB-NEXT: module asm ".balign 4" -; THUMB-NEXT: module asm ".thumb_func" -; THUMB-NEXT: module asm ".cfi.jumptable:" -; THUMB-NEXT: module asm "b.w f.cfi" -; THUMB-NEXT: module asm "b.w g.cfi" - - -; X86: @.cfi.jumptable = external hidden constant [2 x [8 x i8]] -; ARM: @.cfi.jumptable = external hidden constant [2 x [4 x i8]] -; THUMB: @.cfi.jumptable = external hidden constant [2 x [4 x i8]] -; WASM32: private constant [0 x i8] zeroinitializer +; NATIVE: @0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16 @0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16 -; NATIVE: @llvm.used = appending global [2 x i8*] [i8* bitcast (void ()* @f.cfi to i8*), i8* bitcast (void ()* @g.cfi to i8*)], section "llvm.metadata" +; NATIVE: private constant [0 x i8] zeroinitializer +; WASM32: private constant [0 x i8] zeroinitializer + +; NATIVE: @f = alias void (), void ()* @[[JT:.*]] + +; X86: @g = internal alias void (), bitcast ([8 x i8]* getelementptr inbounds ([2 x [8 x i8]], [2 x [8 x i8]]* bitcast (void ()* @[[JT]] to [2 x [8 x i8]]*), i64 0, i64 1) to void ()*) +; ARM: @g = internal alias void (), bitcast ([4 x i8]* getelementptr inbounds ([2 x [4 x i8]], [2 x [4 x i8]]* bitcast (void ()* @[[JT]] to [2 x [4 x i8]]*), i64 0, i64 1) to void ()*) +; THUMB: @g = internal alias void (), bitcast ([4 x i8]* getelementptr inbounds ([2 x [4 x i8]], [2 x [4 x i8]]* bitcast (void ()* @[[JT]] to [2 x [4 x i8]]*), i64 0, i64 1) to void ()*) ; NATIVE: define internal void @f.cfi() ; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]] @@ -82,16 +41,38 @@ declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone define i1 @foo(i8* %p) { - ; X86: sub i64 {{.*}}, ptrtoint ([2 x [8 x i8]]* @.cfi.jumptable to i64) - ; ARM: sub i64 {{.*}}, ptrtoint ([2 x [4 x i8]]* @.cfi.jumptable to i64) + ; NATIVE: sub i64 {{.*}}, ptrtoint (void ()* @[[JT]] to i64) ; WASM32: sub i64 {{.*}}, 1 ; WASM32: icmp ult i64 {{.*}}, 2 %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") ret i1 %x } -; NATIVE: declare void @f() -; NATIVE: declare hidden void @g() +; X86-LINUX: define private void @[[JT]]() #[[ATTR:.*]] section ".text.cfi" align 8 { +; X86-WIN32: define private void @[[JT]]() section ".text.cfi" align 8 { +; ARM: define private void @[[JT]]() #[[ATTR:.*]] section ".text.cfi" align 4 { +; THUMB: define private void @[[JT]]() #[[ATTR:.*]] section ".text.cfi" align 4 { + +; X86: jmp ${0:c}@plt +; X86-SAME: int3 +; X86-SAME: int3 +; X86-SAME: int3 +; X86-SAME: jmp ${1:c}@plt +; X86-SAME: int3 +; X86-SAME: int3 +; X86-SAME: int3 + +; ARM: b $0 +; ARM-SAME: b $1 + +; THUMB: b.w $0 +; THUMB-SAME: b.w $1 + +; NATIVE-SAME: "s,s"(void ()* @f.cfi, void ()* @g.cfi) + +; X86-LINUX: attributes #[[ATTR]] = { {{.*}}naked +; ARM: attributes #[[ATTR]] = { {{.*}}naked +; THUMB: attributes #[[ATTR]] = { {{.*}}naked{{.*}}"target-cpu"="cortex-a8" ; WASM32: ![[I0]] = !{i64 1} ; WASM32: ![[I1]] = !{i64 2} Index: test/Transforms/LowerTypeTests/section.ll =================================================================== --- test/Transforms/LowerTypeTests/section.ll +++ test/Transforms/LowerTypeTests/section.ll @@ -5,10 +5,7 @@ target triple = "x86_64-unknown-linux-gnu" -; CHECK: module asm ".section .text.cfi, -; CHECK: module asm ".cfi.jumptable:" -; CHECK-NEXT: module asm "jmp f.cfi@plt" - +; CHECK: @f = alias void (), void ()* @[[JT:.*]] ; CHECK: define internal void @f.cfi() section "xxx" define void @f() section "xxx" !type !0 { @@ -22,6 +19,8 @@ ret i1 %0 } +; CHECK: define private void @[[JT]]() #{{.*}} section ".text.cfi" align {{.*}} { + declare i1 @llvm.type.test(i8*, metadata) nounwind readnone !0 = !{i64 0, !"_ZTSFvE"}