[llvm] [BOLT][RISCV] Avoid evaluating indirect branches as direct branches (PR #218088)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 19:16:16 PDT 2026


https://github.com/WangJee created https://github.com/llvm/llvm-project/pull/218088

The RISC-V branch evaluator can resolve JALR when the base register state is known. In particular, jalr zero, zero, 0 evaluates to address zero even though it remains an indirect branch.

Do not send indirect branches through the direct branch symbolization path. Leave them to the existing indirect branch handling instead.

Add a regression test modeling a tail call to an undefined weak symbol relaxed by GNU ld.

>From 9cd7cd3fe43ebf468cf483f65a8b5866eddcf4f4 Mon Sep 17 00:00:00 2001
From: "wangjue.wangjue" <wangjue.wangjue at alibaba-inc.com>
Date: Sat, 22 Aug 2026 11:12:35 +0900
Subject: [PATCH] [BOLT][RISCV] Avoid evaluating indirect branches as direct
 branches

The RISC-V branch evaluator can resolve JALR when the base register state is known. In particular, jalr zero, zero, 0 evaluates to address zero even though it remains an indirect branch.

Do not send indirect branches through the direct branch symbolization path. Leave them to the existing indirect branch handling instead.

Add a regression test modeling a tail call to an undefined weak symbol relaxed by GNU ld.
---
 bolt/lib/Core/BinaryFunction.cpp           |  3 ++-
 bolt/test/RISCV/weak-undefined-tail-call.s | 30 ++++++++++++++++++++++
 2 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 bolt/test/RISCV/weak-undefined-tail-call.s

diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index a81fa2f45c206..eb904ebef201f 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -1423,7 +1423,8 @@ Error BinaryFunction::disassemble() {
 
     if (MIB->isBranch(Instruction) || MIB->isCall(Instruction)) {
       uint64_t TargetAddress = 0;
-      if (MIB->evaluateBranch(Instruction, AbsoluteInstrAddr, Size,
+      if (!MIB->isIndirectBranch(Instruction) &&
+          MIB->evaluateBranch(Instruction, AbsoluteInstrAddr, Size,
                               TargetAddress)) {
         // Check if the target is within the same function. Otherwise it's
         // a call, possibly a tail call.
diff --git a/bolt/test/RISCV/weak-undefined-tail-call.s b/bolt/test/RISCV/weak-undefined-tail-call.s
new file mode 100644
index 0000000000000..41610630d7a17
--- /dev/null
+++ b/bolt/test/RISCV/weak-undefined-tail-call.s
@@ -0,0 +1,30 @@
+// RUN: llvm-mc -triple riscv64 -filetype=obj -o %t.o %s
+// RUN: ld.lld --emit-relocs -static -o %t.exe %t.o
+// RUN: llvm-bolt --print-cfg --print-only=_start -o %t.bolt %t.exe \
+// RUN:   | FileCheck %s
+
+/// GNU ld can relax a tail call to an undefined weak symbol to
+/// `jalr zero, zero, 0`, while preserving the R_RISCV_CALL_PLT relocation on
+/// the preceding AUIPC. The JALR target is evaluatable as zero, but the
+/// instruction is still an indirect branch and must not be rewritten as a
+/// direct branch.
+
+  .text
+  .option norvc
+  .weak weak_func
+
+// CHECK-LABEL: Binary Function "_start
+// CHECK:      auipc t1,
+// CHECK-NEXT: jr zero # TAILCALL
+
+  .globl _start
+  .type _start, @function
+_start:
+  li a0, 0
+  beqz a0, .Lreturn
+.Lcall:
+  auipc t1, 0
+  .reloc .Lcall, R_RISCV_CALL_PLT, weak_func
+  jalr zero, zero, 0
+.Lreturn:
+  ret



More information about the llvm-commits mailing list