[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