unsigned getJumpTableEntrySize();
Type *getJumpTableEntryType();
void createJumpTableEntry(raw_ostream &AsmOS, raw_ostream &ConstraintOS,
+ Triple::ArchType JumpTableArch,
SmallVectorImpl<Value *> &AsmArgs, Function *Dest);
void verifyTypeMDNode(GlobalObject *GO, MDNode *Type);
void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
// constraints and arguments to AsmOS, ConstraintOS and AsmArgs.
void LowerTypeTestsModule::createJumpTableEntry(
raw_ostream &AsmOS, raw_ostream &ConstraintOS,
- SmallVectorImpl<Value *> &AsmArgs, Function *Dest) {
+ Triple::ArchType JumpTableArch, SmallVectorImpl<Value *> &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");
PlaceholderFn->eraseFromParent();
}
+static bool isThumbFunction(Function *F, Triple::ArchType ModuleArch) {
+ Attribute TFAttr = F->getFnAttribute("target-features");
+ if (!TFAttr.hasAttribute(Attribute::None)) {
+ SmallVector<StringRef, 6> 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<GlobalTypeMember *> 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<Function>(GTM->getGlobal());
+ ++(isThumbFunction(F, ModuleArch) ? ThumbCount : ArmCount);
+ }
+
+ return ArmCount > ThumbCount ? Triple::arm : Triple::thumb;
+}
+
void LowerTypeTestsModule::createJumpTable(
Function *F, ArrayRef<GlobalTypeMember *> Functions) {
std::string AsmStr, ConstraintStr;
SmallVector<Value *, 16> 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<Function>(Functions[I]->getGlobal()));
// Try to emit the jump table at the end of the text segment.
// 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);
--- /dev/null
+; 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" }