Skip to content

Commit c7ea01b

Browse files
authored
LowerTypeTests: Switch to emitting one inline asm call per jump table entry.
With the previous approach of emitting one inline asm call for all jump table entries we would encounter SelectionDAG's limit on the number of operands per node (65536) when the number of jump table entries exceeded that number. Fix the problem by switching to one inline asm per jump table entry so that each DAG node only needs one operand. Reviewers: fmayer, vitalybuka Reviewed By: fmayer Pull Request: #136265
1 parent 2b44eb9 commit c7ea01b

File tree

8 files changed

+83
-80
lines changed

8 files changed

+83
-80
lines changed

llvm/lib/Transforms/IPO/LowerTypeTests.cpp

Lines changed: 40 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -441,10 +441,6 @@ class LowerTypeTestsModule {
441441
// Cache variable used by hasBranchTargetEnforcement().
442442
int HasBranchTargetEnforcement = -1;
443443

444-
// The jump table type we ended up deciding on. (Usually the same as
445-
// Arch, except that 'arm' and 'thumb' are often interchangeable.)
446-
Triple::ArchType JumpTableArch = Triple::UnknownArch;
447-
448444
IntegerType *Int1Ty = Type::getInt1Ty(M.getContext());
449445
IntegerType *Int8Ty = Type::getInt8Ty(M.getContext());
450446
PointerType *PtrTy = PointerType::getUnqual(M.getContext());
@@ -525,11 +521,8 @@ class LowerTypeTestsModule {
525521
Triple::ArchType
526522
selectJumpTableArmEncoding(ArrayRef<GlobalTypeMember *> Functions);
527523
bool hasBranchTargetEnforcement();
528-
unsigned getJumpTableEntrySize();
529-
Type *getJumpTableEntryType();
530-
void createJumpTableEntry(raw_ostream &AsmOS, raw_ostream &ConstraintOS,
531-
Triple::ArchType JumpTableArch,
532-
SmallVectorImpl<Value *> &AsmArgs, Function *Dest);
524+
unsigned getJumpTableEntrySize(Triple::ArchType JumpTableArch);
525+
InlineAsm *createJumpTableEntryAsm(Triple::ArchType JumpTableArch);
533526
void verifyTypeMDNode(GlobalObject *GO, MDNode *Type);
534527
void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
535528
ArrayRef<GlobalTypeMember *> Functions);
@@ -548,7 +541,8 @@ class LowerTypeTestsModule {
548541
void findGlobalVariableUsersOf(Constant *C,
549542
SmallSetVector<GlobalVariable *, 8> &Out);
550543

551-
void createJumpTable(Function *F, ArrayRef<GlobalTypeMember *> Functions);
544+
void createJumpTable(Function *F, ArrayRef<GlobalTypeMember *> Functions,
545+
Triple::ArchType JumpTableArch);
552546

553547
/// replaceCfiUses - Go through the uses list for this definition
554548
/// and make each use point to "V" instead of "this" when the use is outside
@@ -1245,7 +1239,8 @@ bool LowerTypeTestsModule::hasBranchTargetEnforcement() {
12451239
return HasBranchTargetEnforcement;
12461240
}
12471241

1248-
unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
1242+
unsigned
1243+
LowerTypeTestsModule::getJumpTableEntrySize(Triple::ArchType JumpTableArch) {
12491244
switch (JumpTableArch) {
12501245
case Triple::x86:
12511246
case Triple::x86_64:
@@ -1278,33 +1273,32 @@ unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
12781273
}
12791274
}
12801275

1281-
// Create a jump table entry for the target. This consists of an instruction
1282-
// sequence containing a relative branch to Dest. Appends inline asm text,
1283-
// constraints and arguments to AsmOS, ConstraintOS and AsmArgs.
1284-
void LowerTypeTestsModule::createJumpTableEntry(
1285-
raw_ostream &AsmOS, raw_ostream &ConstraintOS,
1286-
Triple::ArchType JumpTableArch, SmallVectorImpl<Value *> &AsmArgs,
1287-
Function *Dest) {
1288-
unsigned ArgIndex = AsmArgs.size();
1276+
// Create an inline asm constant representing a jump table entry for the target.
1277+
// This consists of an instruction sequence containing a relative branch to
1278+
// Dest.
1279+
InlineAsm *
1280+
LowerTypeTestsModule::createJumpTableEntryAsm(Triple::ArchType JumpTableArch) {
1281+
std::string Asm;
1282+
raw_string_ostream AsmOS(Asm);
12891283

12901284
if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) {
12911285
bool Endbr = false;
12921286
if (const auto *MD = mdconst::extract_or_null<ConstantInt>(
1293-
Dest->getParent()->getModuleFlag("cf-protection-branch")))
1287+
M.getModuleFlag("cf-protection-branch")))
12941288
Endbr = !MD->isZero();
12951289
if (Endbr)
12961290
AsmOS << (JumpTableArch == Triple::x86 ? "endbr32\n" : "endbr64\n");
1297-
AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n";
1291+
AsmOS << "jmp ${0:c}@plt\n";
12981292
if (Endbr)
12991293
AsmOS << ".balign 16, 0xcc\n";
13001294
else
13011295
AsmOS << "int3\nint3\nint3\n";
13021296
} else if (JumpTableArch == Triple::arm) {
1303-
AsmOS << "b $" << ArgIndex << "\n";
1297+
AsmOS << "b $0\n";
13041298
} else if (JumpTableArch == Triple::aarch64) {
13051299
if (hasBranchTargetEnforcement())
13061300
AsmOS << "bti c\n";
1307-
AsmOS << "b $" << ArgIndex << "\n";
1301+
AsmOS << "b $0\n";
13081302
} else if (JumpTableArch == Triple::thumb) {
13091303
if (!CanUseThumbBWJumpTable) {
13101304
// In Armv6-M, this sequence will generate a branch without corrupting
@@ -1328,28 +1322,26 @@ void LowerTypeTestsModule::createJumpTableEntry(
13281322
<< "str r0, [sp, #4]\n"
13291323
<< "pop {r0,pc}\n"
13301324
<< ".balign 4\n"
1331-
<< "1: .word $" << ArgIndex << " - (0b + 4)\n";
1325+
<< "1: .word $0 - (0b + 4)\n";
13321326
} else {
13331327
if (hasBranchTargetEnforcement())
13341328
AsmOS << "bti\n";
1335-
AsmOS << "b.w $" << ArgIndex << "\n";
1329+
AsmOS << "b.w $0\n";
13361330
}
13371331
} else if (JumpTableArch == Triple::riscv32 ||
13381332
JumpTableArch == Triple::riscv64) {
1339-
AsmOS << "tail $" << ArgIndex << "@plt\n";
1333+
AsmOS << "tail $0@plt\n";
13401334
} else if (JumpTableArch == Triple::loongarch64) {
1341-
AsmOS << "pcalau12i $$t0, %pc_hi20($" << ArgIndex << ")\n"
1342-
<< "jirl $$r0, $$t0, %pc_lo12($" << ArgIndex << ")\n";
1335+
AsmOS << "pcalau12i $$t0, %pc_hi20($0)\n"
1336+
<< "jirl $$r0, $$t0, %pc_lo12($0)\n";
13431337
} else {
13441338
report_fatal_error("Unsupported architecture for jump tables");
13451339
}
13461340

1347-
ConstraintOS << (ArgIndex > 0 ? ",s" : "s");
1348-
AsmArgs.push_back(Dest);
1349-
}
1350-
1351-
Type *LowerTypeTestsModule::getJumpTableEntryType() {
1352-
return ArrayType::get(Int8Ty, getJumpTableEntrySize());
1341+
return InlineAsm::get(
1342+
FunctionType::get(Type::getVoidTy(M.getContext()), PtrTy, false),
1343+
AsmOS.str(), "s",
1344+
/*hasSideEffects=*/true);
13531345
}
13541346

13551347
/// Given a disjoint set of type identifiers and functions, build the bit sets
@@ -1498,12 +1490,18 @@ Triple::ArchType LowerTypeTestsModule::selectJumpTableArmEncoding(
14981490
}
14991491

15001492
void LowerTypeTestsModule::createJumpTable(
1501-
Function *F, ArrayRef<GlobalTypeMember *> Functions) {
1493+
Function *F, ArrayRef<GlobalTypeMember *> Functions,
1494+
Triple::ArchType JumpTableArch) {
15021495
std::string AsmStr, ConstraintStr;
15031496
raw_string_ostream AsmOS(AsmStr), ConstraintOS(ConstraintStr);
15041497
SmallVector<Value *, 16> AsmArgs;
15051498
AsmArgs.reserve(Functions.size() * 2);
15061499

1500+
BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", F);
1501+
IRBuilder<> IRB(BB);
1502+
1503+
InlineAsm *JumpTableAsm = createJumpTableEntryAsm(JumpTableArch);
1504+
15071505
// Check if all entries have the NoUnwind attribute.
15081506
// If all entries have it, we can safely mark the
15091507
// cfi.jumptable as NoUnwind, otherwise, direct calls
@@ -1514,12 +1512,12 @@ void LowerTypeTestsModule::createJumpTable(
15141512
->hasFnAttribute(llvm::Attribute::NoUnwind)) {
15151513
areAllEntriesNounwind = false;
15161514
}
1517-
createJumpTableEntry(AsmOS, ConstraintOS, JumpTableArch, AsmArgs,
1518-
cast<Function>(GTM->getGlobal()));
1515+
IRB.CreateCall(JumpTableAsm, GTM->getGlobal());
15191516
}
1517+
IRB.CreateUnreachable();
15201518

15211519
// Align the whole table by entry size.
1522-
F->setAlignment(Align(getJumpTableEntrySize()));
1520+
F->setAlignment(Align(getJumpTableEntrySize(JumpTableArch)));
15231521
// Skip prologue.
15241522
// Disabled on win32 due to https://llvm.org/bugs/show_bug.cgi?id=28641#c3.
15251523
// Luckily, this function does not get any prologue even without the
@@ -1568,21 +1566,6 @@ void LowerTypeTestsModule::createJumpTable(
15681566

15691567
// Make sure we do not inline any calls to the cfi.jumptable.
15701568
F->addFnAttr(Attribute::NoInline);
1571-
1572-
BasicBlock *BB = BasicBlock::Create(M.getContext(), "entry", F);
1573-
IRBuilder<> IRB(BB);
1574-
1575-
SmallVector<Type *, 16> ArgTypes;
1576-
ArgTypes.reserve(AsmArgs.size());
1577-
for (const auto &Arg : AsmArgs)
1578-
ArgTypes.push_back(Arg->getType());
1579-
InlineAsm *JumpTableAsm =
1580-
InlineAsm::get(FunctionType::get(IRB.getVoidTy(), ArgTypes, false),
1581-
AsmOS.str(), ConstraintOS.str(),
1582-
/*hasSideEffects=*/true);
1583-
1584-
IRB.CreateCall(JumpTableAsm, AsmArgs);
1585-
IRB.CreateUnreachable();
15861569
}
15871570

15881571
/// Given a disjoint set of type identifiers and functions, build a jump table
@@ -1669,11 +1652,11 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
16691652

16701653
// Decide on the jump table encoding, so that we know how big the
16711654
// entries will be.
1672-
JumpTableArch = selectJumpTableArmEncoding(Functions);
1655+
Triple::ArchType JumpTableArch = selectJumpTableArmEncoding(Functions);
16731656

16741657
// Build a simple layout based on the regular layout of jump tables.
16751658
DenseMap<GlobalTypeMember *, uint64_t> GlobalLayout;
1676-
unsigned EntrySize = getJumpTableEntrySize();
1659+
unsigned EntrySize = getJumpTableEntrySize(JumpTableArch);
16771660
for (unsigned I = 0; I != Functions.size(); ++I)
16781661
GlobalLayout[Functions[I]] = I * EntrySize;
16791662

@@ -1684,7 +1667,7 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
16841667
M.getDataLayout().getProgramAddressSpace(),
16851668
".cfi.jumptable", &M);
16861669
ArrayType *JumpTableType =
1687-
ArrayType::get(getJumpTableEntryType(), Functions.size());
1670+
ArrayType::get(ArrayType::get(Int8Ty, EntrySize), Functions.size());
16881671
auto JumpTable = ConstantExpr::getPointerCast(
16891672
JumpTableFn, PointerType::getUnqual(M.getContext()));
16901673

