[llvm] [AArch64][PAC] Rework the expansion of AUT/AUTPAC pseudos (PR #169699)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 17 05:46:32 PDT 2026


https://github.com/atrosinenko updated https://github.com/llvm/llvm-project/pull/169699

>From 1945b47536970a4c0f5e137f31c29fdce78a184b Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 25 Sep 2025 22:28:14 +0300
Subject: [PATCH 1/4] [AArch64][PAC] Rework the expansion of AUT/AUTPAC pseudos

Refactor `AArch64AsmPrinter::emitPtrauthAuthResign` to improve
readability and fix the conditions when `emitPtrauthDiscriminator` is
allowed to clobber AddrDisc.

* do not clobber `AUTAddrDisc` when computing `AUTDiscReg` on resigning
  if `AUTAddrDisc == PACAddrDisc`, as it would prevent passing raw,
  64-bit value as the new discriminator
* move the code computing `ShouldCheck` and `ShouldTrap` conditions to a
  separate function
---
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 118 +++++++++++-------
 ...trauth-intrinsic-auth-resign-with-blend.ll |  77 ++++++++++--
 2 files changed, 140 insertions(+), 55 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 1f2da924db263..11361871cecd4 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -202,6 +202,10 @@ class AArch64AsmPrinter : public AsmPrinter {
     Register AddrDisc;
     bool AddrDiscIsKilled;
     Register PCDisc;
+
+    bool addrDiscIsKilledAndNoneOf(std::initializer_list<Register> Regs) {
+      return AddrDiscIsKilled && !llvm::is_contained(Regs, AddrDisc);
+    }
   };
 
   // Helper for emitting AUTRELLOADPAC: increment Pointer by Addend and then by
@@ -2358,24 +2362,9 @@ void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer,
                      .addImm(0));
 }
 
-void AArch64AsmPrinter::emitPtrauthAuthResign(
-    Register Pointer, Register Scratch, PtrAuthSchema AuthSchema,
-    std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
-    Value *DS) {
-  const bool IsResign = SignSchema.has_value();
-  const bool WithPC = AuthSchema.PCDisc != AArch64::NoRegister;
-  assert(!SignSchema || SignSchema->PCDisc == AArch64::NoRegister);
-
-  // We expand AUT/AUTPAC (and their PC-blending variants) into:
-  //
-  //      ; authenticate Pointer
-  //      ; check Pointer
-  //    Lsuccess:
-  //      ; sign Pointer (if resign)
-  //    Lend:   ; if not trapping on failure
-  //
-  // with the checking sequence chosen depending on whether/how we should check
-  // the pointer and whether we should trap on failure.
+static std::pair<bool, bool> getCheckAndTrapMode(const MachineFunction *MF,
+                                                 bool IsResign) {
+  const AArch64Subtarget &STI = MF->getSubtarget<AArch64Subtarget>();
 
   // By default, auth/resign sequences check for auth failures.
   bool ShouldCheck = true;
@@ -2384,7 +2373,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
 
   // On an FPAC CPU, you get traps whether you want them or not: there's
   // no point in emitting checks or traps.
-  if (STI->hasFPAC())
+  if (STI.hasFPAC())
     ShouldCheck = ShouldTrap = false;
 
   // However, command-line flags can override this, for experimentation.
@@ -2403,6 +2392,52 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
     break;
   }
 
+  // Checked-but-not-trapping mode ("poison") only applies to resigning,
+  // replace with "unchecked" for standalone AUT.
+  if (!IsResign && ShouldCheck && !ShouldTrap)
+    ShouldCheck = ShouldTrap = false;
+
+  return std::make_pair(ShouldCheck, ShouldTrap);
+}
+
+// We expand AUTx16x17/AUTxMxN into a sequence of the form
+//
+//      ; authenticate Pointer
+//      ; check that Pointer is valid (optional, traps on failure)
+//
+// We expand AUTPAC into a sequence of the form
+//
+//      ; authenticate Pointer
+//      ; check that Pointer is valid (optional, traps on failure)
+//      ; load addend and add it to Pointer (if OptAddend)
+//      ; sign Pointer
+//
+// or
+//
+//      ; authenticate Pointer
+//      ; check that Pointer is valid (skips re-sign on failure)
+//      ; load addend and add it to Pointer (if OptAddend)
+//      ; sign Pointer
+//    Lon_failure:
+//
+void AArch64AsmPrinter::emitPtrauthAuthResign(
+    Register Pointer, Register Scratch, PtrAuthSchema AuthSchema,
+    std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
+    Value *DS) {
+  const bool IsResign = SignSchema.has_value();
+  const bool WithPC = AuthSchema.PCDisc != AArch64::NoRegister;
+  assert(!SignSchema || SignSchema->PCDisc == AArch64::NoRegister);
+
+  Register SignAddrDiscOrNone =
+      SignSchema ? SignSchema->AddrDisc : AArch64::NoRegister;
+
+  const auto [ShouldCheck, ShouldTrap] = getCheckAndTrapMode(MF, IsResign);
+  assert((ShouldCheck || !ShouldTrap) && "ShouldTrap implies ShouldCheck");
+
+  MCSymbol *OnFailure = nullptr;
+  if (ShouldCheck && !ShouldTrap)
+    OnFailure = createTempSymbol("resign_end_");
+
   if (WithPC) {
     assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 &&
            "AUTPCPAC must use x17/x16 as Pointer/Scratch");
@@ -2426,46 +2461,39 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
       EmitToStreamer(MCInstBuilder(AutOpc));
     }
   } else {
-    // Standard AUT: discriminator computed into Scratch, then auti[ab].
-    Register AUTDiscReg =
-        emitPtrauthDiscriminator(AuthSchema.IntDisc, AuthSchema.AddrDisc,
-                                 Scratch, AuthSchema.AddrDiscIsKilled);
+    // While rather unlikely, it is technically possible to use the Pointer to
+    // compute its own discriminator.
+    // AuthSchema.AddrDisc may be clobbered by emitPtrauthDiscriminator as long
+    // as it is not used past this point neither externally (the register
+    // operand is "killed"), nor internally (it does not alias anything being
+    // used later).
+    Register AUTDiscReg = emitPtrauthDiscriminator(
+        AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch,
+        AuthSchema.addrDiscIsKilledAndNoneOf({Pointer, SignAddrDiscOrNone}));
     if (!emitDeactivationSymbolRelocation(DS))
       emitAUT(AuthSchema.Key, Pointer, AUTDiscReg);
   }
 
