[llvm-branch-commits] [llvm] [AArch64] Mark X16 as clobbered in PAUTH_EPILOGUE for hint-based PAuthLR (PR #175991)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jan 14 08:51:56 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Victor Campos (vhscampos)
<details>
<summary>Changes</summary>
When users request branch protection with PAuthLR on targets that do not support the PAuthLR instructions, the PAUTH_EPILOGUE falls back to using hint-space instructions. This fallback sequence uses X16 as a temporary register, but X16 was not listed in the clobber set.
Because Speculative Load Hardening uses X16, this omission made SLH incompatible with this PAUTH_EPILOGUE path.
Mark X16 as clobbered so the compiler does not assume X16 is preserved across the epilogue, restoring compatibility with Speculative Load Hardening and avoiding incorrect register liveness assumptions. The clobber is added in C++ rather than TableGen, as X16 is only clobbered when PAuthLR is requested as a branch protection variation and should not be treated as clobbered unconditionally.
---
Full diff: https://github.com/llvm/llvm-project/pull/175991.diff
6 Files Affected:
- (modified) llvm/lib/Target/AArch64/AArch64FrameLowering.cpp (+1-2)
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.cpp (+13-3)
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.h (+6)
- (modified) llvm/lib/Target/AArch64/AArch64InstrInfo.td (+3)
- (modified) llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp (+2-5)
- (added) llvm/test/CodeGen/AArch64/sign-return-address-pauthlr-slh.ll (+103)
``````````diff
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 4fb7c62156733..78ccae81f531e 100644
--- a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
@@ -1197,8 +1197,7 @@ void AArch64FrameLowering::emitPacRetPlusLeafHardening(
if (MBBI != MBB.end())
DL = MBBI->getDebugLoc();
- BuildMI(MBB, MBBI, DL, TII->get(AArch64::PAUTH_EPILOGUE))
- .setMIFlag(MachineInstr::FrameDestroy);
+ TII->createPauthEpilogueInstr(MBB, DL);
};
// This should be in sync with PEIImpl::calculateSaveRestoreBlocks.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
index f07211325393d..e8b96f6a532bd 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -10719,14 +10719,13 @@ void AArch64InstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
static void signOutlinedFunction(MachineFunction &MF, MachineBasicBlock &MBB,
const AArch64InstrInfo *TII,
bool ShouldSignReturnAddr) {
+ assert(&MF.front() == &MBB);
if (!ShouldSignReturnAddr)
return;
BuildMI(MBB, MBB.begin(), DebugLoc(), TII->get(AArch64::PAUTH_PROLOGUE))
.setMIFlag(MachineInstr::FrameSetup);
- BuildMI(MBB, MBB.getFirstInstrTerminator(), DebugLoc(),
- TII->get(AArch64::PAUTH_EPILOGUE))
- .setMIFlag(MachineInstr::FrameDestroy);
+ TII->createPauthEpilogueInstr(MBB, DebugLoc());
}
void AArch64InstrInfo::buildOutlinedFrame(
@@ -11217,6 +11216,17 @@ unsigned llvm::getBLRCallOpcode(const MachineFunction &MF) {
return AArch64::BLR;
}
+void AArch64InstrInfo::createPauthEpilogueInstr(MachineBasicBlock &MBB,
+ DebugLoc DL) const {
+ MachineBasicBlock::iterator InsertPt = MBB.getFirstTerminator();
+ auto Builder = BuildMI(MBB, InsertPt, DL, get(AArch64::PAUTH_EPILOGUE))
+ .setMIFlag(MachineInstr::FrameDestroy);
+
+ const auto *AFI = MBB.getParent()->getInfo<AArch64FunctionInfo>();
+ if (AFI->branchProtectionPAuthLR() && !Subtarget.hasPAuthLR())
+ Builder.addReg(AArch64::X16, RegState::ImplicitDefine);
+}
+
MachineBasicBlock::iterator
AArch64InstrInfo::probedStackAlloc(MachineBasicBlock::iterator MBBI,
Register TargetReg, bool FrameSetup) const {
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.h b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
index 2ccde3e661de5..e40e37b0c526f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -571,6 +571,12 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
Register TargetReg,
bool FrameSetup) const;
+ /// Insert a `PAUTH_EPILOGUE` pseudo before the first terminator in \p MBB to
+ /// authenticate the return address. Adds an implicit def of X16 when the
+ /// branch protection uses PAuthLR but the subtarget lacks PAuthLR
+ /// instructions.
+ void createPauthEpilogueInstr(MachineBasicBlock &MBB, DebugLoc DL) const;
+
#define GET_INSTRINFO_HELPER_DECLS
#include "AArch64GenInstrInfo.inc"
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index cb8f7c3d70afc..58a96efee0507 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2063,6 +2063,9 @@ def PAUTH_PROLOGUE : Pseudo<(outs), (ins), []>, Sched<[]> {
// Insertion point of LR authentication code.
// The RET terminator of the containing machine basic block may be replaced
// with a combined RETA(A|B) instruction when rewriting this Pseudo.
+//
+// In the case where PAuthLR is requested but the subtarget lacks PAuthLR instructions,
+// this pseudo also implicitly defines X16. This is done in C++ code.
def PAUTH_EPILOGUE : Pseudo<(outs), (ins), []>, Sched<[]>;
}
diff --git a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
index a1be940937cdb..432584adbb4a1 100644
--- a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
@@ -1754,11 +1754,8 @@ void AArch64EpilogueEmitter::finalizeEpilogue() const {
if (AFI->shouldSignReturnAddress(MF)) {
// If pac-ret+leaf is in effect, PAUTH_EPILOGUE pseudo instructions
// are inserted by emitPacRetPlusLeafHardening().
- if (!AFL.shouldSignReturnAddressEverywhere(MF)) {
- BuildMI(MBB, MBB.getFirstTerminator(), DL,
- TII->get(AArch64::PAUTH_EPILOGUE))
- .setMIFlag(MachineInstr::FrameDestroy);
- }
+ if (!AFL.shouldSignReturnAddressEverywhere(MF))
+ TII->createPauthEpilogueInstr(MBB, DL);
// AArch64PointerAuth pass will insert SEH_PACSignLR
HasWinCFI |= NeedsWinCFI;
}
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-pauthlr-slh.ll b/llvm/test/CodeGen/AArch64/sign-return-address-pauthlr-slh.ll
new file mode 100644
index 0000000000000..f74e369647730
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-pauthlr-slh.ll
@@ -0,0 +1,103 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-none-linux-gnu %s -o - | FileCheck %s --check-prefix=CHECK-NO-PAUTH
+; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+pauth %s -o - | FileCheck %s --check-prefix=CHECK-PAUTH
+; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+pauth-lr %s -o - | FileCheck %s --check-prefix=CHECK-PAUTHLR
+; RUN: llc -mtriple=aarch64-none-linux-gnu -mattr=+pauth,+pauth-lr %s -o - | FileCheck %s --check-prefix=CHECK-PAUTH-PAUTHLR
+
+define i32 @f() #0 {
+; CHECK-NO-PAUTH-LABEL: f:
+; CHECK-NO-PAUTH: // %bb.0: // %entry
+; CHECK-NO-PAUTH-NEXT: dsb sy
+; CHECK-NO-PAUTH-NEXT: isb
+; CHECK-NO-PAUTH-NEXT: hint #39
+; CHECK-NO-PAUTH-NEXT: .cfi_negate_ra_state_with_pc
+; CHECK-NO-PAUTH-NEXT: .Ltmp0:
+; CHECK-NO-PAUTH-NEXT: hint #25
+; CHECK-NO-PAUTH-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NO-PAUTH-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NO-PAUTH-NEXT: .cfi_offset w30, -16
+; CHECK-NO-PAUTH-NEXT: hint #7
+; CHECK-NO-PAUTH-NEXT: mov w0, wzr
+; CHECK-NO-PAUTH-NEXT: //APP
+; CHECK-NO-PAUTH-NEXT: //NO_APP
+; CHECK-NO-PAUTH-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NO-PAUTH-NEXT: adrp x16, .Ltmp0
+; CHECK-NO-PAUTH-NEXT: add x16, x16, :lo12:.Ltmp0
+; CHECK-NO-PAUTH-NEXT: hint #39
+; CHECK-NO-PAUTH-NEXT: hint #29
+; CHECK-NO-PAUTH-NEXT: ret
+;
+; CHECK-PAUTH-LABEL: f:
+; CHECK-PAUTH: // %bb.0: // %entry
+; CHECK-PAUTH-NEXT: dsb sy
+; CHECK-PAUTH-NEXT: isb
+; CHECK-PAUTH-NEXT: hint #39
+; CHECK-PAUTH-NEXT: .cfi_negate_ra_state_with_pc
+; CHECK-PAUTH-NEXT: .Ltmp0:
+; CHECK-PAUTH-NEXT: paciasp
+; CHECK-PAUTH-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-PAUTH-NEXT: .cfi_def_cfa_offset 16
+; CHECK-PAUTH-NEXT: .cfi_offset w30, -16
+; CHECK-PAUTH-NEXT: xpaci x30
+; CHECK-PAUTH-NEXT: mov w0, wzr
+; CHECK-PAUTH-NEXT: //APP
+; CHECK-PAUTH-NEXT: //NO_APP
+; CHECK-PAUTH-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-PAUTH-NEXT: adrp x16, .Ltmp0
+; CHECK-PAUTH-NEXT: add x16, x16, :lo12:.Ltmp0
+; CHECK-PAUTH-NEXT: hint #39
+; CHECK-PAUTH-NEXT: retaa
+;
+; CHECK-PAUTHLR-LABEL: f:
+; CHECK-PAUTHLR: // %bb.0: // %entry
+; CHECK-PAUTHLR-NEXT: cmp sp, #0
+; CHECK-PAUTHLR-NEXT: csetm x16, ne
+; CHECK-PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc
+; CHECK-PAUTHLR-NEXT: .Ltmp0:
+; CHECK-PAUTHLR-NEXT: paciasppc
+; CHECK-PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; CHECK-PAUTHLR-NEXT: .cfi_offset w30, -16
+; CHECK-PAUTHLR-NEXT: hint #7
+; CHECK-PAUTHLR-NEXT: mov w0, wzr
+; CHECK-PAUTHLR-NEXT: //APP
+; CHECK-PAUTHLR-NEXT: //NO_APP
+; CHECK-PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-PAUTHLR-NEXT: and x30, x30, x16
+; CHECK-PAUTHLR-NEXT: csdb
+; CHECK-PAUTHLR-NEXT: mov x1, sp
+; CHECK-PAUTHLR-NEXT: autiasppc .Ltmp0
+; CHECK-PAUTHLR-NEXT: and x1, x1, x16
+; CHECK-PAUTHLR-NEXT: mov sp, x1
+; CHECK-PAUTHLR-NEXT: ret
+;
+; CHECK-PAUTH-PAUTHLR-LABEL: f:
+; CHECK-PAUTH-PAUTHLR: // %bb.0: // %entry
+; CHECK-PAUTH-PAUTHLR-NEXT: cmp sp, #0
+; CHECK-PAUTH-PAUTHLR-NEXT: csetm x16, ne
+; CHECK-PAUTH-PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc
+; CHECK-PAUTH-PAUTHLR-NEXT: .Ltmp0:
+; CHECK-PAUTH-PAUTHLR-NEXT: paciasppc
+; CHECK-PAUTH-PAUTHLR-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-PAUTH-PAUTHLR-NEXT: .cfi_def_cfa_offset 16
+; CHECK-PAUTH-PAUTHLR-NEXT: .cfi_offset w30, -16
+; CHECK-PAUTH-PAUTHLR-NEXT: xpaci x30
+; CHECK-PAUTH-PAUTHLR-NEXT: mov w0, wzr
+; CHECK-PAUTH-PAUTHLR-NEXT: //APP
+; CHECK-PAUTH-PAUTHLR-NEXT: //NO_APP
+; CHECK-PAUTH-PAUTHLR-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-PAUTH-PAUTHLR-NEXT: and x30, x30, x16
+; CHECK-PAUTH-PAUTHLR-NEXT: csdb
+; CHECK-PAUTH-PAUTHLR-NEXT: mov x1, sp
+; CHECK-PAUTH-PAUTHLR-NEXT: and x1, x1, x16
+; CHECK-PAUTH-PAUTHLR-NEXT: mov sp, x1
+; CHECK-PAUTH-PAUTHLR-NEXT: retaasppc .Ltmp0
+entry:
+ %0 = tail call ptr @llvm.returnaddress(i32 0)
+ tail call void asm sideeffect "", "r"(ptr %0)
+ ret i32 0
+}
+
+declare ptr @llvm.returnaddress(i32 immarg)
+
+attributes #0 = { speculative_load_hardening "branch-protection-pauth-lr" "sign-return-address"="all" "sign-return-address-key"="a_key" }
``````````
</details>
https://github.com/llvm/llvm-project/pull/175991
More information about the llvm-branch-commits
mailing list