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