-  // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done.
-  if (!IsResign && (!ShouldCheck || !ShouldTrap))
-    return;
-
-  MCSymbol *EndSym = nullptr;
-
-  if (ShouldCheck) {
-    if (IsResign && !ShouldTrap)
-      EndSym = createTempSymbol("resign_end_");
-
+  if (ShouldCheck)
     emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key,
                                        AArch64PAuth::AuthCheckMethod::XPAC,
-                                       EndSym);
-  }
+                                       OnFailure);
 
-  // We already emitted unchecked and checked-but-non-trapping AUTs.
-  // That left us with trapping AUTs, and AUTPAC/AUTRELLOADPACs.
-  // Trapping AUTs don't need PAC: we're done.
-  if (!IsResign)
+  if (!IsResign) {
+    assert(!OnFailure && "Poison mode only applies to resigning");
     return;
+  }
 
   if (Addend.has_value())
     emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
 
-  // Compute PAC discriminator into Scratch, then re-sign Pointer.
-  Register PACDiscReg = emitPtrauthDiscriminator(SignSchema->IntDisc,
-                                                 SignSchema->AddrDisc, Scratch);
+  Register PACDiscReg = emitPtrauthDiscriminator(
+      SignSchema->IntDisc, SignSchema->AddrDisc, Scratch,
+      SignSchema->addrDiscIsKilledAndNoneOf({Pointer}));
   emitPAC(SignSchema->Key, Pointer, PACDiscReg);
 
-  //  Lend:
-  if (EndSym)
-    OutStreamer->emitLabel(EndSym);
+  if (OnFailure)
+    OutStreamer->emitLabel(OnFailure);
 }
 
 void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) {
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
index a56921d008712..16263be6ace30 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
@@ -1,4 +1,3 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0                    -verify-machineinstrs \
 ; RUN:   -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefixes=UNCHECKED,UNCHECKED-DARWIN
 ; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
@@ -89,12 +88,14 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
 ; UNCHECKED-NEXT:    mov x16, x0
 ; UNCHECKED-ELF-NEXT:    movk x1, #12345, lsl #48
 ; UNCHECKED-ELF-NEXT:    autda x16, x1
+; UNCHECKED-ELF-NEXT:    movk x2, #56789, lsl #48
+; UNCHECKED-ELF-NEXT:    pacdb x16, x2
 ; UNCHECKED-DARWIN-NEXT: mov x17, x1
 ; UNCHECKED-DARWIN-NEXT: movk x17, #12345, lsl #48
 ; UNCHECKED-DARWIN-NEXT: autda x16, x17
-; UNCHECKED-NEXT:    mov x17, x2
-; UNCHECKED-NEXT:    movk x17, #56789, lsl #48
-; UNCHECKED-NEXT:    pacdb x16, x17
+; UNCHECKED-DARWIN-NEXT: mov x17, x2
+; UNCHECKED-DARWIN-NEXT: movk x17, #56789, lsl #48
+; UNCHECKED-DARWIN-NEXT: pacdb x16, x17
 ; UNCHECKED-NEXT:    mov x0, x16
 ; UNCHECKED-NEXT:    ret
 ;
@@ -113,9 +114,11 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
 ; CHECKED-NEXT:    mov x16, x17
 ; CHECKED-NEXT:    b [[L]]resign_end_0
 ; CHECKED-NEXT:  Lauth_success_0:
-; CHECKED-NEXT:    mov x17, x2
-; CHECKED-NEXT:    movk x17, #56789, lsl #48
-; CHECKED-NEXT:    pacdb x16, x17
+; CHECKED-ELF-NEXT:    movk x2, #56789, lsl #48
+; CHECKED-ELF-NEXT:    pacdb x16, x2
+; CHECKED-DARWIN-NEXT: mov x17, x2
+; CHECKED-DARWIN-NEXT: movk x17, #56789, lsl #48
+; CHECKED-DARWIN-NEXT: pacdb x16, x17
 ; CHECKED-NEXT:  Lresign_end_0:
 ; CHECKED-NEXT:    mov x0, x16
 ; CHECKED-NEXT:    ret
@@ -134,9 +137,11 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
 ; TRAP-NEXT:    b.eq [[L]]auth_success_1
 ; TRAP-NEXT:    brk #0xc472
 ; TRAP-NEXT:  Lauth_success_1:
-; TRAP-NEXT:    mov x17, x2
-; TRAP-NEXT:    movk x17, #56789, lsl #48
-; TRAP-NEXT:    pacdb x16, x17
+; TRAP-ELF-NEXT:    movk x2, #56789, lsl #48
+; TRAP-ELF-NEXT:    pacdb x16, x2
+; TRAP-DARWIN-NEXT: mov x17, x2
+; TRAP-DARWIN-NEXT: movk x17, #56789, lsl #48
+; TRAP-DARWIN-NEXT: pacdb x16, x17
 ; TRAP-NEXT:    mov x0, x16
 ; TRAP-NEXT:    ret
   %tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 12345)
@@ -326,6 +331,58 @@ some.other.bb:
   ret i64 %authed
 }
 
+; As long as we support raw, non-blended 64-bit discriminators (which might be
+; useful for low-level code such as dynamic loaders), the "auth" part of resign
+; must not clobber %arg, if its upper bits are later used by the "sign" part.
+define i64 @test_resign_aliased_discs_raw_sign_disc(i64 %p, i64 %arg) {
+; UNCHECKED-LABEL: test_resign_aliased_discs_raw_sign_disc:
+; UNCHECKED:       %bb.0:
+; UNCHECKED-NEXT:    mov x16, x0
+; UNCHECKED-NEXT:    mov  x17, x1
+; UNCHECKED-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-NEXT:    autda x16, x17
+; UNCHECKED-NEXT:    pacdb x16, x1
+; UNCHECKED-NEXT:    mov x0, x16
+; UNCHECKED-NEXT:    ret
+;
+; CHECKED-LABEL: test_resign_aliased_discs_raw_sign_disc:
+; CHECKED:       %bb.0:
+; CHECKED-NEXT:    mov x16, x0
+; CHECKED-NEXT:    mov  x17, x1
+; CHECKED-NEXT:    movk x17, #12345, lsl #48
+; CHECKED-NEXT:    autda x16, x17
+; CHECKED-NEXT:    mov x17, x16
+; CHECKED-NEXT:    xpacd x17
+; CHECKED-NEXT:    cmp x16, x17
+; CHECKED-NEXT:    b.eq [[L]]auth_success_3
+; CHECKED-NEXT:    mov x16, x17
+; CHECKED-NEXT:    b [[L]]resign_end_3
+; CHECKED-NEXT:  Lauth_success_3:
+; CHECKED-NEXT:    pacdb x16, x1
+; CHECKED-NEXT:  Lresign_end_3:
+; CHECKED-NEXT:    mov x0, x16
+; CHECKED-NEXT:    ret
+;
+; TRAP-LABEL: test_resign_aliased_discs_raw_sign_disc:
+; TRAP:       %bb.0:
+; TRAP-NEXT:    mov x16, x0
+; TRAP-NEXT:    mov  x17, x1
+; TRAP-NEXT:    movk x17, #12345, lsl #48
+; TRAP-NEXT:    autda x16, x17
+; TRAP-NEXT:    mov x17, x16
+; TRAP-NEXT:    xpacd x17
+; TRAP-NEXT:    cmp x16, x17
+; TRAP-NEXT:    b.eq [[L]]auth_success_6
+; TRAP-NEXT:    brk #0xc472
+; TRAP-NEXT:  Lauth_success_6:
+; TRAP-NEXT:    pacdb x16, x1
+; TRAP-NEXT:    mov x0, x16
+; TRAP-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345)
+  %res = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %arg)
+  ret i64 %res
+}
+
 declare i64 @llvm.ptrauth.auth(i64, i32, i64)
 declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)
 declare i64 @llvm.ptrauth.blend(i64, i64)

