[llvm] f9c9f94 - [AArch64] Mark X16 as clobbered in PAUTH_EPILOGUE for hint-based PAuthLR (#175991)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 13 05:13:30 PDT 2026
Author: Victor Campos
Date: 2026-04-13T13:13:25+01:00
New Revision: f9c9f94f13c88be0626d5a4e453f5494de0e106a
URL: https://github.com/llvm/llvm-project/commit/f9c9f94f13c88be0626d5a4e453f5494de0e106a
DIFF: https://github.com/llvm/llvm-project/commit/f9c9f94f13c88be0626d5a4e453f5494de0e106a.diff
LOG: [AArch64] Mark X16 as clobbered in PAUTH_EPILOGUE for hint-based PAuthLR (#175991)
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.
Added:
llvm/test/CodeGen/AArch64/sign-return-address-pauthlr-slh.ll
Modified:
llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
llvm/lib/Target/AArch64/AArch64InstrInfo.h
llvm/lib/Target/AArch64/AArch64InstrInfo.td
llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp b/llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
index 07447316b7fc2..396f7d8ff5f9c 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 988fe7014ddcf..1a7c092793ed5 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.cpp
@@ -10801,9 +10801,7 @@ static void signOutlinedFunction(MachineFunction &MF, MachineBasicBlock &MBB,
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(
@@ -11294,6 +11292,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 fa63c56739d62..2307e2e75786d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.h
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.h
@@ -580,6 +580,12 @@ class AArch64InstrInfo final : public AArch64GenInstrInfo {
static int
findCondCodeUseOperandIdxForBranchOrSelect(const MachineInstr &Instr);
+ /// 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 d3c714fcbb564..047368d6847c7 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2083,6 +2083,11 @@ 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 clobbers X16. Insert this instruction with the
+// AArch64InstrInfo::createPauthEpilogueInstr method that adds an implicit-def
+// operand as needed.
def PAUTH_EPILOGUE : Pseudo<(outs), (ins), []>, Sched<[]>;
}
diff --git a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
index 37a5f5b8b1c62..230ea947c5e54 100644
--- a/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PrologueEpilogue.cpp
@@ -1774,11 +1774,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" }
More information about the llvm-commits
mailing list