https://github.com/AbhayKanhere updated 
https://github.com/llvm/llvm-project/pull/142047

>From 0ab5d47bfdb77d8e6870e6f80714790f0317ad8a Mon Sep 17 00:00:00 2001
From: Abhay Kanhere <ab...@kanhere.net>
Date: Wed, 28 May 2025 16:35:05 -0700
Subject: [PATCH] [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/Basic/DiagnosticSemaKinds.td        |   2 +
 clang/lib/CodeGen/CGBuiltin.cpp               |   6 +-
 clang/lib/Headers/ptrauth.h                   |  37 +-
 clang/lib/Sema/SemaChecking.cpp               |  28 +
 clang/test/CodeGen/ptrauth-intrinsics.c       |  12 +
 clang/test/Sema/ptrauth.c                     |  23 +
 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 ++++++++++++++++++
 14 files changed, 808 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 c81714e9b009d..ce5ac81474de5 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -4655,6 +4655,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/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 27d2152805f97..0f1271a18445e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11097,6 +11097,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/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index e1f7ea08837c5..8cba775db63e5 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -5601,12 +5601,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));
 
@@ -5617,6 +5618,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]];
@@ -5644,6 +5646,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..2eb23803f9faa 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.
 
@@ -351,6 +376,17 @@ 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;                                                          
\
+    const char *__value_tmp = (const char *)(__value);                         
\
+    (void *)(__value_tmp + *(const int *)(__value_tmp + (__addend)));          
\
+  })
+
 #define ptrauth_auth_function(__value, __old_key, __old_data)                  
\
   ({                                                                           
\
     (void)__old_key;                                                           
\
@@ -380,7 +416,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/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c74b67106ad74..d4b02487a6adc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -1814,6 +1814,32 @@ 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);
+  bool AddendIsConstInt = AddendExpr->isIntegerConstantExpr(S.Context);
+  if (!AddendIsConstInt) {
+    const Expr *Arg = Call->getArg(5)->IgnoreParenImpCasts();
+    DeclRefExpr *DRE = 
cast<DeclRefExpr>(Call->getCallee()->IgnoreParenCasts());
+    FunctionDecl *FDecl = cast<FunctionDecl>(DRE->getDecl());
+    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) ||
+      !AddendIsConstInt)
+    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 +2892,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 b4e5214a7cb50..2dadb6334f45d 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}}
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 c52487ab8a79a..684d8caad724e 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 for PAC.
   void emitPtrauthSign(const MachineInstr *MI);
@@ -2078,9 +2079,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
@@ -2151,12 +2152,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);
@@ -2906,22 +2971,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::PAC:
diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp 
b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index ad42f4b56caf2..4aedab377e917 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 251fd44b6ea31..f682a5f2fad64 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2190,6 +2190,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 babd7f6b3a058..ed8d476fe94b6 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)

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to