[clang] [llvm] [CodeGen][AArch64] ptrauth intrinsic to safely construct relative ptr (PR #142047)
Abhay Kanhere via llvm-commits
llvm-commits at lists.llvm.org
Wed Jul 30 10:05:06 PDT 2025
https://github.com/AbhayKanhere updated https://github.com/llvm/llvm-project/pull/142047
>From c9d478a056fae873fd925f4df76189c4158fee8c Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <abhay at kanhere.net>
Date: Wed, 28 May 2025 16:35:05 -0700
Subject: [PATCH 1/2] [CodeGen][AArch64] ptrauth intrinsic to safely construct
relative pointer for swift coroutines A ptrauth intrinsic for swift
co-routine support that allows creation of signed pointer from offset stored
at address relative to the pointer.
Following C-like pseudo code (ignoring keys,discriminators) explains its operation:
let rawptr = PACauth(inputptr);
return PACsign( rawptr + *(int32*)(rawptr+addend) )
What: Authenticate a signed pointer, load a 32bit value at offset 'addend' from pointer,
add this value to pointer, sign this new pointer.
builtin: __builtin_ptrauth_auth_load_relative_and_sign
intrinsic: ptrauth_auth_resign_load_relative
note: conflicts resolved llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp due to upstream change
in args for emitPtrauthAuthResign
---
clang/include/clang/Basic/Builtins.td | 6 +
clang/lib/CodeGen/CGBuiltin.cpp | 6 +-
clang/lib/Headers/ptrauth.h | 26 +-
llvm/include/llvm/IR/Intrinsics.td | 13 +
llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp | 92 +++-
.../Target/AArch64/AArch64ISelDAGToDAG.cpp | 37 +-
llvm/lib/Target/AArch64/AArch64InstrInfo.td | 20 +
.../GISel/AArch64InstructionSelector.cpp | 36 ++
llvm/lib/Transforms/Utils/Local.cpp | 1 +
...uth-intrinsic-auth-resign-relative-load.ll | 516 ++++++++++++++++++
10 files changed, 732 insertions(+), 21 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 5ebb82180521d..fa1532e700fe9 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4643,6 +4643,12 @@ def PtrauthAuthAndResign : Builtin {
let Prototype = "void*(void*,int,void*,int,void*)";
}
+def PtrauthAuthLoadRelativeAndSign : Builtin {
+ let Spellings = ["__builtin_ptrauth_auth_load_relative_and_sign"];
+ let Attributes = [CustomTypeChecking, NoThrow];
+ let Prototype = "void*(void*,int,void*,int,void*,ptrdiff_t)";
+}
+
def PtrauthAuth : Builtin {
let Spellings = ["__builtin_ptrauth_auth"];
let Attributes = [CustomTypeChecking, NoThrow];
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 5f2eb76e7bacb..160eb665d7209 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5584,12 +5584,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
case Builtin::BI__builtin_ptrauth_auth:
case Builtin::BI__builtin_ptrauth_auth_and_resign:
+ case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
case Builtin::BI__builtin_ptrauth_blend_discriminator:
case Builtin::BI__builtin_ptrauth_sign_generic_data:
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
case Builtin::BI__builtin_ptrauth_strip: {
// Emit the arguments.
- SmallVector<llvm::Value *, 5> Args;
+ SmallVector<llvm::Value *, 6> Args;
for (auto argExpr : E->arguments())
Args.push_back(EmitScalarExpr(argExpr));
@@ -5600,6 +5601,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
switch (BuiltinID) {
case Builtin::BI__builtin_ptrauth_auth_and_resign:
+ case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
if (Args[4]->getType()->isPointerTy())
Args[4] = Builder.CreatePtrToInt(Args[4], IntPtrTy);
[[fallthrough]];
@@ -5627,6 +5629,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
return Intrinsic::ptrauth_auth;
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return Intrinsic::ptrauth_resign;
+ case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
+ return Intrinsic::ptrauth_resign_load_relative;
case Builtin::BI__builtin_ptrauth_blend_discriminator:
return Intrinsic::ptrauth_blend;
case Builtin::BI__builtin_ptrauth_sign_generic_data:
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 7f7d387cbdfda..981ad345be0e9 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -178,6 +178,31 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data)
+/* Authenticate a pointer using one scheme, load 32bit value at offset addend
+ from the pointer, and add this value to the pointer, sign using specified
+ scheme.
+
+ If the result is subsequently authenticated using the new scheme, that
+ authentication is guaranteed to fail if and only if the initial
+ authentication failed.
+
+ The value must be an expression of pointer type.
+ The key must be a constant expression of type ptrauth_key.
+ The extra data must be an expression of pointer or integer type;
+ if an integer, it will be coerced to ptrauth_extra_data_t.
+ The addend must be an immediate ptrdiff_t value.
+ The result will have the same type as the original value.
+
+ This operation is guaranteed to not leave the intermediate value
+ available for attack before it is re-signed.
+
+ Do not pass a null pointer to this function. A null pointer
+ will not successfully authenticate. */
+#define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \
+ __new_key, __new_data, __addend) \
+ __builtin_ptrauth_auth_load_relative_and_sign( \
+ __value, __old_key, __old_data, __new_key, __new_data, __addend)
+
/* Authenticate a pointer using one scheme and resign it as a C
function pointer.
@@ -380,7 +405,6 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
((ptrauth_generic_signature_t)0); \
})
-
#define ptrauth_cxx_vtable_pointer(key, address_discrimination, \
extra_discrimination...)
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index bd6f94ac1286c..85d2be4326ce5 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -2818,6 +2818,19 @@ def int_ptrauth_resign : Intrinsic<[llvm_i64_ty],
[IntrNoMem, ImmArg<ArgIndex<1>>,
ImmArg<ArgIndex<3>>]>;
+// Authenticate a signed pointer, load 32bit value at offset from pointer, add
+// both, and sign it. The second (key) and third (discriminator) arguments
+// specify the signing schema used for authenticating. The fourth and fifth
+// arguments specify the schema used for signing. The sixth argument is addend
+// added to pointer to load the relative offset. The signature must be valid.
+// This is a combined form of int_ptrauth_resign for relative pointers
+def int_ptrauth_resign_load_relative
+ : Intrinsic<[llvm_i64_ty],
+ [llvm_i64_ty, llvm_i32_ty, llvm_i64_ty, llvm_i32_ty,
+ llvm_i64_ty, llvm_i64_ty],
+ [IntrReadMem, ImmArg<ArgIndex<1>>, ImmArg<ArgIndex<3>>,
+ ImmArg<ArgIndex<5>>]>;
+
// Strip the embedded signature out of a signed pointer.
// The second argument specifies the key.
// This behaves like @llvm.ptrauth.auth, but doesn't require the signature to
diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
index c4b43e1b51265..3496734519366 100644
--- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
+++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp
@@ -168,13 +168,14 @@ class AArch64AsmPrinter : public AsmPrinter {
// Check authenticated LR before tail calling.
void emitPtrauthTailCallHardening(const MachineInstr *TC);
- // Emit the sequence for AUT or AUTPAC.
+ // Emit the sequence for AUT or AUTPAC. Addend if AUTRELLOADPAC
void emitPtrauthAuthResign(Register AUTVal, AArch64PACKey::ID AUTKey,
uint64_t AUTDisc,
const MachineOperand *AUTAddrDisc,
Register Scratch,
std::optional<AArch64PACKey::ID> PACKey,
- uint64_t PACDisc, Register PACAddrDisc);
+ uint64_t PACDisc, Register PACAddrDisc,
+ std::optional<uint64_t> Addend);
// Emit the sequence to compute the discriminator.
//
@@ -2075,9 +2076,9 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
Register AUTVal, AArch64PACKey::ID AUTKey, uint64_t AUTDisc,
const MachineOperand *AUTAddrDisc, Register Scratch,
std::optional<AArch64PACKey::ID> PACKey, uint64_t PACDisc,
- Register PACAddrDisc) {
+ Register PACAddrDisc, std::optional<uint64_t> OptAddend) {
const bool IsAUTPAC = PACKey.has_value();
-
+ const bool HasLoad = OptAddend.has_value();
// We expand AUT/AUTPAC into a sequence of the form
//
// ; authenticate x16
@@ -2148,12 +2149,76 @@ void AArch64AsmPrinter::emitPtrauthAuthResign(
}
// We already emitted unchecked and checked-but-non-trapping AUTs.
- // That left us with trapping AUTs, and AUTPACs.
+ // That left us with trapping AUTs, and AUTPA/AUTRELLOADPACs.
// Trapping AUTs don't need PAC: we're done.
if (!IsAUTPAC)
return;
- // Compute pac discriminator
+ if (HasLoad) {
+ int64_t Addend = *OptAddend;
+ // incoming rawpointer in X16, X17 is not live at this point.
+ // LDSRWpre x17, x16, simm9 ; note: x16+simm9 used later.
+ if (isInt<9>(Addend)) {
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWpre)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X17)
+ .addReg(AArch64::X16)
+ .addImm(/*simm9:*/ Addend));
+ } else {
+ // x16 = x16 + Addend computation has 2 variants
+ if (isUInt<24>(Addend)) {
+ // variant 1: add x16, x16, Addend >> shift12 ls shift12
+ // This can take upto 2 instructions.
+ for (int BitPos = 0; BitPos != 24 && (Addend >> BitPos); BitPos += 12) {
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X16)
+ .addImm((Addend >> BitPos) & 0xfff)
+ .addImm(AArch64_AM::getShifterImm(
+ AArch64_AM::LSL, BitPos)));
+ }
+ } else {
+ // variant 2: accumulate constant in X17 16 bits at a time, and add to
+ // X16 This can take 2-5 instructions.
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi)
+ .addReg(AArch64::X17)
+ .addImm(Addend & 0xffff)
+ .addImm(AArch64_AM::getShifterImm(
+ AArch64_AM::LSL, 0)));
+
+ for (int Offset = 16; Offset < 64; Offset += 16) {
+ uint16_t Fragment = static_cast<uint16_t>(Addend >> Offset);
+ if (!Fragment)
+ continue;
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi)
+ .addReg(AArch64::X17)
+ .addReg(AArch64::X17)
+ .addImm(Fragment)
+ .addImm(/*shift:*/ Offset));
+ }
+ // addx x16, x16, x17
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X17)
+ .addImm(0));
+ }
+ // ldrsw x17,x16(0)
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWui)
+ .addReg(AArch64::X17)
+ .addReg(AArch64::X16)
+ .addImm(0));
+ }
+ // addx x16, x16, x17
+ EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X16)
+ .addReg(AArch64::X17)
+ .addImm(0));
+
+ } /* HasLoad == true */
+
+ // Compute pac discriminator into x17
assert(isUInt<16>(PACDisc));
Register PACDiscReg =
emitPtrauthDiscriminator(PACDisc, PACAddrDisc, Scratch);
@@ -2872,22 +2937,31 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) {
emitPtrauthAuthResign(AArch64::X16,
(AArch64PACKey::ID)MI->getOperand(0).getImm(),
MI->getOperand(1).getImm(), &MI->getOperand(2),
- AArch64::X17, std::nullopt, 0, 0);
+ AArch64::X17, std::nullopt, 0, 0, std::nullopt);
return;
case AArch64::AUTxMxN:
emitPtrauthAuthResign(MI->getOperand(0).getReg(),
(AArch64PACKey::ID)MI->getOperand(3).getImm(),
MI->getOperand(4).getImm(), &MI->getOperand(5),
- MI->getOperand(1).getReg(), std::nullopt, 0, 0);
+ MI->getOperand(1).getReg(), std::nullopt, 0, 0,
+ std::nullopt);
return;
+ case AArch64::AUTRELLOADPAC:
+ emitPtrauthAuthResign(
+ AArch64::X16, (AArch64PACKey::ID)MI->getOperand(0).getImm(),
+ MI->getOperand(1).getImm(), &MI->getOperand(2), AArch64::X17,
+ (AArch64PACKey::ID)MI->getOperand(3).getImm(),
+ MI->getOperand(4).getImm(), MI->getOperand(5).getReg(),
+ MI->getOperand(6).getImm());
+ return;
case AArch64::AUTPAC:
emitPtrauthAuthResign(
AArch64::X16, (AArch64PACKey::ID)MI->getOperand(0).getImm(),
MI->getOperand(1).getImm(), &MI->getOperand(2), AArch64::X17,
(AArch64PACKey::ID)MI->getOperand(3).getImm(),
- MI->getOperand(4).getImm(), MI->getOperand(5).getReg());
+ MI->getOperand(4).getImm(), MI->getOperand(5).getReg(), std::nullopt);
return;
case AArch64::LOADauthptrstatic:
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index eca7ca566cfc2..e4e6ba6bdc6a0 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -1552,12 +1552,15 @@ void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) {
SDLoc DL(N);
- // IntrinsicID is operand #0
- SDValue Val = N->getOperand(1);
- SDValue AUTKey = N->getOperand(2);
- SDValue AUTDisc = N->getOperand(3);
- SDValue PACKey = N->getOperand(4);
- SDValue PACDisc = N->getOperand(5);
+ // IntrinsicID is operand #0, if W_CHAIN it is #1
+ int OffsetBase = N->getOpcode() == ISD::INTRINSIC_W_CHAIN ? 1 : 0;
+ SDValue Val = N->getOperand(OffsetBase + 1);
+ SDValue AUTKey = N->getOperand(OffsetBase + 2);
+ SDValue AUTDisc = N->getOperand(OffsetBase + 3);
+ SDValue PACKey = N->getOperand(OffsetBase + 4);
+ SDValue PACDisc = N->getOperand(OffsetBase + 5);
+ uint32_t IntNum = N->getConstantOperandVal(OffsetBase + 0);
+ bool HasLoad = IntNum == Intrinsic::ptrauth_resign_load_relative;
unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue();
unsigned PACKeyC = cast<ConstantSDNode>(PACKey)->getZExtValue();
@@ -1576,11 +1579,22 @@ void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) {
SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
AArch64::X16, Val, SDValue());
- SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey,
- PACConstDisc, PACAddrDisc, X16Copy.getValue(1)};
+ if (HasLoad) {
+ SDValue Addend = N->getOperand(OffsetBase + 6);
+ SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc,
+ PACKey, PACConstDisc, PACAddrDisc,
+ Addend, X16Copy.getValue(1)};
- SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops);
- ReplaceNode(N, AUTPAC);
+ SDNode *AUTRELLOADPAC = CurDAG->getMachineNode(AArch64::AUTRELLOADPAC, DL,
+ MVT::i64, MVT::Other, Ops);
+ ReplaceNode(N, AUTRELLOADPAC);
+ } else {
+ SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, PACKey,
+ PACConstDisc, PACAddrDisc, X16Copy.getValue(1)};
+
+ SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops);
+ ReplaceNode(N, AUTPAC);
+ }
}
bool AArch64DAGToDAGISel::tryIndexedLoad(SDNode *N) {
@@ -5777,6 +5791,9 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
{AArch64::BF2CVT_2ZZ_BtoH, AArch64::F2CVT_2ZZ_BtoH}))
SelectCVTIntrinsicFP8(Node, 2, Opc);
return;
+ case Intrinsic::ptrauth_resign_load_relative:
+ SelectPtrauthResign(Node);
+ return;
}
} break;
case ISD::INTRINSIC_WO_CHAIN: {
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 6c46b18d506c5..b9d60414ae0c7 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2176,6 +2176,26 @@ let Predicates = [HasPAuth] in {
let Uses = [X16];
}
+ // Similiar to AUTPAC, except a 32bit value is loaded at Addend offset from
+ // pointer and this value is added to the pointer before signing. This
+ // directly manipulates x16/x17, which are the only registers the OS
+ // guarantees are safe to use for sensitive operations.
+ def AUTRELLOADPAC
+ : Pseudo<(outs),
+ (ins i32imm:$AUTKey, i64imm:$AUTDisc, GPR64:$AUTAddrDisc,
+ i32imm:$PACKey, i64imm:$PACDisc, GPR64noip:$PACAddrDisc,
+ i64imm:$Addend),
+ []>,
+ Sched<[WriteI, ReadI]> {
+ let isCodeGenOnly = 1;
+ let hasSideEffects = 1;
+ let mayStore = 0;
+ let mayLoad = 1;
+ let Size = 84;
+ let Defs = [X16, X17, NZCV];
+ let Uses = [X16];
+ }
+
// Materialize a signed global address, with adrp+add and PAC.
def MOVaddrPAC : Pseudo<(outs),
(ins i64imm:$Addr, i32imm:$Key,
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 1381a9b70df87..2b554002dd21d 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -6665,6 +6665,42 @@ bool AArch64InstructionSelector::selectIntrinsicWithSideEffects(
constrainSelectedInstRegOperands(*Memset, TII, TRI, RBI);
break;
}
+ case Intrinsic::ptrauth_resign_load_relative: {
+ Register DstReg = I.getOperand(0).getReg();
+ Register ValReg = I.getOperand(2).getReg();
+ uint64_t AUTKey = I.getOperand(3).getImm();
+ Register AUTDisc = I.getOperand(4).getReg();
+ uint64_t PACKey = I.getOperand(5).getImm();
+ Register PACDisc = I.getOperand(6).getReg();
+ int64_t Addend = I.getOperand(7).getImm();
+
+ Register AUTAddrDisc = AUTDisc;
+ uint16_t AUTConstDiscC = 0;
+ std::tie(AUTConstDiscC, AUTAddrDisc) =
+ extractPtrauthBlendDiscriminators(AUTDisc, MRI);
+
+ Register PACAddrDisc = PACDisc;
+ uint16_t PACConstDiscC = 0;
+ std::tie(PACConstDiscC, PACAddrDisc) =
+ extractPtrauthBlendDiscriminators(PACDisc, MRI);
+
+ MIB.buildCopy({AArch64::X16}, {ValReg});
+
+ MIB.buildInstr(AArch64::AUTRELLOADPAC)
+ .addImm(AUTKey)
+ .addImm(AUTConstDiscC)
+ .addUse(AUTAddrDisc)
+ .addImm(PACKey)
+ .addImm(PACConstDiscC)
+ .addUse(PACAddrDisc)
+ .addImm(Addend)
+ .constrainAllUses(TII, TRI, RBI);
+ MIB.buildCopy({DstReg}, Register(AArch64::X16));
+
+ RBI.constrainGenericRegister(DstReg, AArch64::GPR64RegClass, MRI);
+ I.eraseFromParent();
+ return true;
+ }
}
I.eraseFromParent();
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index b14bbeac97675..655477931a8dd 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -457,6 +457,7 @@ bool llvm::wouldInstructionBeTriviallyDead(const Instruction *I,
case Intrinsic::wasm_trunc_unsigned:
case Intrinsic::ptrauth_auth:
case Intrinsic::ptrauth_resign:
+ case Intrinsic::ptrauth_resign_load_relative:
return true;
default:
return false;
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll
new file mode 100644
index 0000000000000..affa0c2369ba2
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-relative-load.ll
@@ -0,0 +1,516 @@
+; 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-prefix=UNCHECKED
+; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
+; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefix=UNCHECKED
+
+; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \
+; RUN: | FileCheck %s -DL="L" --check-prefix=CHECKED
+; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
+; RUN: | FileCheck %s -DL="L" --check-prefix=CHECKED
+
+; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \
+; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefix=TRAP
+; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
+; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefix=TRAP
+
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
+;RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefix=UNCHECKED
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
+;RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefix=UNCHECKED
+
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
+;RUN: | FileCheck %s -DL=".L" --check-prefix=CHECKED
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
+;RUN: | FileCheck %s -DL=".L" --check-prefix=CHECKED
+
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
+;RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefix=TRAP
+;RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
+;RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefix=TRAP
+
+target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
+
+define i64 @test_resign_load_relative_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_ia_ia:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autia x16, x1
+; UNCHECKED-NEXT: ldrsw x17, [x16, #-256]!
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacia x16, x2
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_ia_ia:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-NEXT: autia x16, x1
+; CHECKED-NEXT: mov x17, x16
+; CHECKED-NEXT: xpaci x17
+; CHECKED-NEXT: cmp x16, x17
+; CHECKED-NEXT: b.eq [[L]]auth_success_0
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_0
+; CHECKED-NEXT: Lauth_success_0:
+; CHECKED-NEXT: ldrsw x17, [x16, #-256]!
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacia x16, x2
+; CHECKED-NEXT: Lresign_end_0:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_ia_ia:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-NEXT: autia x16, x1
+; TRAP-NEXT: mov x17, x16
+; TRAP-NEXT: xpaci x17
+; TRAP-NEXT: cmp x16, x17
+; TRAP-NEXT: b.eq [[L]]auth_success_0
+; TRAP-NEXT: brk #0xc470
+; TRAP-NEXT: Lauth_success_0:
+; TRAP-NEXT: ldrsw x17, [x16, #-256]!
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacia x16, x2
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 0, i64 %arg1, i32 0, i64 %arg2, i64 -256)
+ ret i64 %tmp
+}
+
+; note: offset 256 is larger tha 255 (largest simm9), is uint<24>
+define i64 @test_resign_load_relative_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_ib_ia:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autib x16, x1
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacia x16, x2
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_ib_ia:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-NEXT: autib x16, x1
+; CHECKED-NEXT: mov x17, x16
+; CHECKED-NEXT: xpaci x17
+; CHECKED-NEXT: cmp x16, x17
+; CHECKED-NEXT: b.eq [[L]]auth_success_1
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_1
+; CHECKED-NEXT: Lauth_success_1:
+; CHECKED-NEXT: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacia x16, x2
+; CHECKED-NEXT: Lresign_end_1:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_ib_ia:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-NEXT: autib x16, x1
+; TRAP-NEXT: mov x17, x16
+; TRAP-NEXT: xpaci x17
+; TRAP-NEXT: cmp x16, x17
+; TRAP-NEXT: b.eq [[L]]auth_success_1
+; TRAP-NEXT: brk #0xc471
+; TRAP-NEXT: Lauth_success_1:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacia x16, x2
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 1, i64 %arg1, i32 0, i64 %arg2, i64 256)
+ ret i64 %tmp
+}
+
+define i64 @test_resign_load_relative_da_ia(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_da_ia:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autda x16, x1
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacia x16, x2
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_da_ia:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-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_2
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_2
+; CHECKED-NEXT: Lauth_success_2:
+; CHECKED-NEXT: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacia x16, x2
+; CHECKED-NEXT: Lresign_end_2:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_da_ia:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-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_2
+; TRAP-NEXT: brk #0xc472
+; TRAP-NEXT: Lauth_success_2:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacia x16, x2
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 0, i64 %arg2, i64 256)
+ ret i64 %tmp
+}
+
+define i64 @test_resign_load_relative_db_da(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_db_da:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autdb x16, x1
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacda x16, x2
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_db_da:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-NEXT: autdb x16, x1
+; 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: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacda x16, x2
+; CHECKED-NEXT: Lresign_end_3:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_db_da:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-NEXT: autdb x16, x1
+; TRAP-NEXT: mov x17, x16
+; TRAP-NEXT: xpacd x17
+; TRAP-NEXT: cmp x16, x17
+; TRAP-NEXT: b.eq [[L]]auth_success_3
+; TRAP-NEXT: brk #0xc473
+; TRAP-NEXT: Lauth_success_3:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacda x16, x2
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 3, i64 %arg1, i32 2, i64 %arg2, i64 256)
+ ret i64 %tmp
+}
+
+define i64 @test_resign_load_relative_iza_db(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_iza_db:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autiza x16
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacdb x16, x2
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_iza_db:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-NEXT: autiza x16
+; CHECKED-NEXT: mov x17, x16
+; CHECKED-NEXT: xpaci x17
+; CHECKED-NEXT: cmp x16, x17
+; CHECKED-NEXT: b.eq [[L]]auth_success_4
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_4
+; CHECKED-NEXT: Lauth_success_4:
+; CHECKED-NEXT: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacdb x16, x2
+; CHECKED-NEXT: Lresign_end_4:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_iza_db:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-NEXT: autiza x16
+; TRAP-NEXT: mov x17, x16
+; TRAP-NEXT: xpaci x17
+; TRAP-NEXT: cmp x16, x17
+; TRAP-NEXT: b.eq [[L]]auth_success_4
+; TRAP-NEXT: brk #0xc470
+; TRAP-NEXT: Lauth_success_4:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacdb x16, x2
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 0, i64 0, i32 3, i64 %arg2, i64 256)
+ ret i64 %tmp
+}
+
+define i64 @test_resign_load_relative_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) {
+; UNCHECKED-LABEL: test_resign_load_relative_da_dzb:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autda x16, x1
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: pacdzb x16
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_da_dzb:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-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_5
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_5
+; CHECKED-NEXT: Lauth_success_5:
+; CHECKED-NEXT: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: pacdzb x16
+; CHECKED-NEXT: Lresign_end_5:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_da_dzb:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-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_5
+; TRAP-NEXT: brk #0xc472
+; TRAP-NEXT: Lauth_success_5:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: pacdzb x16
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 3, i64 0,i64 256)
+ ret i64 %tmp
+}
+
+define i64 @test_resign_load_relative_da_constdisc(i64 %arg, i64 %arg1) {
+; UNCHECKED-LABEL: test_resign_load_relative_da_constdisc:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autda x16, x1
+; UNCHECKED-NEXT: add x16, x16, #256
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: mov x17, #256
+; UNCHECKED-NEXT: pacda x16, x17
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_da_constdisc:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-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_6
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_6
+; CHECKED-NEXT: Lauth_success_6:
+; CHECKED-NEXT: add x16, x16, #256
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: mov x17, #256
+; CHECKED-NEXT: pacda x16, x17
+; CHECKED-NEXT: Lresign_end_6:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_da_constdisc:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-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_6
+; TRAP-NEXT: brk #0xc472
+; TRAP-NEXT: Lauth_success_6:
+; TRAP-NEXT: add x16, x16, #256
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: mov x17, #256
+; TRAP-NEXT: pacda x16, x17
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg, i32 2, i64 %arg1, i32 2, i64 256,i64 256)
+ ret i64 %tmp
+}
+
+; note: addend is larger than 24bit integer
+define i64 @test_resign_load_relative_loadNegOffset_constdisc(i64 %arg,i64 %arg1) {
+; UNCHECKED-LABEL: test_resign_load_relative_loadNegOffset_constdisc:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autda x16, x1
+; UNCHECKED-NEXT: mov x17, #62980
+; UNCHECKED-NEXT: movk x17, #65535, lsl #16
+; UNCHECKED-NEXT: movk x17, #65535, lsl #32
+; UNCHECKED-NEXT: movk x17, #65535, lsl #48
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: mov x17, #256
+; UNCHECKED-NEXT: pacda x16, x17
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_loadNegOffset_constdisc:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-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_7
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_7
+; CHECKED-NEXT: Lauth_success_7:
+; CHECKED-NEXT: mov x17, #62980
+; CHECKED-NEXT: movk x17, #65535, lsl #16
+; CHECKED-NEXT: movk x17, #65535, lsl #32
+; CHECKED-NEXT: movk x17, #65535, lsl #48
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: mov x17, #256
+; CHECKED-NEXT: pacda x16, x17
+; CHECKED-NEXT: Lresign_end_7:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_loadNegOffset_constdisc:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-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_7
+; TRAP-NEXT: brk #0xc472
+; TRAP-NEXT: Lauth_success_7:
+; TRAP-NEXT: mov x17, #62980
+; TRAP-NEXT: movk x17, #65535, lsl #16
+; TRAP-NEXT: movk x17, #65535, lsl #32
+; TRAP-NEXT: movk x17, #65535, lsl #48
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: mov x17, #256
+; TRAP-NEXT: pacda x16, x17
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg,i32 2,i64 %arg1,i32 2,i64 256,i64 -2556)
+ ret i64 %tmp
+}
+define i64 @test_resign_load_relative_largeOffset_constdisc(i64 %arg,i64 %arg1) {
+; UNCHECKED-LABEL: test_resign_load_relative_largeOffset_constdisc:
+; UNCHECKED: %bb.0:
+; UNCHECKED-NEXT: mov x16, x0
+; UNCHECKED-NEXT: autda x16, x1
+; UNCHECKED-NEXT: add x16, x16, #3884
+; UNCHECKED-NEXT: add x16, x16, #7, lsl #12
+; UNCHECKED-NEXT: ldrsw x17, [x16]
+; UNCHECKED-NEXT: add x16, x16, x17
+; UNCHECKED-NEXT: mov x17, #256
+; UNCHECKED-NEXT: pacda x16, x17
+; UNCHECKED-NEXT: mov x0, x16
+; UNCHECKED-NEXT: ret
+;
+; CHECKED-LABEL: test_resign_load_relative_largeOffset_constdisc:
+; CHECKED: %bb.0:
+; CHECKED-NEXT: mov x16, x0
+; CHECKED-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_8
+; CHECKED-NEXT: mov x16, x17
+; CHECKED-NEXT: b [[L]]resign_end_8
+; CHECKED-NEXT: Lauth_success_8:
+; CHECKED-NEXT: add x16, x16, #3884
+; CHECKED-NEXT: add x16, x16, #7, lsl #12
+; CHECKED-NEXT: ldrsw x17, [x16]
+; CHECKED-NEXT: add x16, x16, x17
+; CHECKED-NEXT: mov x17, #256
+; CHECKED-NEXT: pacda x16, x17
+; CHECKED-NEXT: Lresign_end_8:
+; CHECKED-NEXT: mov x0, x16
+; CHECKED-NEXT: ret
+;
+; TRAP-LABEL: test_resign_load_relative_largeOffset_constdisc:
+; TRAP: %bb.0:
+; TRAP-NEXT: mov x16, x0
+; TRAP-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_8
+; TRAP-NEXT: brk #0xc472
+; TRAP-NEXT: Lauth_success_8:
+; TRAP-NEXT: add x16, x16, #3884
+; TRAP-NEXT: add x16, x16, #7, lsl #12
+; TRAP-NEXT: ldrsw x17, [x16]
+; TRAP-NEXT: add x16, x16, x17
+; TRAP-NEXT: mov x17, #256
+; TRAP-NEXT: pacda x16, x17
+; TRAP-NEXT: mov x0, x16
+; TRAP-NEXT: ret
+ %tmp = call i64 @llvm.ptrauth.resign.load.relative(i64 %arg,i32 2,i64 %arg1,i32 2,i64 256,i64 32556)
+ ret i64 %tmp
+}
+declare i64 @llvm.ptrauth.auth(i64, i32, i64)
+declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)
+declare i64 @llvm.ptrauth.resign.load.relative(i64,i32,i64,i32,i64,i64)
>From c5c6bacbefb61725901f67f6c9a6e2805d8a1725 Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <abhay at kanhere.net>
Date: Wed, 30 Jul 2025 10:04:04 -0700
Subject: [PATCH 2/2] Adding Sema checks, tests and diagnostics for constant
argument
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/Headers/ptrauth.h | 10 +++++++
clang/lib/Sema/SemaChecking.cpp | 29 +++++++++++++++++++
clang/test/CodeGen/ptrauth-intrinsics.c | 12 ++++++++
clang/test/Sema/ptrauth.c | 23 +++++++++++++++
5 files changed, 76 insertions(+)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b2ea65ae111be..8dba5701edccd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11078,6 +11078,8 @@ def err_builtin_requires_language : Error<"'%0' is only available in %1">;
def err_constant_integer_arg_type : Error<
"argument to %0 must be a constant integer">;
+def err_constant_integer_last_arg_type
+ : Error<"last argument to %0 must be a constant integer">;
def ext_mixed_decls_code : Extension<
"mixing declarations and code is a C99 extension">,
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 981ad345be0e9..6190cc8394250 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -376,6 +376,16 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__value; \
})
+#define ptrauth_auth_load_relative_and_sign(__value, __old_key, __old_data, \
+ __new_key, __new_data, __addend) \
+ ({ \
+ (void)__old_key; \
+ (void)__old_data; \
+ (void)__new_key; \
+ (void)__new_data; \
+ __value + *(int *)((char *)__value + __addend); \
+ })
+
#define ptrauth_auth_function(__value, __old_key, __old_data) \
({ \
(void)__old_key; \
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index dd5b710d7e1d4..dcb775725d027 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1814,6 +1814,33 @@ static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) {
return Call;
}
+static ExprResult PointerAuthAuthLoadRelativeAndSign(Sema &S, CallExpr *Call) {
+ if (S.checkArgCount(Call, 6))
+ return ExprError();
+ if (checkPointerAuthEnabled(S, Call))
+ return ExprError();
+ const Expr *AddendExpr = Call->getArg(5);
+ std::optional<llvm::APSInt> AddendValue =
+ AddendExpr->getIntegerConstantExpr(S.Context);
+ const Expr *Arg = Call->getArg(5)->IgnoreParenImpCasts();
+ DeclRefExpr *DRE = cast<DeclRefExpr>(Call->getCallee()->IgnoreParenCasts());
+ FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+ if (!AddendValue.has_value()) {
+ S.Diag(Arg->getBeginLoc(), diag::err_constant_integer_last_arg_type)
+ << FDecl->getDeclName() << Arg->getSourceRange();
+ }
+ if (checkPointerAuthValue(S, Call->getArgs()[0], PAO_Auth) ||
+ checkPointerAuthKey(S, Call->getArgs()[1]) ||
+ checkPointerAuthValue(S, Call->getArgs()[2], PAO_Discriminator) ||
+ checkPointerAuthKey(S, Call->getArgs()[3]) ||
+ checkPointerAuthValue(S, Call->getArgs()[4], PAO_Discriminator) ||
+ !AddendValue.has_value())
+ return ExprError();
+
+ Call->setType(Call->getArgs()[0]->getType());
+ return Call;
+}
+
static ExprResult PointerAuthStringDiscriminator(Sema &S, CallExpr *Call) {
if (checkPointerAuthEnabled(S, Call))
return ExprError();
@@ -2866,6 +2893,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
return PointerAuthSignGenericData(*this, TheCall);
case Builtin::BI__builtin_ptrauth_auth_and_resign:
return PointerAuthAuthAndResign(*this, TheCall);
+ case Builtin::BI__builtin_ptrauth_auth_load_relative_and_sign:
+ return PointerAuthAuthLoadRelativeAndSign(*this, TheCall);
case Builtin::BI__builtin_ptrauth_string_discriminator:
return PointerAuthStringDiscriminator(*this, TheCall);
diff --git a/clang/test/CodeGen/ptrauth-intrinsics.c b/clang/test/CodeGen/ptrauth-intrinsics.c
index 50bf1898e4b37..bd348f9b3551a 100644
--- a/clang/test/CodeGen/ptrauth-intrinsics.c
+++ b/clang/test/CodeGen/ptrauth-intrinsics.c
@@ -55,6 +55,18 @@ void test_auth_and_resign() {
fnptr = __builtin_ptrauth_auth_and_resign(fnptr, 0, ptr_discriminator, 3, 15);
}
+// CHECK-LABEL: define {{.*}}void @test_auth_load_relative_and_sign()
+void test_auth_load_relative_and_sign() {
+ // CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
+ // CHECK-NEXT: [[DISC0:%.*]] = load ptr, ptr @ptr_discriminator,
+ // CHECK-NEXT: [[T0:%.*]] = ptrtoint ptr [[PTR]] to i64
+ // CHECK-NEXT: [[DISC:%.*]] = ptrtoint ptr [[DISC0]] to i64
+ // CHECK-NEXT: [[T1:%.*]] = call i64 @llvm.ptrauth.resign.load.relative(i64 [[T0]], i32 0, i64 [[DISC]], i32 3, i64 15, i64 16)
+ // CHECK-NEXT: [[RESULT:%.*]] = inttoptr i64 [[T1]] to ptr
+ // CHECK-NEXT: store ptr [[RESULT]], ptr @fnptr,
+ fnptr = __builtin_ptrauth_auth_load_relative_and_sign(fnptr, 0, ptr_discriminator, 3, 15, 16L);
+}
+
// CHECK-LABEL: define {{.*}}void @test_blend_discriminator()
void test_blend_discriminator() {
// CHECK: [[PTR:%.*]] = load ptr, ptr @fnptr,
diff --git a/clang/test/Sema/ptrauth.c b/clang/test/Sema/ptrauth.c
index e3932615c2962..8196bcf70314c 100644
--- a/clang/test/Sema/ptrauth.c
+++ b/clang/test/Sema/ptrauth.c
@@ -121,6 +121,29 @@ void test_auth_and_resign(int *dp, int (*fp)(int)) {
float *mismatch = __builtin_ptrauth_auth_and_resign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
}
+void test_auth_load_relative_and_sign(int *dp, int (*fp)(int)) {
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, 0); // expected-error {{too few arguments}}
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp, 0, 0); // expected-error {{too many arguments}}
+ int n = *dp;
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, dp, VALID_DATA_KEY, dp,n); // expected-error {{last argument to '__builtin_ptrauth_auth_load_relative_and_sign' must be a constant integer}}
+ __builtin_ptrauth_auth_load_relative_and_sign(mismatched_type, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp, 0); // expected-error {{signed value must have pointer type; type here is 'struct A'}}
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, mismatched_type, 0, VALID_DATA_KEY, dp, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, mismatched_type, VALID_DATA_KEY, dp, 0); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, mismatched_type, dp, 0); // expected-error {{passing 'struct A' to parameter of incompatible type 'int'}}
+ __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, mismatched_type, 0); // expected-error {{extra discriminator must have pointer or integer type; type here is 'struct A'}}
+
+ (void) __builtin_ptrauth_auth_and_resign(NULL, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp); // expected-warning {{authenticating a null pointer will almost certainly trap}}
+
+ int *dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp, 10);
+ dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, INVALID_KEY, 0, VALID_DATA_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+ dr = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, INVALID_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+ int (*fr)(int) = __builtin_ptrauth_auth_load_relative_and_sign(fp, VALID_CODE_KEY, 0, VALID_CODE_KEY, dp, 10);
+ fr = __builtin_ptrauth_auth_load_relative_and_sign(fp, INVALID_KEY, 0, VALID_CODE_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+ fr = __builtin_ptrauth_auth_load_relative_and_sign(fp, VALID_CODE_KEY, 0, INVALID_KEY, dp, 10); // expected-error {{does not identify a valid pointer authentication key for the current target}}
+
+ float *mismatch = __builtin_ptrauth_auth_load_relative_and_sign(dp, VALID_DATA_KEY, 0, VALID_DATA_KEY, dp,0); // expected-warning {{incompatible pointer types initializing 'float *' with an expression of type 'int *'}}
+}
void test_sign_generic_data(int *dp) {
__builtin_ptrauth_sign_generic_data(dp); // expected-error {{too few arguments}}
More information about the llvm-commits
mailing list