From 881c877d43a6069250b675d1dae7624e1fb2e9ca Mon Sep 17 00:00:00 2001 From: Maksim Panchenko Date: Wed, 17 Sep 2025 13:15:56 -0700 Subject: [PATCH] [BOLT][AArch64] Treat `br x30` as a return On AArch64, `br x30` instruction is equivalent to `ret`. Treat it as such while analysing the control flow. Without the special case, `br x30` is considered an indirect branch with an unknown control flow making a control flow analysis more complicated than necessary. We can also replace `br x30` with `ret`. I'd rather do it in a separate pass to allow tools built on top of BOLT to have access to the original assembly. --- .../Target/AArch64/AArch64MCPlusBuilder.cpp | 21 +++++++++++++++++++ bolt/test/AArch64/br-x30.s | 16 ++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 bolt/test/AArch64/br-x30.s diff --git a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp index f972646aa12ea..b8da5d854b836 100644 --- a/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp +++ b/bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp @@ -152,6 +152,27 @@ class AArch64MCPlusBuilder : public MCPlusBuilder { return isLoadFromStack(Inst); }; + bool isReturn(const MCInst &Inst) const override { + // BR X30 is equivalent to RET + if (Inst.getOpcode() == AArch64::BR && + Inst.getOperand(0).getReg() == AArch64::LR) + return true; + + return Analysis->isReturn(Inst); + } + + bool isBranch(const MCInst &Inst) const override { + if (isReturn(Inst)) + return false; + return Analysis->isBranch(Inst); + } + + bool isIndirectBranch(const MCInst &Inst) const override { + if (isReturn(Inst)) + return false; + return Analysis->isIndirectBranch(Inst); + } + void createCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx) override { createDirectCall(Inst, Target, Ctx, false); diff --git a/bolt/test/AArch64/br-x30.s b/bolt/test/AArch64/br-x30.s new file mode 100644 index 0000000000000..711e8a8faef84 --- /dev/null +++ b/bolt/test/AArch64/br-x30.s @@ -0,0 +1,16 @@ +## Test that "br x30" is treated as a return instruction and not as an indirect +## branch. + +# RUN: %clang %cflags %s -o %t.exe -Wl,-q -Wl,--entry=foo +# RUN: llvm-bolt %t.exe -o %t.bolt --print-cfg 2>&1 | FileCheck %s + +# CHECK: BB Count : 2 +# CHECK-NOT: UNKNOWN CONTROL FLOW + + .text + .global foo + .type foo, %function +foo: + br x30 + nop + .size foo, .-foo