@@ -1742,7 +1725,7 @@ void LowerTypeTestsModule::buildBitSetsFromFunctionsNative(
17421725
}
17431726
}
17441727

1745-
createJumpTable(JumpTableFn, Functions);
1728+
createJumpTable(JumpTableFn, Functions, JumpTableArch);
17461729
}
17471730

17481731
/// Assign a dummy layout using an incrementing counter, tag each function

llvm/test/Transforms/LowerTypeTests/aarch64-jumptable.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ define i1 @foo(ptr %p) {
5353
; AARCH64-LABEL: define private void @.cfi.jumptable
5454
; AARCH64-SAME: () #[[ATTR1:[0-9]+]] align 8 {
5555
; AARCH64-NEXT: entry:
56-
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0Abti c\0Ab $1\0A", "s,s"(ptr @f.cfi, ptr @g.cfi)
56+
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @f.cfi)
57+
; AARCH64-NEXT: call void asm sideeffect "bti c\0Ab $0\0A", "s"(ptr @g.cfi)
5758
; AARCH64-NEXT: unreachable
5859
;

llvm/test/Transforms/LowerTypeTests/cfi-direct-call1.ll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ entry:
7373
; Check which jump table entries are created
7474
; FULL: define private void @.cfi.jumptable(){{.*}}
7575
; FULL-NEXT: entry:
76-
; FULL-NEXT: call void asm{{.*}}local_func1.cfi{{.*}}local_func2.cfi{{.*}}extern_weak{{.*}}extern_decl
76+
; FULL-NEXT: call void asm{{.*}}local_func1.cfi
77+
; FULL-NEXT: call void asm{{.*}}local_func2.cfi
78+
; FULL-NEXT: call void asm{{.*}}extern_weak
79+
; FULL-NEXT: call void asm{{.*}}extern_decl
7780

