[cfi] Avoid branch veneers in jump tables when possible.

Summary:
When jumptable encoding does not match target code encoding (arm vs
thumb), a veneer is inserted by the linker. We can not avoid this
in all cases, because entries within one jumptable must have the same
encoding, but we can make it less common by selecting the jumptable
encoding to match the majority of its targets.

This change only covers FullLTO, and not ThinLTO.

Reviewers: pcc

Subscribers: aemerson, mehdi_amini, javed.absar, kristof.beyls, llvm-commits, hiraditya

Differential Revision: https://reviews.llvm.org/D37171

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@312054 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evgeniy Stepanov 2017-08-29 22:40:19 +00:00
parent 7cf6af50d7
commit aa1a72db63
2 changed files with 97 additions and 8 deletions

View File

@ -329,6 +329,7 @@ class LowerTypeTestsModule {
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,
@ -983,15 +984,16 @@ unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
// 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");
@ -1078,6 +1080,46 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr(
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;
@ -1085,8 +1127,10 @@ void LowerTypeTestsModule::createJumpTable(
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.
@ -1103,10 +1147,14 @@ void LowerTypeTestsModule::createJumpTable(
// 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);

View File

@ -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" }