Index: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp @@ -329,6 +329,7 @@ unsigned getJumpTableEntrySize(); Type *getJumpTableEntryType(); void createJumpTableEntry(raw_ostream &AsmOS, raw_ostream &ConstraintOS, + Triple::ArchType JumpTableArch, SmallVectorImpl &AsmArgs, Function *Dest); void verifyTypeMDNode(GlobalObject *GO, MDNode *Type); void buildBitSetsFromFunctions(ArrayRef TypeIds, @@ -983,15 +984,16 @@ // constraints and arguments to AsmOS, ConstraintOS and AsmArgs. void LowerTypeTestsModule::createJumpTableEntry( raw_ostream &AsmOS, raw_ostream &ConstraintOS, - SmallVectorImpl &AsmArgs, Function *Dest) { + Triple::ArchType JumpTableArch, SmallVectorImpl &AsmArgs, + Function *Dest) { unsigned ArgIndex = AsmArgs.size(); - if (Arch == Triple::x86 || Arch == Triple::x86_64) { + if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) { AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n"; AsmOS << "int3\nint3\nint3\n"; - } else if (Arch == Triple::arm || Arch == Triple::aarch64) { + } else if (JumpTableArch == Triple::arm || JumpTableArch == Triple::aarch64) { AsmOS << "b $" << ArgIndex << "\n"; - } else if (Arch == Triple::thumb) { + } else if (JumpTableArch == Triple::thumb) { AsmOS << "b.w $" << ArgIndex << "\n"; } else { report_fatal_error("Unsupported architecture for jump tables"); @@ -1078,6 +1080,46 @@ PlaceholderFn->eraseFromParent(); } +static bool isThumbFunction(Function *F, Triple::ArchType ModuleArch) { + Attribute TFAttr = F->getFnAttribute("target-features"); + if (!TFAttr.hasAttribute(Attribute::None)) { + SmallVector Features; + TFAttr.getValueAsString().split(Features, ','); + for (StringRef Feature : Features) { + if (Feature == "-thumb-mode") + return false; + else if (Feature == "+thumb-mode") + return true; + } + } + + return ModuleArch == Triple::thumb; +} + +// Each jump table must be either ARM or Thumb as a whole for the bit-test math +// to work. Pick one that matches the majority of members to minimize interop +// veneers inserted by the linker. +static Triple::ArchType +selectJumpTableArmEncoding(ArrayRef Functions, + Triple::ArchType ModuleArch) { + if (ModuleArch != Triple::arm && ModuleArch != Triple::thumb) + return ModuleArch; + + unsigned ArmCount = 0, ThumbCount = 0; + for (const auto GTM : Functions) { + if (!GTM->isDefinition()) { + // PLT stubs are always ARM. + ++ArmCount; + continue; + } + + Function *F = cast(GTM->getGlobal()); + ++(isThumbFunction(F, ModuleArch) ? ThumbCount : ArmCount); + } + + return ArmCount > ThumbCount ? Triple::arm : Triple::thumb; +} + void LowerTypeTestsModule::createJumpTable( Function *F, ArrayRef Functions) { std::string AsmStr, ConstraintStr; @@ -1085,8 +1127,10 @@ SmallVector AsmArgs; AsmArgs.reserve(Functions.size() * 2); + Triple::ArchType JumpTableArch = selectJumpTableArmEncoding(Functions, Arch); + for (unsigned I = 0; I != Functions.size(); ++I) - createJumpTableEntry(AsmOS, ConstraintOS, AsmArgs, + createJumpTableEntry(AsmOS, ConstraintOS, JumpTableArch, AsmArgs, cast(Functions[I]->getGlobal())); // Try to emit the jump table at the end of the text segment. @@ -1103,10 +1147,14 @@ // 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) + if (JumpTableArch == Triple::arm) + F->addFnAttr("target-features", "-thumb-mode"); + if (JumpTableArch == Triple::thumb) { + F->addFnAttr("target-features", "+thumb-mode"); + // Thumb jump table assembly needs Thumb2. The following attribute is added + // by Clang for -march=armv7. F->addFnAttr("target-cpu", "cortex-a8"); + } BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", F); IRBuilder<> IRB(BB); Index: llvm/trunk/test/Transforms/LowerTypeTests/function-arm-thumb.ll =================================================================== --- llvm/trunk/test/Transforms/LowerTypeTests/function-arm-thumb.ll +++ llvm/trunk/test/Transforms/LowerTypeTests/function-arm-thumb.ll @@ -0,0 +1,41 @@ +; RUN: opt -S -mtriple=arm-unknown-linux-gnu -lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/use-typeid1-typeid2.yaml -lowertypetests-write-summary=%t < %s | FileCheck %s + +target datalayout = "e-p:64:64" + +define void @f1() "target-features"="+thumb-mode" !type !0 { + ret void +} + +define void @g1() "target-features"="-thumb-mode" !type !0 { + ret void +} + +define void @f2() "target-features"="+thumb-mode" !type !1 { + ret void +} + +define void @g2() "target-features"="-thumb-mode" !type !1 { + ret void +} + +define void @h2() "target-features"="-thumb-mode" !type !1 { + ret void +} + +!0 = !{i32 0, !"typeid1"} +!1 = !{i32 0, !"typeid2"} + +; CHECK: define private void {{.*}} #[[AT:.*]] section ".text.cfi" align 4 { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void asm sideeffect "b.w $0\0Ab.w $1\0A", "s,s"(void ()* @f1.cfi, void ()* @g1.cfi) +; CHECK-NEXT: unreachable +; CHECK-NEXT: } + +; CHECK: define private void {{.*}} #[[AA:.*]] section ".text.cfi" align 4 { +; CHECK-NEXT: entry: +; CHECK-NEXT: call void asm sideeffect "b $0\0Ab $1\0Ab $2\0A", "s,s,s"(void ()* @f2.cfi, void ()* @g2.cfi, void ()* @h2.cfi) +; CHECK-NEXT: unreachable +; CHECK-NEXT: } + +; CHECK-DAG: attributes #[[AA]] = { naked "target-features"="-thumb-mode" } +; CHECK-DAG: attributes #[[AT]] = { naked "target-cpu"="cortex-a8" "target-features"="+thumb-mode" }