7881
; Make sure all local functions have been renamed to <name>.cfi
7982
; THIN: define hidden i32 @local_func1.cfi()

llvm/test/Transforms/LowerTypeTests/function-arm-thumb.ll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ define void @addrtaken() {
3535

3636
; CHECK: define private void {{.*}} #[[AT:.*]] align 4 {
3737
; CHECK-NEXT: entry:
38-
; CHECK-NEXT: call void asm sideeffect "b.w $0\0Ab.w $1\0A", "s,s"(ptr @f1.cfi, ptr @g1.cfi)
38+
; CHECK-NEXT: call void asm sideeffect "b.w $0\0A", "s"(ptr @f1.cfi)
39+
; CHECK-NEXT: call void asm sideeffect "b.w $0\0A", "s"(ptr @g1.cfi)
3940
; CHECK-NEXT: unreachable
4041
; CHECK-NEXT: }
4142

4243
; CHECK: define private void {{.*}} #[[AA:.*]] align 4 {
4344
; CHECK-NEXT: entry:
44-
; CHECK-NEXT: call void asm sideeffect "b $0\0Ab $1\0Ab $2\0A", "s,s,s"(ptr @f2.cfi, ptr @g2.cfi, ptr @h2.cfi)
45+
; CHECK-NEXT: call void asm sideeffect "b $0\0A", "s"(ptr @f2.cfi)
46+
; CHECK-NEXT: call void asm sideeffect "b $0\0A", "s"(ptr @g2.cfi)
47+
; CHECK-NEXT: call void asm sideeffect "b $0\0A", "s"(ptr @h2.cfi)
4548
; CHECK-NEXT: unreachable
4649
; CHECK-NEXT: }
4750

