mirror of
https://github.com/RPCS3/llvm.git
synced 2025-01-09 13:41:47 +00:00
[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:
parent
7cf6af50d7
commit
aa1a72db63
@ -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);
|
||||
|
41
test/Transforms/LowerTypeTests/function-arm-thumb.ll
Normal file
41
test/Transforms/LowerTypeTests/function-arm-thumb.ll
Normal 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" }
|
Loading…
Reference in New Issue
Block a user