Skip to content

[BOLT][RISCV] Handle long tail calls #67098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1761,7 +1761,8 @@ bool BinaryFunction::postProcessIndirectBranches(
uint64_t LastJT = 0;
uint16_t LastJTIndexReg = BC.MIB->getNoRegister();
for (BinaryBasicBlock &BB : blocks()) {
for (MCInst &Instr : BB) {
for (BinaryBasicBlock::iterator II = BB.begin(); II != BB.end(); ++II) {
MCInst &Instr = *II;
if (!BC.MIB->isIndirectBranch(Instr))
continue;

Expand Down Expand Up @@ -1789,7 +1790,7 @@ bool BinaryFunction::postProcessIndirectBranches(
const MCExpr *DispExpr;
MCInst *PCRelBaseInstr;
IndirectBranchType Type = BC.MIB->analyzeIndirectBranch(
Instr, BB.begin(), BB.end(), PtrSize, MemLocInstr, BaseRegNum,
Instr, BB.begin(), II, PtrSize, MemLocInstr, BaseRegNum,
IndexRegNum, DispValue, DispExpr, PCRelBaseInstr);
if (Type != IndirectBranchType::UNKNOWN || MemLocInstr != nullptr)
continue;
Expand Down
7 changes: 6 additions & 1 deletion bolt/lib/Passes/FixRISCVCallsPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,12 @@ void FixRISCVCallsPass::runOnFunction(BinaryFunction &BF) {

MCInst OldCall = *NextII;
auto L = BC.scopeLock();
MIB->createCall(*II, Target, Ctx);

if (MIB->isTailCall(*NextII))
MIB->createTailCall(*II, Target, Ctx);
else
MIB->createCall(*II, Target, Ctx);

MIB->moveAnnotations(std::move(OldCall), *II);

// The original offset was set on the jalr of the auipc+jalr pair. Since
Expand Down
12 changes: 12 additions & 0 deletions bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
return false;
case RISCV::JALR:
case RISCV::C_JALR:
case RISCV::C_JR:
return true;
}
}
Expand Down Expand Up @@ -154,6 +155,17 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
DispValue = 0;
DispExpr = nullptr;
PCRelBaseOut = nullptr;

// Check for the following long tail call sequence:
// 1: auipc xi, %pcrel_hi(sym)
// jalr zero, %pcrel_lo(1b)(xi)
if (Instruction.getOpcode() == RISCV::JALR && Begin != End) {
MCInst &PrevInst = *std::prev(End);
if (isRISCVCall(PrevInst, Instruction) &&
Instruction.getOperand(0).getReg() == RISCV::X0)
return IndirectBranchType::POSSIBLE_TAIL_CALL;
}

return IndirectBranchType::UNKNOWN;
}

Expand Down
33 changes: 32 additions & 1 deletion bolt/test/RISCV/call-annotations.s
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// RUN: llvm-mc -triple riscv64 -filetype obj -o %t.o %s
// RUN: ld.lld --emit-relocs -o %t %t.o
// RUN: llvm-bolt --enable-bat --print-cfg --print-fix-riscv-calls \
// RUN: --print-only=_start -o /dev/null %t | FileCheck %s
// RUN: -o /dev/null %t | FileCheck %s

.text
.global f
Expand All @@ -19,15 +19,46 @@ f:
// CHECK-NEXT: jal ra, f # Offset: 8
// CHECK-NEXT: jal zero, f # TAILCALL # Offset: 12

// CHECK-LABEL: Binary Function "long_tail" after building cfg {
// CHECK: auipc t1, f
// CHECK-NEXT: jalr zero, -24(t1) # TAILCALL # Offset: 8

// CHECK-LABEL: Binary Function "compressed_tail" after building cfg {
// CHECK: jr a0 # TAILCALL # Offset: 0

// CHECK-LABEL: Binary Function "_start" after fix-riscv-calls {
// CHECK: call f # Offset: 0
// CHECK-NEXT: call f # Offset: 8
// CHECK-NEXT: tail f # TAILCALL # Offset: 12

// CHECK-LABEL: Binary Function "long_tail" after fix-riscv-calls {
// CHECK: tail f # TAILCALL # Offset: 4

// CHECK-LABEL: Binary Function "compressed_tail" after fix-riscv-calls {
// CHECK: jr a0 # TAILCALL # Offset: 0

.globl _start
.p2align 1
_start:
call f
jal f
jal zero, f
.size _start, .-_start

.globl long_tail
.p2align 1
long_tail:
// NOTE: BOLT assumes indirect calls in single-BB functions are tail calls
// so artificially introduce a second BB to force RISC-V-specific analysis
// to get triggered.
beq a0, a1, 1f
1:
tail f
.size long_tail, .-long_tail

.globl compressed_tail
.p2align 1
.option rvc
compressed_tail:
c.jr a0
.size compressed_tail, .-compressed_tail