>From 4a0d7733c9fdcbf2d80ccb3b7db74f6922a5e65f Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 9 Jul 2026 18:55:28 +0300
Subject: [PATCH 2/4] Use enum instead of a pair of boolean variables

---
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 139 +++++++++---------
 1 file changed, 71 insertions(+), 68 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index 11361871cecd4..d4a3aa0eca48c 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -82,14 +82,13 @@ STATISTIC(NumZCZeroingInstrsFPR,
           "Number of zero-cycle FPR zeroing instructions expanded from "
           "canonical pseudo instructions");
 
-enum PtrauthCheckMode { Default, Unchecked, Poison, Trap };
+enum PtrauthCheckMode { Unchecked, Poison, Trap };
 static cl::opt<PtrauthCheckMode> PtrauthAuthChecks(
     "aarch64-ptrauth-auth-checks", cl::Hidden,
     cl::values(clEnumValN(Unchecked, "none", "don't test for failure"),
                clEnumValN(Poison, "poison", "poison on failure"),
                clEnumValN(Trap, "trap", "trap on failure")),
-    cl::desc("Check pointer authentication auth/resign failures"),
-    cl::init(Default));
+    cl::desc("Check pointer authentication auth/resign failures"));
 
 namespace {
 
@@ -2362,83 +2361,65 @@ void AArch64AsmPrinter::emitPtrauthApplyIndirectAddend(Register Pointer,
                      .addImm(0));
 }
 
