[all-commits] [llvm/llvm-project] 56acb0: [ARM, AArch64] Don't put BTI at asm goto branch tar...

Simon Tatham via All-commits all-commits at lists.llvm.org
Tue Jun 3 00:44:35 PDT 2025


  Branch: refs/heads/main
  Home:   https://github.com/llvm/llvm-project
  Commit: 56acb06bc6a1bbde6b1f1a3aa3633d049f1821dc
      https://github.com/llvm/llvm-project/commit/56acb06bc6a1bbde6b1f1a3aa3633d049f1821dc
  Author: Simon Tatham <simon.tatham at arm.com>
  Date:   2025-06-03 (Tue, 03 Jun 2025)

  Changed paths:
    M clang/docs/LanguageExtensions.rst
    M clang/docs/ReleaseNotes.rst
    M llvm/docs/LangRef.rst
    M llvm/docs/ReleaseNotes.md
    M llvm/include/llvm/CodeGen/MachineBasicBlock.h
    M llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
    M llvm/lib/CodeGen/BasicBlockPathCloning.cpp
    M llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
    M llvm/lib/Target/AArch64/AArch64BranchTargets.cpp
    M llvm/lib/Target/ARM/ARMBranchTargets.cpp
    A llvm/test/CodeGen/AArch64/callbr-asm-label-bti.ll
    M llvm/test/CodeGen/AArch64/callbr-asm-label.ll
    M llvm/test/CodeGen/AArch64/callbr-asm-outputs-indirect-isel.ll
    M llvm/test/CodeGen/PowerPC/callbr-asm-outputs-indirect-isel.ll
    M llvm/test/CodeGen/PowerPC/ppc64-inlineasm-clobber.ll
    M llvm/test/CodeGen/RISCV/inline-asm-mem-constraint.ll
    M llvm/test/CodeGen/X86/basic-block-sections-cloning-invalid.ll
    M llvm/test/CodeGen/X86/callbr-asm-blockplacement.ll
    M llvm/test/CodeGen/X86/callbr-asm-branch-folding.ll
    M llvm/test/CodeGen/X86/callbr-asm-destinations.ll
    M llvm/test/CodeGen/X86/callbr-asm-label-addr.ll
    M llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel-m32.ll
    M llvm/test/CodeGen/X86/callbr-asm-outputs-indirect-isel.ll
    M llvm/test/CodeGen/X86/callbr-asm-outputs-pred-succ.ll
    M llvm/test/CodeGen/X86/callbr-asm-outputs.ll
    M llvm/test/CodeGen/X86/callbr-asm-phi-placement.ll
    M llvm/test/CodeGen/X86/callbr-asm-sink.ll
    M llvm/test/CodeGen/X86/callbr-asm.ll
    M llvm/test/CodeGen/X86/shrinkwrap-callbr.ll
    M llvm/test/CodeGen/X86/tail-dup-asm-goto.ll

  Log Message:
  -----------
  [ARM,AArch64] Don't put BTI at asm goto branch targets (#141562)

In 'asm goto' statements ('callbr' in LLVM IR), you can specify one or
more labels / basic blocks in the containing function which the assembly
code might jump to. If you're also compiling with branch target
enforcement via BTI, then previously listing a basic block as a possible
jump destination of an asm goto would cause a BTI instruction to be
placed at the start of the block, in case the assembly code used an
_indirect_ branch instruction (i.e. to a destination address read from a
register) to jump to that location. Now it doesn't do that any more:
branches to destination labels from the assembly code are assumed to be
direct branches (to a relative offset encoded in the instruction), which
don't require a BTI at their destination.

This change was proposed in https://discourse.llvm.org/t/85845 and there
seemed to be no disagreement. The rationale is:

1. it brings clang's handling of asm goto in Arm and AArch64 in line
with gcc's, which didn't generate BTIs at the target labels in the first
place.

2. it improves performance in the Linux kernel, which uses a lot of 'asm
goto' in which the assembly language just contains a NOP, and the
label's address is saved elsewhere to let the kernel self-modify at run
time to swap between the original NOP and a direct branch to the label.
This allows hot code paths to be instrumented for debugging, at only the
cost of a NOP when the instrumentation is turned off, instead of the
larger cost of an indirect branch. In this situation a BTI is
unnecessary (if the branch happens it's direct), and since the code
paths are hot, also a noticeable performance hit.

Implementation:

`SelectionDAGBuilder::visitCallBr` is the place where 'asm goto' target
labels are handled. It calls `setIsInlineAsmBrIndirectTarget()` on each
target `MachineBasicBlock`. Previously it also called
`setMachineBlockAddressTaken()`, which made `hasAddressTaken()` return
true, which caused a BTI to be added in the Arm backends.

Now `visitCallBr` doesn't call `setMachineBlockAddressTaken()` any more
on asm goto targets, but `hasAddressTaken()` also checks the flag set by
`setIsInlineAsmBrIndirectTarget()`. So call sites that were using
`hasAddressTaken()` don't need to be modified. But the Arm backends
don't call `hasAddressTaken()` any more: instead they test two more
specific query functions that cover all the reasons `hasAddressTaken()`
might have returned true _except_ being an asm goto target.

Testing:

The new test `AArch64/callbr-asm-label-bti.ll` is testing the actual
change, where it expects not to see a `bti` instruction after
`[[LABEL]]`. The rest of the test changes are all churn, due to the
flags on basic blocks changing. Actual output code hasn't changed in any
of the existing tests, only comments and diagnostics.

Further work:

`RISCVIndirectBranchTracking.cpp` and `X86IndirectBranchTracking.cpp`
also call `hasAddressTaken()` in a way that might benefit from using the
same more specific check I've put in `ARMBranchTargets.cpp` and
`AArch64BranchTargets.cpp`. But I'm not sure of that, so in this commit
I've only changed the Arm backends, and left those alone.



To unsubscribe from these emails, change your notification settings at https://github.com/llvm/llvm-project/settings/notifications


More information about the All-commits mailing list