[llvm] [BOLT][RISCV] Fix conditional tail call (PR #209474)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 14 06:21:41 PDT 2026
https://github.com/Thrrreeee created https://github.com/llvm/llvm-project/pull/209474
When BOLT encounters an external-reference branch, `BinaryFunction::handleExternalReference()` first calls convertJmpToTailCall(). The RISC-V implementation previously bailed out with unsupported tail call opcode, because it only accepted `JAL`, `JALR`, `C_J`, and `C_JR`. As a result, conditional branches targeting external symbols could not be converted into (conditional) tail calls.
This patch adds the RISC-V backend to cooperate with BOLT's existing conditional-tail-call machinery.
PR [#160042](https://github.com/llvm/llvm-project/pull/160042) explicitly adds every conditional branch opcode to `convertJmpToTailCall().` That causes the instruction to first receive the regular kTailCall annotation, before `handleExternalReference()` subsequently overrides it with `kConditionalTailCall`.
Added regression tests covering conditional-tail-call conversion for all base and compressed RISC-V conditional branches (`BEQ`, `BNE`, `BLT`, `BGE`, `BLTU`, `BGEU`, `C_BEQZ`, `C_BNEZ`).
>From aaa119bb45a5aabf9905b56694105e150eb033d6 Mon Sep 17 00:00:00 2001
From: Thrrreeeee <1379998393 at qq.com>
Date: Tue, 14 Jul 2026 20:58:30 +0800
Subject: [PATCH] [BOLT][RISCV] Fix conditional tail call
---
bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp | 12 +++-
bolt/test/RISCV/conditional-tail-call.s | 66 ++++++++++++++++++++
2 files changed, 77 insertions(+), 1 deletion(-)
create mode 100644 bolt/test/RISCV/conditional-tail-call.s
diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
index d1a0572277874..a1461645409a3 100644
--- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
+++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
@@ -215,7 +215,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
switch (Inst.getOpcode()) {
default:
- llvm_unreachable("unsupported tail call opcode");
+ return false;
case RISCV::JAL:
case RISCV::JALR:
case RISCV::C_J:
@@ -227,6 +227,14 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
return true;
}
+ bool convertTailCallToJmp(MCInst &Inst) override {
+ removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall);
+ clearOffset(Inst);
+ if (getConditionalTailCall(Inst))
+ unsetConditionalTailCall(Inst);
+ return true;
+ }
+
void createReturn(MCInst &Inst) const override {
// TODO "c.jr ra" when RVC is enabled
Inst.setOpcode(RISCV::JALR);
@@ -328,6 +336,8 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
default:
return false;
case RISCV::C_J:
+ case RISCV::PseudoCALL:
+ case RISCV::PseudoTAIL:
OpNum = 0;
return true;
case RISCV::AUIPC:
diff --git a/bolt/test/RISCV/conditional-tail-call.s b/bolt/test/RISCV/conditional-tail-call.s
new file mode 100644
index 0000000000000..4a7c6e84ca4a4
--- /dev/null
+++ b/bolt/test/RISCV/conditional-tail-call.s
@@ -0,0 +1,66 @@
+// Check that all base and compressed RISC-V conditional branches targeting
+// another function are expanded to tail-call blocks, survive block reordering,
+// and are emitted with the correct target.
+
+// RUN: llvm-mc -triple riscv64 -mattr=+c -filetype=obj -o %t.o %s
+// RUN: ld.lld -o %t %t.o
+// RUN: llvm-bolt %t -o %t.bolt --reorder-blocks=reverse --print-cfg \
+// RUN: --print-only=conditional_tail_calls 2>&1 | FileCheck %s --check-prefix=CFG
+// RUN: llvm-objdump -d --disassemble-symbols=conditional_tail_calls %t.bolt \
+// RUN: | FileCheck %s --check-prefix=DISASM
+
+// CFG-LABEL: Binary Function "conditional_tail_calls" after building cfg {
+// CFG: beq a0, a1, .LTC0
+// CFG: bne a0, a1, .LTC1
+// CFG: blt a0, a1, .LTC2
+// CFG: bge a0, a1, .LTC3
+// CFG: bltu a0, a1, .LTC4
+// CFG: bgeu a0, a1, .LTC5
+// CFG: beqz a0, .LTC6
+// CFG: bnez a0, .LTC7
+// CFG-COUNT-8: tail callee
+// CFG: BOLT-INFO: basic block reordering modified layout of 1 functions
+
+// DISASM-LABEL: <conditional_tail_calls>:
+// DISASM-NEXT: {{.*}} beq a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} bne a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} blt a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} bge a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} bltu a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} bgeu a0, a1, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} beqz a0, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} bnez a0, {{.*}} <callee>
+// DISASM-NEXT: {{.*}} ret
+
+ .text
+ .option rvc
+
+ .globl conditional_tail_calls
+ .type conditional_tail_calls, @function
+ .p2align 1
+conditional_tail_calls:
+ beq a0, a1, .Lcallee
+ bne a0, a1, .Lcallee
+ blt a0, a1, .Lcallee
+ bge a0, a1, .Lcallee
+ bltu a0, a1, .Lcallee
+ bgeu a0, a1, .Lcallee
+ c.beqz a0, .Lcallee
+ c.bnez a0, .Lcallee
+ ret
+ .size conditional_tail_calls, .-conditional_tail_calls
+
+ .globl callee
+ .type callee, @function
+ .p2align 1
+callee:
+.Lcallee:
+ ret
+ .size callee, .-callee
+
+ .globl _start
+ .type _start, @function
+ .p2align 1
+_start:
+ ret
+ .size _start, .-_start
More information about the llvm-commits
mailing list