-static std::pair<bool, bool> getCheckAndTrapMode(const MachineFunction *MF,
-                                                 bool IsResign) {
+static PtrauthCheckMode getCheckMode(const MachineFunction *MF) {
   const AArch64Subtarget &STI = MF->getSubtarget<AArch64Subtarget>();
 
-  // By default, auth/resign sequences check for auth failures.
-  bool ShouldCheck = true;
-  // In the checked sequence, we only trap if explicitly requested.
-  bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
+  // If an override is passed via command line argument, just use that value.
+  if (PtrauthAuthChecks.getNumOccurrences())
+    return PtrauthAuthChecks;
 
-  // On an FPAC CPU, you get traps whether you want them or not: there's
-  // no point in emitting checks or traps.
+  // Otherwise, on an FPAC CPU, you get traps whether you want them or not:
+  // there's no point in emitting checks or traps.
   if (STI.hasFPAC())
-    ShouldCheck = ShouldTrap = false;
-
-  // However, command-line flags can override this, for experimentation.
-  switch (PtrauthAuthChecks) {
-  case PtrauthCheckMode::Default:
-    break;
-  case PtrauthCheckMode::Unchecked:
-    ShouldCheck = ShouldTrap = false;
-    break;
-  case PtrauthCheckMode::Poison:
-    ShouldCheck = true;
-    ShouldTrap = false;
-    break;
-  case PtrauthCheckMode::Trap:
-    ShouldCheck = ShouldTrap = true;
-    break;
-  }
+    return PtrauthCheckMode::Unchecked;
 
-  // Checked-but-not-trapping mode ("poison") only applies to resigning,
-  // replace with "unchecked" for standalone AUT.
-  if (!IsResign && ShouldCheck && !ShouldTrap)
-    ShouldCheck = ShouldTrap = false;
-
-  return std::make_pair(ShouldCheck, ShouldTrap);
+  bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps");
+  return ShouldTrap ? PtrauthCheckMode::Trap : PtrauthCheckMode::Poison;
 }
 
-// We expand AUTx16x17/AUTxMxN into a sequence of the form
+// We expand AUT* pseudo instructions into a sequence of the form
+//
+//      ; 1. Authenticate Pointer
 //
-//      ; authenticate Pointer
-//      ; check that Pointer is valid (optional, traps on failure)
+// or
+//
+//      ; 1. Authenticate Pointer
+//      ; 2. Check that Pointer is valid, trap otherwise
 //
-// We expand AUTPAC into a sequence of the form
+// We expand AUT*PAC pseudo instructions into a sequence of the form
+// (with addend only applied if Addend argument is given):
 //
-//      ; authenticate Pointer
-//      ; check that Pointer is valid (optional, traps on failure)
-//      ; load addend and add it to Pointer (if OptAddend)
-//      ; sign Pointer
+//      ; 1. Authenticate Pointer
+//      ; 3. Apply addend and sign Pointer
 //
 // or
 //
-//      ; authenticate Pointer
-//      ; check that Pointer is valid (skips re-sign on failure)
-//      ; load addend and add it to Pointer (if OptAddend)
-//      ; sign Pointer
-//    Lon_failure:
+//      ; 1. Authenticate Pointer
+//      ; 2. Check that Pointer is valid, trap otherwise
+//      ; 3. Apply addend and sign Pointer
+//
+// or
+//
+//      ; 1. Authenticate Pointer
+//      ; 2. Check that Pointer is valid, jump to .Lon_failure otherwise
+//      ; 3. Apply addend and sign Pointer
+//    .Lon_failure:
 //
 void AArch64AsmPrinter::emitPtrauthAuthResign(
     Register Pointer, Register Scratch, PtrAuthSchema AuthSchema,
     std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
     Value *DS) {
-  const bool IsResign = SignSchema.has_value();
-  const bool WithPC = AuthSchema.PCDisc != AArch64::NoRegister;
+  const PtrauthCheckMode CheckMode = getCheckMode(MF);
+  const bool AuthWithPC = AuthSchema.PCDisc != AArch64::NoRegister;
   assert(!SignSchema || SignSchema->PCDisc == AArch64::NoRegister);
 
   Register SignAddrDiscOrNone =
       SignSchema ? SignSchema->AddrDisc : AArch64::NoRegister;
 
-  const auto [ShouldCheck, ShouldTrap] = getCheckAndTrapMode(MF, IsResign);
-  assert((ShouldCheck || !ShouldTrap) && "ShouldTrap implies ShouldCheck");
-
-  MCSymbol *OnFailure = nullptr;
-  if (ShouldCheck && !ShouldTrap)
-    OnFailure = createTempSymbol("resign_end_");
+  // 1. Authenticate Pointer - this is the only common step.
+  // It is more complex than signing because AUTI[AB]171615 may be used.
 
-  if (WithPC) {
+  if (AuthWithPC) {
     assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 &&
            "AUTPCPAC must use x17/x16 as Pointer/Scratch");
 
@@ -2474,26 +2455,48 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
       emitAUT(AuthSchema.Key, Pointer, AUTDiscReg);
   }
 
-  if (ShouldCheck)
+  // The other two steps are optional, define lambdas for them:
+  // 2. Check That Pointer is valid, on failure jump to label or trap.
+  auto EmitCheck = [&](MCSymbol *OnFailure = nullptr) {
     emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key,
                                        AArch64PAuth::AuthCheckMethod::XPAC,
                                        OnFailure);
+  };
+  // 3. Apply addend and sign Pointer.
+  auto EmitResignOnSuccess = [&]() {
+    if (Addend.has_value())
+      emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
+
+    Register PACDiscReg = emitPtrauthDiscriminator(
+        SignSchema->IntDisc, SignSchema->AddrDisc, Scratch,
+        SignSchema->addrDiscIsKilledAndNoneOf({Pointer}));
+    emitPAC(SignSchema->Key, Pointer, PACDiscReg);
+  };
+
+  // Emit checking and resigning as needed.
 
-  if (!IsResign) {
-    assert(!OnFailure && "Poison mode only applies to resigning");
+  if (!SignSchema) {
+    if (CheckMode == PtrauthCheckMode::Trap)
+      EmitCheck();
+    // For authentication-only pseudos, Poison is demoted to Unchecked.
     return;
   }
 
-  if (Addend.has_value())
-    emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
-
-  Register PACDiscReg = emitPtrauthDiscriminator(
-      SignSchema->IntDisc, SignSchema->AddrDisc, Scratch,
-      SignSchema->addrDiscIsKilledAndNoneOf({Pointer}));
-  emitPAC(SignSchema->Key, Pointer, PACDiscReg);
-
-  if (OnFailure)
+  switch (CheckMode) {
+  case Unchecked:
+    EmitResignOnSuccess();
+    break;
+  case Trap:
+    EmitCheck();
+    EmitResignOnSuccess();
+    break;
+  case Poison:
+    MCSymbol *OnFailure = createTempSymbol("resign_end_");
+    EmitCheck(OnFailure);
+    EmitResignOnSuccess();
     OutStreamer->emitLabel(OnFailure);
+    break;
+  }
 }
 
 void AArch64AsmPrinter::emitPtrauthSign(const MachineInstr *MI) {

>From 2c1939595588e407297ce1a5910a1bfb848c58dc Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Fri, 10 Jul 2026 19:32:00 +0300
Subject: [PATCH 3/4] Add more test cases; other minor changes

---
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp |  18 +-
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   6 +
 ...trauth-intrinsic-auth-resign-with-blend.ll | 388 +++++++++++++++++-
 3 files changed, 398 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index d4a3aa0eca48c..a518bdf69c2da 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -2377,7 +2377,7 @@ static PtrauthCheckMode getCheckMode(const MachineFunction *MF) {
   return ShouldTrap ? PtrauthCheckMode::Trap : PtrauthCheckMode::Poison;
 }
 
-// We expand AUT* pseudo instructions into a sequence of the form
+// We expand non-signing AUT* pseudo instructions into a sequence of the form
 //
 //      ; 1. Authenticate Pointer
 //
@@ -2442,12 +2442,13 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
       EmitToStreamer(MCInstBuilder(AutOpc));
     }
   } else {
-    // While rather unlikely, it is technically possible to use the Pointer to
-    // compute its own discriminator.
-    // AuthSchema.AddrDisc may be clobbered by emitPtrauthDiscriminator as long
-    // as it is not used past this point neither externally (the register
+    // emitPtrauthDiscriminator is allowed to clobber AuthSchema.AddrDisc as
+    // long as it is not used past this point neither externally (the register
     // operand is "killed"), nor internally (it does not alias anything being
     // used later).
+    //
+    // Note that, while rather unlikely, it is technically possible to use the
+    // Pointer to compute its own discriminator.
     Register AUTDiscReg = emitPtrauthDiscriminator(
         AuthSchema.IntDisc, AuthSchema.AddrDisc, Scratch,
         AuthSchema.addrDiscIsKilledAndNoneOf({Pointer, SignAddrDiscOrNone}));
@@ -2467,9 +2468,10 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
     if (Addend.has_value())
       emitPtrauthApplyIndirectAddend(Pointer, Scratch, *Addend);
 
-    Register PACDiscReg = emitPtrauthDiscriminator(
-        SignSchema->IntDisc, SignSchema->AddrDisc, Scratch,
-        SignSchema->addrDiscIsKilledAndNoneOf({Pointer}));
+    assert(Pointer != SignSchema->AddrDisc && "Pointer is early-clobbered");
+    Register PACDiscReg =
+        emitPtrauthDiscriminator(SignSchema->IntDisc, SignSchema->AddrDisc,
+                                 Scratch, SignSchema->AddrDiscIsKilled);
     emitPAC(SignSchema->Key, Pointer, PACDiscReg);
   };
 
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 51fb2e1d1f9f0..afa5e1ece6425 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2267,6 +2267,8 @@ let Predicates = [HasPAuth] in {
                (ins i32imm:$AUTKey, i64imm:$AUTDisc, GPR64noip:$AUTAddrDisc,
                     i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc),
                []>, Sched<[WriteI, ReadI]> {
+    // Thanks to its register class, $PACAddrDisc never aliases X16 which is
+    // early-clobbered.
     let isCodeGenOnly = 1;
     let hasSideEffects = 1;
     let mayStore = 0;
@@ -2288,6 +2290,8 @@ let Predicates = [HasPAuth] in {
                (ins i32imm:$AUTKey,
                     i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc),
                []>, Sched<[WriteI, ReadI]> {
+    // Thanks to its register class, $PACAddrDisc never aliases X16 which is
+    // early-clobbered.
     let isCodeGenOnly = 1;
     let hasSideEffects = 1;
     let mayStore = 0;
@@ -2308,6 +2312,8 @@ let Predicates = [HasPAuth] in {
                    i64imm:$Addend),
                []>,
         Sched<[WriteI, ReadI]> {
+    // Thanks to its register class, $PACAddrDisc never aliases X16 which is
+    // early-clobbered.
     let isCodeGenOnly = 1;
     let hasSideEffects = 1;
     let mayStore = 0;
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
index 16263be6ace30..1dea85aba7fa7 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
@@ -331,6 +331,216 @@ some.other.bb:
   ret i64 %authed
 }
 
+define void @test_auth_live_addrdisc(i64 %p, i64 %arg, ptr %out) {
+; UNCHECKED-DARWIN-LABEL: test_auth_live_addrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov     x16, x0
+; UNCHECKED-DARWIN-NEXT:    mov     x17, x1
+; UNCHECKED-DARWIN-NEXT:    movk    x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT:    autda   x16, x17
+; UNCHECKED-DARWIN-NEXT:    str     x16, [x2]
+; UNCHECKED-DARWIN-NEXT:    str     x1, [x2]
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+; UNCHECKED-ELF-LABEL: test_auth_live_addrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov     x8, x1
+; UNCHECKED-ELF-NEXT:    movk    x8, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda   x0, x8
+; UNCHECKED-ELF-NEXT:    str     x0, [x2]
+; UNCHECKED-ELF-NEXT:    str     x1, [x2]
+; UNCHECKED-ELF-NEXT:    ret
+;
+; CHECKED-DARWIN-LABEL: test_auth_live_addrdisc:
+; CHECKED-DARWIN:       %bb.0:
+; CHECKED-DARWIN-NEXT:    mov     x16, x0
+; CHECKED-DARWIN-NEXT:    mov     x17, x1
+; CHECKED-DARWIN-NEXT:    movk    x17, #12345, lsl #48
+; CHECKED-DARWIN-NEXT:    autda   x16, x17
+; CHECKED-DARWIN-NEXT:    str     x16, [x2]
+; CHECKED-DARWIN-NEXT:    str     x1, [x2]
+; CHECKED-DARWIN-NEXT:    ret
+;
+; CHECKED-ELF-LABEL: test_auth_live_addrdisc:
+; CHECKED-ELF:       %bb.0:
+; CHECKED-ELF-NEXT:    mov     x8, x1
+; CHECKED-ELF-NEXT:    movk    x8, #12345, lsl #48
+; CHECKED-ELF-NEXT:    autda   x0, x8
+; CHECKED-ELF-NEXT:    str     x0, [x2]
+; CHECKED-ELF-NEXT:    str     x1, [x2]
+; CHECKED-ELF-NEXT:    ret
+;
+; TRAP-DARWIN-LABEL: test_auth_live_addrdisc:
+; TRAP-DARWIN:       %bb.0:
+; TRAP-DARWIN-NEXT:    mov     x16, x0
+; TRAP-DARWIN-NEXT:    mov     x17, x1
+; TRAP-DARWIN-NEXT:    movk    x17, #12345, lsl #48
+; TRAP-DARWIN-NEXT:    autda   x16, x17
+; TRAP-DARWIN-NEXT:    mov     x17, x16
+; TRAP-DARWIN-NEXT:    xpacd   x17
+; TRAP-DARWIN-NEXT:    cmp     x16, x17
+; TRAP-DARWIN-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; TRAP-DARWIN-NEXT:    brk     #0xc472
+; TRAP-DARWIN-NEXT:  [[L]]auth_success_[[N]]:
+; TRAP-DARWIN-NEXT:    str     x16, [x2]
+; TRAP-DARWIN-NEXT:    str     x1, [x2]
+; TRAP-DARWIN-NEXT:    ret
+;
+; TRAP-ELF-LABEL: test_auth_live_addrdisc:
+; TRAP-ELF:       %bb.0:
+; TRAP-ELF-NEXT:    mov     x8, x1
+; TRAP-ELF-NEXT:    movk    x8, #12345, lsl #48
+; TRAP-ELF-NEXT:    autda   x0, x8
+; TRAP-ELF-NEXT:    mov     x8, x0
+; TRAP-ELF-NEXT:    xpacd   x8
+; TRAP-ELF-NEXT:    cmp     x0, x8
+; TRAP-ELF-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; TRAP-ELF-NEXT:    brk     #0xc472
+; TRAP-ELF-NEXT:  [[L]]auth_success_[[N]]:
+; TRAP-ELF-NEXT:    str     x0, [x2]
+; TRAP-ELF-NEXT:    str     x1, [x2]
+; TRAP-ELF-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345)
+  %authed = call i64 @llvm.ptrauth.auth(i64 %p, i32 2, i64 %auth.disc)
+  store volatile i64 %authed, ptr %out
+  store volatile i64 %arg, ptr %out
+  ret void
+}
+
+define void @test_resign_live_autaddrdisc(i64 %p, i64 %auth.arg, i64 %sign.arg, ptr %out) {
+; UNCHECKED-LABEL: test_resign_live_autaddrdisc:
+; UNCHECKED:       %bb.0:
+; UNCHECKED-NEXT:    mov     x16, x0
+; UNCHECKED-NEXT:    mov     x17, x1
+; UNCHECKED-NEXT:    movk    x17, #12345, lsl #48
+; UNCHECKED-NEXT:    autda   x16, x17
+; UNCHECKED-DARWIN-NEXT: mov     x17, x2
+; UNCHECKED-DARWIN-NEXT: movk    x17, #54321, lsl #48
+; UNCHECKED-DARWIN-NEXT: pacdb   x16, x17
+; UNCHECKED-ELF-NEXT:    movk    x2, #54321, lsl #48
+; UNCHECKED-ELF-NEXT:    pacdb   x16, x2
+; UNCHECKED-NEXT:    str     x16, [x3]
+; UNCHECKED-NEXT:    str     x1, [x3]
+; UNCHECKED-NEXT:    ret
+;
+; CHECKED-LABEL: test_resign_live_autaddrdisc:
+; CHECKED:       %bb.0:
+; CHECKED-NEXT:    mov     x16, x0
+; CHECKED-NEXT:    mov     x17, x1
+; CHECKED-NEXT:    movk    x17, #12345, lsl #48
+; CHECKED-NEXT:    autda   x16, x17
+; CHECKED-NEXT:    mov     x17, x16
+; CHECKED-NEXT:    xpacd   x17
+; CHECKED-NEXT:    cmp     x16, x17
+; CHECKED-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; CHECKED-NEXT:    mov     x16, x17
+; CHECKED-NEXT:    b       [[L]]resign_end_[[N]]
+; CHECKED-NEXT:  [[L]]auth_success_[[N]]:
+; CHECKED-DARWIN-NEXT: mov     x17, x2
+; CHECKED-DARWIN-NEXT: movk    x17, #54321, lsl #48
+; CHECKED-DARWIN-NEXT: pacdb   x16, x17
+; CHECKED-ELF-NEXT:    movk    x2, #54321, lsl #48
+; CHECKED-ELF-NEXT:    pacdb   x16, x2
+; CHECKED-NEXT:  [[L]]resign_end_[[N]]:
+; CHECKED-NEXT:    str     x16, [x3]
+; CHECKED-NEXT:    str     x1, [x3]
+; CHECKED-NEXT:    ret
+;
+; TRAP-LABEL: test_resign_live_autaddrdisc:
+; TRAP:       %bb.0:
+; TRAP-NEXT:    mov     x16, x0
+; TRAP-NEXT:    mov     x17, x1
+; TRAP-NEXT:    movk    x17, #12345, lsl #48
+; TRAP-NEXT:    autda   x16, x17
+; TRAP-NEXT:    mov     x17, x16
+; TRAP-NEXT:    xpacd   x17
+; TRAP-NEXT:    cmp     x16, x17
+; TRAP-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; TRAP-NEXT:    brk     #0xc472
+; TRAP-NEXT:  [[L]]auth_success_[[N]]:
+; TRAP-DARWIN-NEXT: mov     x17, x2
+; TRAP-DARWIN-NEXT: movk    x17, #54321, lsl #48
+; TRAP-DARWIN-NEXT: pacdb   x16, x17
+; TRAP-ELF-NEXT:    movk    x2, #54321, lsl #48
+; TRAP-ELF-NEXT:    pacdb   x16, x2
+; TRAP-NEXT:    str     x16, [x3]
+; TRAP-NEXT:    str     x1, [x3]
+; TRAP-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %auth.arg, i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %sign.arg, i64 54321)
+  %resigned = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  store volatile i64 %resigned, ptr %out
+  store volatile i64 %auth.arg, ptr %out
+  ret void
+}
+
+define void @test_resign_live_pacaddrdisc(i64 %p, i64 %auth.arg, i64 %sign.arg, ptr %out) {
+; UNCHECKED-LABEL: test_resign_live_pacaddrdisc:
+; UNCHECKED:       %bb.0:
+; UNCHECKED-NEXT:    mov     x16, x0
+; UNCHECKED-DARWIN-NEXT: mov     x17, x1
+; UNCHECKED-DARWIN-NEXT: movk    x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT: autda   x16, x17
+; UNCHECKED-ELF-NEXT:    movk    x1, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda   x16, x1
+; UNCHECKED-NEXT:    mov     x17, x2
+; UNCHECKED-NEXT:    movk    x17, #54321, lsl #48
+; UNCHECKED-NEXT:    pacdb   x16, x17
+; UNCHECKED-NEXT:    str     x16, [x3]
+; UNCHECKED-NEXT:    str     x2, [x3]
+; UNCHECKED-NEXT:    ret
+;
+; CHECKED-LABEL: test_resign_live_pacaddrdisc:
+; CHECKED:       %bb.0:
+; CHECKED-NEXT:    mov     x16, x0
+; CHECKED-DARWIN-NEXT: mov     x17, x1
+; CHECKED-DARWIN-NEXT: movk    x17, #12345, lsl #48
+; CHECKED-DARWIN-NEXT: autda   x16, x17
+; CHECKED-ELF-NEXT:    movk    x1, #12345, lsl #48
+; CHECKED-ELF-NEXT:    autda   x16, x1
+; CHECKED-NEXT:    mov     x17, x16
+; CHECKED-NEXT:    xpacd   x17
+; CHECKED-NEXT:    cmp     x16, x17
+; CHECKED-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; CHECKED-NEXT:    mov     x16, x17
+; CHECKED-NEXT:    b       [[L]]resign_end_[[N]]
+; CHECKED-NEXT:  [[L]]auth_success_[[N]]:
+; CHECKED-NEXT:    mov     x17, x2
+; CHECKED-NEXT:    movk    x17, #54321, lsl #48
+; CHECKED-NEXT:    pacdb   x16, x17
+; CHECKED-NEXT:  [[L]]resign_end_[[N]]:
+; CHECKED-NEXT:    str     x16, [x3]
+; CHECKED-NEXT:    str     x2, [x3]
+; CHECKED-NEXT:    ret
+;
+; TRAP-LABEL: test_resign_live_pacaddrdisc:
+; TRAP:       %bb.0:
+; TRAP-NEXT:    mov     x16, x0
+; TRAP-DARWIN-NEXT: mov     x17, x1
+; TRAP-DARWIN-NEXT: movk    x17, #12345, lsl #48
+; TRAP-DARWIN-NEXT: autda   x16, x17
+; TRAP-ELF-NEXT:    movk    x1, #12345, lsl #48
+; TRAP-ELF-NEXT:    autda   x16, x1
+; TRAP-NEXT:    mov     x17, x16
+; TRAP-NEXT:    xpacd   x17
+; TRAP-NEXT:    cmp     x16, x17
+; TRAP-NEXT:    b.eq    [[L]]auth_success_[[N:[0-9]+]]
+; TRAP-NEXT:    brk     #0xc472
+; TRAP-NEXT:  [[L]]auth_success_[[N]]:
+; TRAP-NEXT:    mov     x17, x2
+; TRAP-NEXT:    movk    x17, #54321, lsl #48
+; TRAP-NEXT:    pacdb   x16, x17
+; TRAP-NEXT:    str     x16, [x3]
+; TRAP-NEXT:    str     x2, [x3]
+; TRAP-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %auth.arg, i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %sign.arg, i64 54321)
+  %resigned = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  store volatile i64 %resigned, ptr %out
+  store volatile i64 %sign.arg, ptr %out
+  ret void
+}
+
 ; As long as we support raw, non-blended 64-bit discriminators (which might be
 ; useful for low-level code such as dynamic loaders), the "auth" part of resign
 ; must not clobber %arg, if its upper bits are later used by the "sign" part.
@@ -354,12 +564,12 @@ define i64 @test_resign_aliased_discs_raw_sign_disc(i64 %p, i64 %arg) {
 ; CHECKED-NEXT:    mov x17, x16
 ; CHECKED-NEXT:    xpacd x17
 ; CHECKED-NEXT:    cmp x16, x17
-; CHECKED-NEXT:    b.eq [[L]]auth_success_3
+; CHECKED-NEXT:    b.eq [[L]]auth_success_[[N:[0-9]+]]
 ; CHECKED-NEXT:    mov x16, x17
-; CHECKED-NEXT:    b [[L]]resign_end_3
-; CHECKED-NEXT:  Lauth_success_3:
+; CHECKED-NEXT:    b [[L]]resign_end_[[N]]
+; CHECKED-NEXT:  Lauth_success_[[N]]:
 ; CHECKED-NEXT:    pacdb x16, x1
-; CHECKED-NEXT:  Lresign_end_3:
+; CHECKED-NEXT:  Lresign_end_[[N]]:
 ; CHECKED-NEXT:    mov x0, x16
 ; CHECKED-NEXT:    ret
 ;
@@ -372,9 +582,9 @@ define i64 @test_resign_aliased_discs_raw_sign_disc(i64 %p, i64 %arg) {
 ; TRAP-NEXT:    mov x17, x16
 ; TRAP-NEXT:    xpacd x17
 ; TRAP-NEXT:    cmp x16, x17
-; TRAP-NEXT:    b.eq [[L]]auth_success_6
+; TRAP-NEXT:    b.eq [[L]]auth_success_[[N:[0-9]+]]
 ; TRAP-NEXT:    brk #0xc472
-; TRAP-NEXT:  Lauth_success_6:
+; TRAP-NEXT:  Lauth_success_[[N]]:
 ; TRAP-NEXT:    pacdb x16, x1
 ; TRAP-NEXT:    mov x0, x16
 ; TRAP-NEXT:    ret
@@ -383,6 +593,172 @@ define i64 @test_resign_aliased_discs_raw_sign_disc(i64 %p, i64 %arg) {
   ret i64 %res
 }
 
+; The following are rather obscure corner cases of computing the discriminator
+; by blending the pointer-in-question itself as the address modifier.
+; For the sake of brevity, just check which registers are used to compute the
+; discriminators.
+;
+; Note: common logic in AArch64AsmPrinter handles $AUTAddrDisc, but $PACAddrDisc
+; must be described appropriately in AArch64InstrInfo.td for each pseudo
+; instruction to prevent aliasing with the pointer.
+
+define i64 @test_auth_pointer_aliased_with_addrdisc(i64 %p) {
+; UNCHECKED-DARWIN-LABEL: test_auth_pointer_aliased_with_addrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov  x16, x0
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x0
+; UNCHECKED-DARWIN-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT:    autda x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov   x0, x16
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+; UNCHECKED-ELF-LABEL: test_auth_pointer_aliased_with_addrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov  x8, x0
+; UNCHECKED-ELF-NEXT:    movk x8, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda x0, x8
+; UNCHECKED-ELF-NEXT:    ret
+  %disc = call i64 @llvm.ptrauth.blend(i64 %p, i64 12345)
+  %res = call i64 @llvm.ptrauth.auth(i64 %p, i32 2, i64 %disc)
+  ret i64 %res
+}
+
+define i64 @test_resign_pointer_aliased_with_autaddrdisc(i64 %p, i64 %arg) {
+; UNCHECKED-DARWIN-LABEL: test_resign_pointer_aliased_with_autaddrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov  x16, x0
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x0
+; UNCHECKED-DARWIN-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT:    autda x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x1
+; UNCHECKED-DARWIN-NEXT:    movk x17, #54321, lsl #48
+; UNCHECKED-DARWIN-NEXT:    pacdb x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov x0, x16
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+; UNCHECKED-ELF-LABEL: test_resign_pointer_aliased_with_autaddrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov  x16, x0
+; UNCHECKED-ELF-NEXT:    movk x0, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda x16, x0
+; UNCHECKED-ELF-NEXT:    movk x1, #54321, lsl #48
+; UNCHECKED-ELF-NEXT:    pacdb x16, x1
+; UNCHECKED-ELF-NEXT:    mov x0, x16
+; UNCHECKED-ELF-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %p,   i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 54321)
+  %res = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  ret i64 %res
+}
+
+define i64 @test_resign_pointer_aliased_with_pacaddrdisc(i64 %p, i64 %arg) {
+; UNCHECKED-DARWIN-LABEL: test_resign_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov x16, x0
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x1
+; UNCHECKED-DARWIN-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT:    autda x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x0
+; UNCHECKED-DARWIN-NEXT:    movk x17, #54321, lsl #48
+; UNCHECKED-DARWIN-NEXT:    pacdb x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov x0, x16
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+
+; UNCHECKED-ELF-LABEL: test_resign_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov x16, x0
+; UNCHECKED-ELF-NEXT:    movk x1, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda x16, x1
+; UNCHECKED-ELF-NEXT:    movk x0, #54321, lsl #48
+; UNCHECKED-ELF-NEXT:    pacdb x16, x0
+; UNCHECKED-ELF-NEXT:    mov x0, x16
+; UNCHECKED-ELF-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %p,   i64 54321)
+  %res = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  ret i64 %res
+}
+
+define i64 @test_resign_pointer_aliased_with_both_addrdisc(i64 %p) {
+; UNCHECKED-LABEL: test_resign_pointer_aliased_with_both_addrdisc:
+; UNCHECKED:       %bb.0:
+; UNCHECKED-NEXT:    mov  x16, x0
+; UNCHECKED-NEXT:    mov  x17, x0
+; UNCHECKED-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-NEXT:    autda x16, x17
+; UNCHECKED-NEXT:    mov  x17, x0
+; UNCHECKED-NEXT:    movk x17, #54321, lsl #48
+; UNCHECKED-NEXT:    pacdb x16, x17
+; UNCHECKED-NEXT:    mov x0, x16
+; UNCHECKED-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %p, i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %p, i64 54321)
+  %res = call i64 @llvm.ptrauth.resign(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  ret i64 %res
+}
+
+define i64 @test_autpcpac_pointer_aliased_with_pacaddrdisc(i64 %p, i64 %arg, i64 %auth.pc) {
+; UNCHECKED-DARWIN-LABEL: test_autpcpac_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x0
+; UNCHECKED-DARWIN-NEXT:    mov  x16, x1
+; UNCHECKED-DARWIN-NEXT:    mov  x15, x2
+; UNCHECKED-DARWIN-NEXT:    autia171615
+; UNCHECKED-DARWIN-NEXT:    mov  x16, x0
+; UNCHECKED-DARWIN-NEXT:    movk x16, #54321, lsl #48
+; UNCHECKED-DARWIN-NEXT:    pacib x17, x16
+; UNCHECKED-DARWIN-NEXT:    mov x0, x17
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+; UNCHECKED-ELF-LABEL: test_autpcpac_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov  x17, x0
+; UNCHECKED-ELF-NEXT:    mov  x16, x1
+; UNCHECKED-ELF-NEXT:    mov  x15, x2
+; UNCHECKED-ELF-NEXT:    autia171615
+; UNCHECKED-ELF-NEXT:    movk x0, #54321, lsl #48
+; UNCHECKED-ELF-NEXT:    pacib x17, x0
+; UNCHECKED-ELF-NEXT:    mov x0, x17
+; UNCHECKED-ELF-NEXT:    ret
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %p, i64 54321)
+  %res = call i64 @llvm.ptrauth.auth.with.pc.and.resign(i64 %p, i32 0, i64 %arg, i64 %auth.pc, i32 1, i64 %sign.disc)
+  ret i64 %res
+}
+
+define i64 @test_autrelloadpac_pointer_aliased_with_pacaddrdisc(i64 %p, i64 %arg) {
+; UNCHECKED-DARWIN-LABEL: test_autrelloadpac_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-DARWIN:       %bb.0:
+; UNCHECKED-DARWIN-NEXT:    mov  x16, x0
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x1
+; UNCHECKED-DARWIN-NEXT:    movk x17, #12345, lsl #48
+; UNCHECKED-DARWIN-NEXT:    autda x16, x17
+; UNCHECKED-DARWIN-NEXT:    ldrsw x17, [x16, #8]!
+; UNCHECKED-DARWIN-NEXT:    add   x16, x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov  x17, x0
+; UNCHECKED-DARWIN-NEXT:    movk x17, #54321, lsl #48
+; UNCHECKED-DARWIN-NEXT:    pacdb x16, x17
+; UNCHECKED-DARWIN-NEXT:    mov x0, x16
+; UNCHECKED-DARWIN-NEXT:    ret
+;
+
+; UNCHECKED-ELF-LABEL: test_autrelloadpac_pointer_aliased_with_pacaddrdisc:
+; UNCHECKED-ELF:       %bb.0:
+; UNCHECKED-ELF-NEXT:    mov  x16, x0
+; UNCHECKED-ELF-NEXT:    movk x1, #12345, lsl #48
+; UNCHECKED-ELF-NEXT:    autda x16, x1
+; UNCHECKED-ELF-NEXT:    ldrsw x17, [x16, #8]!
+; UNCHECKED-ELF-NEXT:    add   x16, x16, x17
+; UNCHECKED-ELF-NEXT:    movk x0, #54321, lsl #48
+; UNCHECKED-ELF-NEXT:    pacdb x16, x0
+; UNCHECKED-ELF-NEXT:    mov x0, x16
+; UNCHECKED-ELF-NEXT:    ret
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %arg, i64 12345)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %p,   i64 54321)
+  %res = call i64 @llvm.ptrauth.resign.load.relative(i64 %p, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc, i64 8)
+  ret i64 %res
+}
+
 declare i64 @llvm.ptrauth.auth(i64, i32, i64)
 declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)
 declare i64 @llvm.ptrauth.blend(i64, i64)

