[llvm-branch-commits] [llvm] release/22.x: [BPF] Fix erroneous removal of non-jump-table globals (#204594) (PR #204724)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Jun 18 21:42:26 PDT 2026
https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/204724
Backport 9fc458a1d95b
Requested by: @yonghong-song
>From 2972230af989ecd61fd45e4c5c8b4d56a8e30a84 Mon Sep 17 00:00:00 2001
From: yonghong-song <yhs at fb.com>
Date: Thu, 18 Jun 2026 18:38:00 -0700
Subject: [PATCH] [BPF] Fix erroneous removal of non-jump-table globals
(#204594)
Jump tables are supported only for cpu v4. After lowering them into
.jumptables entries, BPFAsmPrinter::doFinalization() removes the private
constant arrays that backed the jump tables. But the below 'for' loop is
actually a no-op.
for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {
if (!dyn_cast<BlockAddress>(CA->getOperand(i)))
continue;
}
Targets.push_back(&Global);
With current implementation, 'Global' will be added to 'Targets' and
later in doFinalization(), 'Global' will be removed. But it is possible
in 'Global' there exists non BlockAddress which are used in later code.
This will cause the problem like:
error: Undefined temporary symbol .L__const.select_fn.fns
To fix the problem, For the above 'for' loop, only if all operands are
with BlockAddress, 'Global' can be pushed to 'Targets'.
The issue is discovered when running bpf selftest with -O1. The related
file is
tools/testing/selftests/bpf/progs/kprobe_multi_session.c
Before optimization, we have
@__const.session_check.kfuncs = private unnamed_addr constant [8 x ptr]
[ptr @bpf_fentry_test1, ptr @bpf_fentry_test2, ptr @bpf_fentry_test3,
ptr @bpf_fentry_test4, ptr @bpf_fentry_test5, ptr @bpf_fentry_test6,
ptr @bpf_fentry_test7, ptr @bpf_fentry_test8], align 8
With -O1, `@__const.session_check.kfuncs` is used in codegen like
...
$r2 = LD_imm64 @__const.session_check.kfuncs
...
which triggered the compilation failure.
With -O2, `@__const.session_check.kfuncs` is inlined in llvm
GlobalOptPass and each individual funciton `@bpf_fentry_test1` etc. is
directly used in IR, e.g.,
...
%9 = icmp eq i64 %8, ptrtoint (ptr @bpf_fentry_test1 to i64), !dbg !95
...
(cherry picked from commit 9fc458a1d95b9c3edf288e4ec2cd9dcd1fe0d895)
---
llvm/lib/Target/BPF/BPFAsmPrinter.cpp | 7 ++--
.../CodeGen/BPF/jump_table_func_ptr_array.ll | 41 +++++++++++++++++++
2 files changed, 44 insertions(+), 4 deletions(-)
create mode 100644 llvm/test/CodeGen/BPF/jump_table_func_ptr_array.ll
diff --git a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
index abe081c0c76fd..2e472bd800888 100644
--- a/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
+++ b/llvm/lib/Target/BPF/BPFAsmPrinter.cpp
@@ -74,10 +74,9 @@ bool BPFAsmPrinter::doFinalization(Module &M) {
if (!CA)
continue;
- for (unsigned i = 1, e = CA->getNumOperands(); i != e; ++i) {
- if (!dyn_cast<BlockAddress>(CA->getOperand(i)))
- continue;
- }
+ if (!all_of(CA->operands(),
+ [](const Use &Op) { return isa<BlockAddress>(Op); }))
+ continue;
Targets.push_back(&Global);
}
diff --git a/llvm/test/CodeGen/BPF/jump_table_func_ptr_array.ll b/llvm/test/CodeGen/BPF/jump_table_func_ptr_array.ll
new file mode 100644
index 0000000000000..0b50d57feb4d0
--- /dev/null
+++ b/llvm/test/CodeGen/BPF/jump_table_func_ptr_array.ll
@@ -0,0 +1,41 @@
+; RUN: llc -march=bpf -mcpu=v4 < %s | FileCheck %s
+
+; The real jump table (@__const.foo.jt, all BlockAddress) is converted into a
+; .jumptables entry and its global is removed.
+; CHECK-LABEL: foo:
+; CHECK: r2 = BPF.JT.0.0 ll
+; CHECK: gotox r1
+; CHECK: .section .jumptables
+; CHECK: BPF.JT.0.0:
+
+; The function-pointer array is preserved and still emitted.
+; CHECK-LABEL: get:
+; CHECK: r2 = .Lkfuncs ll
+; CHECK: .Lkfuncs:
+; CHECK: .size .Lkfuncs, 16
+
+ at __const.foo.jt = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@foo, %l1), ptr blockaddress(@foo, %l2)], align 8
+ at kfuncs = private unnamed_addr constant [2 x ptr] [ptr @ext1, ptr @ext2], align 8
+
+declare void @ext1()
+declare void @ext2()
+
+define i32 @foo(i32 %a) {
+entry:
+ %rem = and i32 %a, 1
+ %idx = zext nneg i32 %rem to i64
+ %g = getelementptr inbounds nuw [2 x ptr], ptr @__const.foo.jt, i64 0, i64 %idx
+ %t = load ptr, ptr %g, align 8
+ indirectbr ptr %t, [label %l1, label %l2]
+l1:
+ br label %l2
+l2:
+ %ret = phi i32 [ 4, %l1 ], [ 3, %entry ]
+ ret i32 %ret
+}
+
+define ptr @get(i64 %i) {
+ %p = getelementptr inbounds [2 x ptr], ptr @kfuncs, i64 0, i64 %i
+ %v = load ptr, ptr %p, align 8
+ ret ptr %v
+}
More information about the llvm-branch-commits
mailing list