llvm/test/Transforms/LowerTypeTests/function-thumb-bti.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ define i1 @foo(ptr %p) {
4040

4141
; And check the actual jump table asm string:
4242

43-
; BTI: call void asm sideeffect "bti\0Ab.w $0\0Abti\0Ab.w $1\0A", "s,s"(ptr @f.cfi, ptr @g.cfi)
44-
; NOBTI: call void asm sideeffect "b.w $0\0Ab.w $1\0A", "s,s"(ptr @f.cfi, ptr @g.cfi)
43+
; BTI: call void asm sideeffect "bti\0Ab.w $0\0A", "s"(ptr @f.cfi)
44+
; BTI-NEXT: call void asm sideeffect "bti\0Ab.w $0\0A", "s"(ptr @g.cfi)
45+
; NOBTI: call void asm sideeffect "b.w $0\0A", "s"(ptr @f.cfi)
46+
; NOBTI-NEXT: call void asm sideeffect "b.w $0\0A", "s"(ptr @g.cfi)
4547

4648
; BTI: attributes [[ATTRS]] = { naked noinline "target-features"="+thumb-mode,+pacbti" }
4749
; NOBTI: attributes [[ATTRS]] = { naked noinline "target-cpu"="cortex-a8" "target-features"="+thumb-mode" }

llvm/test/Transforms/LowerTypeTests/function.ll

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,16 +73,10 @@ define i1 @foo(ptr %p) {
7373
; X86-SAME: int3
7474
; X86-SAME: int3
7575
; X86-SAME: int3
76-
; X86-SAME: jmp ${1:c}@plt
77-
; X86-SAME: int3
78-
; X86-SAME: int3
79-
; X86-SAME: int3
8076

8177
; ARM: b $0
82-
; ARM-SAME: b $1
8378

8479
; THUMB: b.w $0
85-
; THUMB-SAME: b.w $1
8680

8781
; THUMBV6M: push {r0,r1}
8882
; THUMBV6M-SAME: ldr r0, 1f
@@ -91,23 +85,37 @@ define i1 @foo(ptr %p) {
9185
; THUMBV6M-SAME: pop {r0,pc}
9286
; THUMBV6M-SAME: .balign 4
9387
; THUMBV6M-SAME: 1: .word $0 - (0b + 4)
94-
; THUMBV6M-SAME: push {r0,r1}
88+
89+
; RISCV: tail $0@plt
90+
91+
; LOONGARCH64: pcalau12i $$t0, %pc_hi20($0)
92+
; LOONGARCH64-SAME: jirl $$r0, $$t0, %pc_lo12($0)
93+
94+
; NATIVE-SAME: "s"(ptr @f.cfi)
95+
96+
; X86-NEXT: jmp ${0:c}@plt
97+
; X86-SAME: int3
98+
; X86-SAME: int3
99+
; X86-SAME: int3
100+
101+
; ARM-NEXT: b $0
102+
103+
; THUMB-NEXT: b.w $0
104+
105+
; THUMBV6M-NEXT: push {r0,r1}
95106
; THUMBV6M-SAME: ldr r0, 1f
96107
; THUMBV6M-SAME: 0: add r0, r0, pc
97108
; THUMBV6M-SAME: str r0, [sp, #4]
98109
; THUMBV6M-SAME: pop {r0,pc}
99110
; THUMBV6M-SAME: .balign 4
100-
; THUMBV6M-SAME: 1: .word $1 - (0b + 4)
111+
; THUMBV6M-SAME: 1: .word $0 - (0b + 4)
101112

102-
; RISCV: tail $0@plt
103-
; RISCV-SAME: tail $1@plt
113+
; RISCV-NEXT: tail $0@plt
104114

105-
; LOONGARCH64: pcalau12i $$t0, %pc_hi20($0)
115+
; LOONGARCH64-NEXT: pcalau12i $$t0, %pc_hi20($0)
106116
; LOONGARCH64-SAME: jirl $$r0, $$t0, %pc_lo12($0)
107-
; LOONGARCH64-SAME: pcalau12i $$t0, %pc_hi20($1)
108-
; LOONGARCH64-SAME: jirl $$r0, $$t0, %pc_lo12($1)
109117

110-
; NATIVE-SAME: "s,s"(ptr @f.cfi, ptr @g.cfi)
118+
; NATIVE-SAME: "s"(ptr @g.cfi)
111119

112120
; X86-LINUX: attributes #[[ATTR]] = { naked nocf_check noinline }
113121
; X86-WIN32: attributes #[[ATTR]] = { nocf_check noinline }

llvm/test/Transforms/LowerTypeTests/x86-jumptable.ll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ define i1 @foo(ptr %p) {
2525

2626
; X86: define private void @.cfi.jumptable() #[[#ATTR:]] align 16 {
2727
; X86-NEXT: entry:
28-
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0Aendbr32\0Ajmp ${1:c}@plt\0A.balign 16, 0xcc\0A", "s,s"(ptr @f.cfi, ptr @g.cfi)
29-
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0Aendbr64\0Ajmp ${1:c}@plt\0A.balign 16, 0xcc\0A", "s,s"(ptr @f.cfi, ptr @g.cfi)
28+
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi)
29+
; X86_32-NEXT: call void asm sideeffect "endbr32\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi)
30+
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @f.cfi)
31+
; X86_64-NEXT: call void asm sideeffect "endbr64\0Ajmp ${0:c}@plt\0A.balign 16, 0xcc\0A", "s"(ptr @g.cfi)
3032

3133
; X86_64: attributes #[[#ATTR]] = { naked nocf_check noinline }

llvm/test/Transforms/MergeFunc/cfi-thunk-merging.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ attributes #3 = { noreturn nounwind }
205205
; LOWERTYPETESTS-LABEL: define private void @.cfi.jumptable
206206
; LOWERTYPETESTS-SAME: () #[[ATTR3:[0-9]+]] align 8 {
207207
; LOWERTYPETESTS-NEXT: entry:
208-
; LOWERTYPETESTS-NEXT: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0Ajmp ${1:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s,s"(ptr @f, ptr @f_thunk)
208+
; LOWERTYPETESTS-NEXT: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(ptr @f)
209+
; LOWERTYPETESTS-NEXT: call void asm sideeffect "jmp ${0:c}@plt\0Aint3\0Aint3\0Aint3\0A", "s"(ptr @f_thunk)
209210
; LOWERTYPETESTS-NEXT: unreachable
210211
;

0 commit comments

Comments
 (0)