>From b82fdb2ba1c224ba6c7e0db11e9cc532daebb022 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Fri, 17 Jul 2026 15:35:26 +0300
Subject: [PATCH 4/4] Minor comment fixes and s/AuthWithPC/IsAuthWithPC/

---
 llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 8 ++++----
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index a518bdf69c2da..46eb6667d539d 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -2410,7 +2410,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
     std::optional<PtrAuthSchema> SignSchema, std::optional<int64_t> Addend,
     Value *DS) {
   const PtrauthCheckMode CheckMode = getCheckMode(MF);
-  const bool AuthWithPC = AuthSchema.PCDisc != AArch64::NoRegister;
+  const bool IsAuthWithPC = AuthSchema.PCDisc != AArch64::NoRegister;
   assert(!SignSchema || SignSchema->PCDisc == AArch64::NoRegister);
 
   Register SignAddrDiscOrNone =
@@ -2419,7 +2419,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
   // 1. Authenticate Pointer - this is the only common step.
   // It is more complex than signing because AUTI[AB]171615 may be used.
 
-  if (AuthWithPC) {
+  if (IsAuthWithPC) {
     assert(Pointer == AArch64::X17 && Scratch == AArch64::X16 &&
            "AUTPCPAC must use x17/x16 as Pointer/Scratch");
 
@@ -2445,7 +2445,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
     // emitPtrauthDiscriminator is allowed to clobber AuthSchema.AddrDisc as
     // long as it is not used past this point neither externally (the register
     // operand is "killed"), nor internally (it does not alias anything being
-    // used later).
+    // used later by this pseudo instruction).
     //
     // Note that, while rather unlikely, it is technically possible to use the
     // Pointer to compute its own discriminator.
@@ -2457,7 +2457,7 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
   }
 
   // The other two steps are optional, define lambdas for them:
-  // 2. Check That Pointer is valid, on failure jump to label or trap.
+  // 2. Check that Pointer is valid, on failure jump to label or trap.
   auto EmitCheck = [&](MCSymbol *OnFailure = nullptr) {
     emitPtrauthCheckAuthenticatedValue(Pointer, Scratch, AuthSchema.Key,
                                        AArch64PAuth::AuthCheckMethod::XPAC,
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index afa5e1ece6425..c3ea54c1dd358 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2290,7 +2290,7 @@ let Predicates = [HasPAuth] in {
                (ins i32imm:$AUTKey,
                     i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc),
                []>, Sched<[WriteI, ReadI]> {
-    // Thanks to its register class, $PACAddrDisc never aliases X16 which is
+    // Thanks to its register class, $PACAddrDisc never aliases X17 which is
     // early-clobbered.
     let isCodeGenOnly = 1;
     let hasSideEffects = 1;



More information about the llvm-commits mailing list