[llvm-branch-commits] [llvm] [AArch64][PAC] Combine signing with address materialization (PR #130809)

Anatoly Trosinenko via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Jul 16 11:26:46 PDT 2025


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

>From 33b61f5939813244d6ea812e821945bf86854a99 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Wed, 16 Jul 2025 20:34:15 +0300
Subject: [PATCH 1/6] Rewrite discriminator matching and add more test cases

---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  39 +++---
 llvm/test/CodeGen/AArch64/ptrauth-isel.ll     |  76 ++++++++++-
 llvm/test/CodeGen/AArch64/ptrauth-isel.mir    | 123 ++++++++++++++++++
 3 files changed, 216 insertions(+), 22 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-isel.mir

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index ffa406b8a2f4c..b5b0ca77dead2 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3081,8 +3081,8 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI,
 
 // Helper function to find the instruction that defined a virtual register.
 // If unable to find such instruction, returns nullptr.
-static MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI,
-                                     Register Reg) {
+static const MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI,
+                                           Register Reg) {
   while (Reg.isVirtual()) {
     MachineInstr *DefMI = MRI.getVRegDef(Reg);
     assert(DefMI && "Virtual register definition not found");
@@ -3114,22 +3114,29 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
 
   Register AddrDisc = AddrDiscOp.getReg();
   int64_t IntDisc = IntDiscOp.getImm();
-
   assert(IntDisc == 0 && "Blend components are already expanded");
 
-  MachineInstr *MaybeBlend = stripVRegCopies(MRI, AddrDisc);
-
-  if (MaybeBlend) {
-    // Detect blend(addr, imm) which is lowered as "MOVK addr, #imm, #48".
-    // Alternatively, recognize small immediate modifier passed via VReg.
-    if (MaybeBlend->getOpcode() == AArch64::MOVKXi &&
-        MaybeBlend->getOperand(3).getImm() == 48) {
-      AddrDisc = MaybeBlend->getOperand(1).getReg();
-      IntDisc = MaybeBlend->getOperand(2).getImm();
-    } else if (MaybeBlend->getOpcode() == AArch64::MOVi32imm &&
-               isUInt<16>(MaybeBlend->getOperand(1).getImm())) {
-      AddrDisc = AArch64::NoRegister;
-      IntDisc = MaybeBlend->getOperand(1).getImm();
+  const MachineInstr *DiscMI = stripVRegCopies(MRI, AddrDisc);
+  if (DiscMI) {
+    switch (DiscMI->getOpcode()) {
+    case AArch64::MOVKXi:
+      // blend(addr, imm) which is lowered as "MOVK addr, #imm, #48".
+      // #imm should be an immediate and not a global symbol, for example.
+      if (DiscMI->getOperand(2).isImm() &&
+          DiscMI->getOperand(3).getImm() == 48) {
+        AddrDisc = DiscMI->getOperand(1).getReg();
+        IntDisc = DiscMI->getOperand(2).getImm();
+      }
+      break;
+    case AArch64::MOVi32imm:
+    case AArch64::MOVi64imm:
+      // Small immediate integer constant passed via VReg.
+      if (DiscMI->getOperand(1).isImm() &&
+          isUInt<16>(DiscMI->getOperand(1).getImm())) {
+        AddrDisc = AArch64::NoRegister;
+        IntDisc = DiscMI->getOperand(1).getImm();
+      }
+      break;
     }
   }
 
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
index 1815d642aa5ed..470b4e6a7bc9f 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
@@ -13,17 +13,17 @@
 
 @discvar = dso_local global i64 0
 
-; Make sure the components of blend(addr, imm) are recognized and passed to
-; PAC pseudo via separate operands to prevent substitution of the immediate
-; modifier.
+; Make sure the components of blend(addr, imm) and integer constants are
+; recognized and passed to PAC pseudo via separate operands to prevent
+; substitution of the immediate modifier.
 ;
 ; MIR output of the instruction selector is inspected, as it is hard to reliably
 ; distinguish MOVKXi immediately followed by a pseudo from a standalone pseudo
 ; instruction carrying address and immediate modifiers in its separate operands
 ; by only observing the final asm output.
 
-define i64 @small_imm_disc(i64 %addr) {
-  ; DAGISEL-LABEL: name: small_imm_disc
+define i64 @small_imm_disc_optimized(i64 %addr) {
+  ; DAGISEL-LABEL: name: small_imm_disc_optimized
   ; DAGISEL: bb.0.entry:
   ; DAGISEL-NEXT:   liveins: $x0
   ; DAGISEL-NEXT: {{  $}}
@@ -34,7 +34,7 @@ define i64 @small_imm_disc(i64 %addr) {
   ; DAGISEL-NEXT:   $x0 = COPY [[PAC]]
   ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
   ;
-  ; GISEL-LABEL: name: small_imm_disc
+  ; GISEL-LABEL: name: small_imm_disc_optimized
   ; GISEL: bb.1.entry:
   ; GISEL-NEXT:   liveins: $x0
   ; GISEL-NEXT: {{  $}}
@@ -49,6 +49,35 @@ entry:
   ret i64 %signed
 }
 
+; Without optimization, MOVi64imm may be used for small i64 constants as well.
+define i64 @small_imm_disc_non_optimized(i64 %addr) noinline optnone {
+  ; DAGISEL-LABEL: name: small_imm_disc_non_optimized
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   liveins: $x0
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY killed [[COPY]]
+  ; DAGISEL-NEXT:   [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 42
+  ; DAGISEL-NEXT:   [[SUBREG_TO_REG:%[0-9]+]]:gpr64noip = SUBREG_TO_REG 0, killed [[MOVi32imm]], %subreg.sub_32
+  ; DAGISEL-NEXT:   [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY1]], 2, 42, killed $noreg, implicit-def dead $x17
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64all = COPY [[PAC]]
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY2]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: small_imm_disc_non_optimized
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   liveins: $x0
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; GISEL-NEXT:   [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm 42
+  ; GISEL-NEXT:   [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, $noreg, implicit-def dead $x17
+  ; GISEL-NEXT:   $x0 = COPY [[PAC]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 42)
+  ret i64 %signed
+}
+
 define i64 @large_imm_disc_wreg(i64 %addr) {
   ; DAGISEL-LABEL: name: large_imm_disc_wreg
   ; DAGISEL: bb.0.entry:
@@ -101,6 +130,41 @@ entry:
   ret i64 %signed
 }
 
+; Make sure blend() is lowered as expected when optimization is disabled.
+define i64 @blended_disc_non_optimized(i64 %addr, i64 %addrdisc) noinline optnone {
+  ; DAGISEL-LABEL: name: blended_disc_non_optimized
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   liveins: $x0, $x1
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY killed [[COPY1]]
+  ; DAGISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64 = COPY killed [[COPY]]
+  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[COPY3]], 42, 48
+  ; DAGISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
+  ; DAGISEL-NEXT:   [[COPY5:%[0-9]+]]:gpr64noip = COPY [[COPY3]]
+  ; DAGISEL-NEXT:   [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY2]], 2, 42, [[COPY5]], implicit-def dead $x17
+  ; DAGISEL-NEXT:   [[COPY6:%[0-9]+]]:gpr64all = COPY [[PAC]]
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY6]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: blended_disc_non_optimized
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   liveins: $x0, $x1
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[COPY1]], 42, 48
+  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[COPY1]]
+  ; GISEL-NEXT:   [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, [[COPY2]], implicit-def dead $x17
+  ; GISEL-NEXT:   $x0 = COPY [[PAC]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
+  %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc)
+  ret i64 %signed
+}
+
 define i64 @blend_and_sign_same_bb(i64 %addr) {
   ; DAGISEL-LABEL: name: blend_and_sign_same_bb
   ; DAGISEL: bb.0.entry:
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.mir b/llvm/test/CodeGen/AArch64/ptrauth-isel.mir
new file mode 100644
index 0000000000000..f4c4260343125
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.mir
@@ -0,0 +1,123 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -o - %s -mtriple arm64e-apple-darwin             -verify-machineinstrs \
+# RUN:     -stop-after=finalize-isel -start-before=finalize-isel | FileCheck %s
+# RUN: llc -o - %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs \
+# RUN:     -stop-after=finalize-isel -start-before=finalize-isel | FileCheck %s
+
+# This MIR-based test contains several test cases that are hard to implement
+# via an LLVM IR input. Most other test cases are in ptrauth-isel.ll file.
+
+--- |
+  @globalvar = dso_local global i64 0
+
+  define i64 @movk_correct_blend(i64 %a, i64 %b) {
+  entry:
+    ret i64 0
+  }
+
+  define i64 @movk_wrong_shift_amount(i64 %a, i64 %b) {
+  entry:
+    ret i64 0
+  }
+
+  define i64 @movk_non_immediate_operand(i64 %a, i64 %b) {
+  entry:
+    ret i64 0
+  }
+
+  define i64 @movi64imm_non_immediate_operand(i64 %a) {
+  entry:
+    ret i64 0
+  }
+...
+---
+name:            movk_correct_blend
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: movk_correct_blend
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+    ; CHECK-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[COPY1]], 42, 48
+    ; CHECK-NEXT: [[COPY2:%[0-9]+]]:gpr64noip = COPY [[COPY1]]
+    ; CHECK-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 42, killed [[COPY2]], implicit-def dead $x17
+    ; CHECK-NEXT: $x0 = COPY [[PAC]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:gpr64 = COPY $x0
+    %1:gpr64 = COPY $x1
+    %2:gpr64noip = MOVKXi %1, 42, 48
+    %3:gpr64 = PAC %0, 2, 0, killed %2, implicit-def dead $x17
+    $x0 = COPY %3
+    RET_ReallyLR implicit $x0
+...
+---
+name:            movk_wrong_shift_amount
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: movk_wrong_shift_amount
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+    ; CHECK-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[COPY1]], 42, 0
+    ; CHECK-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[MOVKXi]], implicit-def dead $x17
+    ; CHECK-NEXT: $x0 = COPY [[PAC]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:gpr64 = COPY $x0
+    %1:gpr64 = COPY $x1
+    %2:gpr64noip = MOVKXi %1, 42, 0
+    %3:gpr64 = PAC %0, 2, 0, killed %2, implicit-def dead $x17
+    $x0 = COPY %3
+    RET_ReallyLR implicit $x0
+...
+---
+name:            movk_non_immediate_operand
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: movk_non_immediate_operand
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+    ; CHECK-NEXT: [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[COPY1]], target-flags(aarch64-pageoff, aarch64-nc) @globalvar, 48
+    ; CHECK-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[MOVKXi]], implicit-def dead $x17
+    ; CHECK-NEXT: $x0 = COPY [[PAC]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:gpr64 = COPY $x0
+    %1:gpr64 = COPY $x1
+    %2:gpr64noip = MOVKXi %1, target-flags(aarch64-pageoff, aarch64-nc) @globalvar, 48
+    %3:gpr64 = PAC %0, 2, 0, killed %2, implicit-def dead $x17
+    $x0 = COPY %3
+    RET_ReallyLR implicit $x0
+...
+---
+name:            movi64imm_non_immediate_operand
+tracksRegLiveness: true
+body:             |
+  bb.0.entry:
+    liveins: $x0, $x1
+
+    ; CHECK-LABEL: name: movi64imm_non_immediate_operand
+    ; CHECK: liveins: $x0, $x1
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+    ; CHECK-NEXT: [[MOVi64imm:%[0-9]+]]:gpr64noip = MOVi64imm target-flags(aarch64-pageoff, aarch64-nc) @globalvar
+    ; CHECK-NEXT: [[PAC:%[0-9]+]]:gpr64 = PAC [[COPY]], 2, 0, killed [[MOVi64imm]], implicit-def dead $x17
+    ; CHECK-NEXT: $x0 = COPY [[PAC]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $x0
+    %0:gpr64 = COPY $x0
+    %1:gpr64noip = MOVi64imm target-flags(aarch64-pageoff, aarch64-nc) @globalvar
+    %2:gpr64 = PAC %0, 2, 0, killed %1, implicit-def dead $x17
+    $x0 = COPY %2
+    RET_ReallyLR implicit $x0
+...

>From fcfed9242321e1ed19806ee0d9c98743d9ea41d7 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Sat, 28 Jun 2025 11:09:01 +0300
Subject: [PATCH 2/6] [AArch64][PAC] Rework discriminator analysis in AUT and
 AUTPAC

Make use of post-processing the discriminator components by custom
inserter hook to eliminate duplication for DAGISel and GlobalISel and
improve cross-BB analysis for DAGISel.
---
 .../Target/AArch64/AArch64ISelDAGToDAG.cpp    |  53 +---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  10 +
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   2 +
 .../GISel/AArch64InstructionSelector.cpp      |  31 +--
 llvm/test/CodeGen/AArch64/ptrauth-isel.ll     | 235 +++++++++++++++++-
 5 files changed, 259 insertions(+), 72 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index eca7ca566cfc2..475997f42ba82 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -1487,39 +1487,6 @@ void AArch64DAGToDAGISel::SelectTable(SDNode *N, unsigned NumVecs, unsigned Opc,
   ReplaceNode(N, CurDAG->getMachineNode(Opc, dl, VT, Ops));
 }
 
-static std::tuple<SDValue, SDValue>
-extractPtrauthBlendDiscriminators(SDValue Disc, SelectionDAG *DAG) {
-  SDLoc DL(Disc);
-  SDValue AddrDisc;
-  SDValue ConstDisc;
-
-  // If this is a blend, remember the constant and address discriminators.
-  // Otherwise, it's either a constant discriminator, or a non-blended
-  // address discriminator.
-  if (Disc->getOpcode() == ISD::INTRINSIC_WO_CHAIN &&
-      Disc->getConstantOperandVal(0) == Intrinsic::ptrauth_blend) {
-    AddrDisc = Disc->getOperand(1);
-    ConstDisc = Disc->getOperand(2);
-  } else {
-    ConstDisc = Disc;
-  }
-
-  // If the constant discriminator (either the blend RHS, or the entire
-  // discriminator value) isn't a 16-bit constant, bail out, and let the
-  // discriminator be computed separately.
-  auto *ConstDiscN = dyn_cast<ConstantSDNode>(ConstDisc);
-  if (!ConstDiscN || !isUInt<16>(ConstDiscN->getZExtValue()))
-    return std::make_tuple(DAG->getTargetConstant(0, DL, MVT::i64), Disc);
-
-  // If there's no address discriminator, use XZR directly.
-  if (!AddrDisc)
-    AddrDisc = DAG->getRegister(AArch64::XZR, MVT::i64);
-
-  return std::make_tuple(
-      DAG->getTargetConstant(ConstDiscN->getZExtValue(), DL, MVT::i64),
-      AddrDisc);
-}
-
 void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
   SDLoc DL(N);
   // IntrinsicID is operand #0
@@ -1530,12 +1497,10 @@ void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
   unsigned AUTKeyC = cast<ConstantSDNode>(AUTKey)->getZExtValue();
   AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64);
 
-  SDValue AUTAddrDisc, AUTConstDisc;
-  std::tie(AUTConstDisc, AUTAddrDisc) =
-      extractPtrauthBlendDiscriminators(AUTDisc, CurDAG);
+  SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i64);
 
   if (!Subtarget->isX16X17Safer()) {
-    SDValue Ops[] = {Val, AUTKey, AUTConstDisc, AUTAddrDisc};
+    SDValue Ops[] = {Val, AUTKey, Zero, AUTDisc};
 
     SDNode *AUT =
         CurDAG->getMachineNode(AArch64::AUTxMxN, DL, MVT::i64, MVT::i64, Ops);
@@ -1543,7 +1508,7 @@ void AArch64DAGToDAGISel::SelectPtrauthAuth(SDNode *N) {
   } else {
     SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
                                            AArch64::X16, Val, SDValue());
-    SDValue Ops[] = {AUTKey, AUTConstDisc, AUTAddrDisc, X16Copy.getValue(1)};
+    SDValue Ops[] = {AUTKey, Zero, AUTDisc, X16Copy.getValue(1)};
 
     SDNode *AUT = CurDAG->getMachineNode(AArch64::AUTx16x17, DL, MVT::i64, Ops);
     ReplaceNode(N, AUT);
@@ -1565,19 +1530,13 @@ void AArch64DAGToDAGISel::SelectPtrauthResign(SDNode *N) {
   AUTKey = CurDAG->getTargetConstant(AUTKeyC, DL, MVT::i64);
   PACKey = CurDAG->getTargetConstant(PACKeyC, DL, MVT::i64);
 
-  SDValue AUTAddrDisc, AUTConstDisc;
-  std::tie(AUTConstDisc, AUTAddrDisc) =
-      extractPtrauthBlendDiscriminators(AUTDisc, CurDAG);
-
-  SDValue PACAddrDisc, PACConstDisc;
-  std::tie(PACConstDisc, PACAddrDisc) =
-      extractPtrauthBlendDiscriminators(PACDisc, CurDAG);
+  SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i64);
 
   SDValue X16Copy = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL,
                                          AArch64::X16, Val, SDValue());
 
-  SDValue Ops[] = {AUTKey,       AUTConstDisc, AUTAddrDisc,        PACKey,
-                   PACConstDisc, PACAddrDisc,  X16Copy.getValue(1)};
+  SDValue Ops[] = {
+      AUTKey, Zero, AUTDisc, PACKey, Zero, PACDisc, X16Copy.getValue(1)};
 
   SDNode *AUTPAC = CurDAG->getMachineNode(AArch64::AUTPAC, DL, MVT::i64, Ops);
   ReplaceNode(N, AUTPAC);
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b5b0ca77dead2..c70505aabb283 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3255,10 +3255,20 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
   case AArch64::MOVT_TIZ_PSEUDO:
     return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
 
+  case AArch64::AUT:
+    fixupBlendComponents(MI, BB, MI.getOperand(1), MI.getOperand(2),
+                         &AArch64::GPR64noipRegClass);
+    return BB;
   case AArch64::PAC:
     fixupPtrauthDiscriminator(MI, BB, MI.getOperand(3), MI.getOperand(4),
                               &AArch64::GPR64noipRegClass);
     return BB;
+  case AArch64::AUTPAC:
+    fixupBlendComponents(MI, BB, MI.getOperand(1), MI.getOperand(2),
+                         &AArch64::GPR64noipRegClass);
+    fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
+                         &AArch64::GPR64noipRegClass);
+    return BB;
   }
 }
 
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f637cc3343418..fe3de4f3c173f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2141,6 +2141,7 @@ let Predicates = [HasPAuth] in {
     let Size = 32;
     let Defs = [X16,X17,NZCV];
     let Uses = [X16];
+    let usesCustomInserter = 1;
   }
 
   def AUTxMxN : Pseudo<(outs GPR64:$AuthVal, GPR64common:$Scratch),
@@ -2190,6 +2191,7 @@ let Predicates = [HasPAuth] in {
     let Size = 48;
     let Defs = [X16,X17,NZCV];
     let Uses = [X16];
+    let usesCustomInserter = 1;
   }
 
   // Materialize a signed global address, with adrp+add and PAC.
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 1381a9b70df87..2692685317f2f 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -6725,25 +6725,15 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
     uint64_t PACKey = I.getOperand(5).getImm();
     Register PACDisc = I.getOperand(6).getReg();
 
-    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(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
     MIB.buildInstr(AArch64::AUTPAC)
         .addImm(AUTKey)
-        .addImm(AUTConstDiscC)
-        .addUse(AUTAddrDisc)
+        .addImm(0)
+        .addUse(AUTDisc)
         .addImm(PACKey)
-        .addImm(PACConstDiscC)
-        .addUse(PACAddrDisc)
+        .addImm(0)
+        .addUse(PACDisc)
         .constrainAllUses(TII, TRI, RBI);
     MIB.buildCopy({DstReg}, Register(AArch64::X16));
 
@@ -6757,18 +6747,13 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
     uint64_t AUTKey = I.getOperand(3).getImm();
     Register AUTDisc = I.getOperand(4).getReg();
 
-    Register AUTAddrDisc = AUTDisc;
-    uint16_t AUTConstDiscC = 0;
-    std::tie(AUTConstDiscC, AUTAddrDisc) =
-        extractPtrauthBlendDiscriminators(AUTDisc, MRI);
-
     if (STI.isX16X17Safer()) {
       MIB.buildCopy({AArch64::X16}, {ValReg});
       MIB.buildInstr(TargetOpcode::IMPLICIT_DEF, {AArch64::X17}, {});
       MIB.buildInstr(AArch64::AUTx16x17)
           .addImm(AUTKey)
-          .addImm(AUTConstDiscC)
-          .addUse(AUTAddrDisc)
+          .addImm(0)
+          .addUse(AUTDisc)
           .constrainAllUses(TII, TRI, RBI);
       MIB.buildCopy({DstReg}, Register(AArch64::X16));
     } else {
@@ -6779,8 +6764,8 @@ bool AArch64InstructionSelector::selectIntrinsic(MachineInstr &I,
           .addDef(ScratchReg)
           .addUse(ValReg)
           .addImm(AUTKey)
-          .addImm(AUTConstDiscC)
-          .addUse(AUTAddrDisc)
+          .addImm(0)
+          .addUse(AUTDisc)
           .constrainAllUses(TII, TRI, RBI);
     }
 
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
index 470b4e6a7bc9f..84f8ccbd15b74 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
@@ -14,8 +14,8 @@
 @discvar = dso_local global i64 0
 
 ; Make sure the components of blend(addr, imm) and integer constants are
-; recognized and passed to PAC pseudo via separate operands to prevent
-; substitution of the immediate modifier.
+; recognized and passed to AUT / PAC / AUTPAC pseudo via separate operands
+; prevent substitution of the immediate modifier.
 ;
 ; MIR output of the instruction selector is inspected, as it is hard to reliably
 ; distinguish MOVKXi immediately followed by a pseudo from a standalone pseudo
@@ -165,6 +165,44 @@ entry:
   ret i64 %signed
 }
 
+define i64 @blend_and_auth_same_bb(i64 %addr) {
+  ; DAGISEL-LABEL: name: blend_and_auth_same_bb
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   liveins: $x0
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   AUT 2, 42, killed [[COPY1]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY2]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: blend_and_auth_same_bb
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   liveins: $x0
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   AUT 2, 42, [[COPY1]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-NEXT:   $x0 = COPY [[COPY2]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %addrdisc = load i64, ptr @discvar
+  %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
+  %authed = call i64 @llvm.ptrauth.auth(i64 %addr, i32 2, i64 %disc)
+  ret i64 %authed
+}
+
 define i64 @blend_and_sign_same_bb(i64 %addr) {
   ; DAGISEL-LABEL: name: blend_and_sign_same_bb
   ; DAGISEL: bb.0.entry:
@@ -198,10 +236,124 @@ entry:
   ret i64 %signed
 }
 
+define i64 @blend_and_resign_same_bb(i64 %addr) {
+  ; DAGISEL-LABEL: name: blend_and_resign_same_bb
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   liveins: $x0
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-NEXT:   [[MOVKXi1:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 123, 48
+  ; DAGISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   AUTPAC 2, 42, killed [[COPY1]], 3, 123, killed [[COPY2]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY3]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: blend_and_resign_same_bb
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   liveins: $x0
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-NEXT:   [[MOVKXi1:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 123, 48
+  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   AUTPAC 2, 42, [[COPY1]], 3, 123, [[COPY2]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-NEXT:   $x0 = COPY [[COPY3]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %addrdisc = load i64, ptr @discvar
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 123)
+  %resigned = call i64 @llvm.ptrauth.resign(i64 %addr, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  ret i64 %resigned
+}
+
 ; In the below test cases both %addrdisc and %disc are computed (i.e. they are
 ; neither global addresses, nor function arguments) in a different basic block,
 ; making them harder to express via ISD::PtrAuthGlobalAddress.
 
+define i64 @blend_and_auth_different_bbs(i64 %addr, i64 %cond) {
+  ; DAGISEL-LABEL: name: blend_and_auth_different_bbs
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
+  ; DAGISEL-NEXT:   liveins: $x0, $x1
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
+  ; DAGISEL-NEXT:   CBZX [[COPY]], %bb.2
+  ; DAGISEL-NEXT:   B %bb.1
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT: bb.1.next:
+  ; DAGISEL-NEXT:   successors: %bb.2(0x80000000)
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]]
+  ; DAGISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]]
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT: bb.2.exit:
+  ; DAGISEL-NEXT:   $x16 = COPY [[COPY1]]
+  ; DAGISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   AUT 2, 42, [[COPY4]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-NEXT:   [[COPY5:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY5]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: blend_and_auth_different_bbs
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; GISEL-NEXT:   liveins: $x0, $x1
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-NEXT:   CBZX [[COPY1]], %bb.3
+  ; GISEL-NEXT:   B %bb.2
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT: bb.2.next:
+  ; GISEL-NEXT:   successors: %bb.3(0x80000000)
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
+  ; GISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]]
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT: bb.3.exit:
+  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   AUT 2, 42, [[COPY3]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-NEXT:   $x0 = COPY [[COPY4]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %addrdisc = load i64, ptr @discvar
+  %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
+  %cond.b = icmp ne i64 %cond, 0
+  br i1 %cond.b, label %next, label %exit
+
+next:
+  call void asm sideeffect "nop", "r"(i64 %disc)
+  br label %exit
+
+exit:
+  %authed = call i64 @llvm.ptrauth.auth(i64 %addr, i32 2, i64 %disc)
+  ret i64 %authed
+}
+
 define i64 @blend_and_sign_different_bbs(i64 %addr, i64 %cond) {
   ; DAGISEL-LABEL: name: blend_and_sign_different_bbs
   ; DAGISEL: bb.0.entry:
@@ -267,3 +419,82 @@ exit:
   %signed = call i64 @llvm.ptrauth.sign(i64 %addr, i32 2, i64 %disc)
   ret i64 %signed
 }
+
+define i64 @blend_and_resign_different_bbs(i64 %addr, i64 %cond) {
+  ; DAGISEL-LABEL: name: blend_and_resign_different_bbs
+  ; DAGISEL: bb.0.entry:
+  ; DAGISEL-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
+  ; DAGISEL-NEXT:   liveins: $x0, $x1
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
+  ; DAGISEL-NEXT:   [[MOVKXi1:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 123, 48
+  ; DAGISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64noip = COPY [[MOVKXi1]]
+  ; DAGISEL-NEXT:   CBZX [[COPY]], %bb.2
+  ; DAGISEL-NEXT:   B %bb.1
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT: bb.1.next:
+  ; DAGISEL-NEXT:   successors: %bb.2(0x80000000)
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64common = COPY [[COPY2]]
+  ; DAGISEL-NEXT:   [[COPY5:%[0-9]+]]:gpr64common = COPY [[COPY3]]
+  ; DAGISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY4]], 3866633 /* reguse:GPR64common */, [[COPY5]]
+  ; DAGISEL-NEXT: {{  $}}
+  ; DAGISEL-NEXT: bb.2.exit:
+  ; DAGISEL-NEXT:   $x16 = COPY [[COPY1]]
+  ; DAGISEL-NEXT:   [[COPY6:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   [[COPY7:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-NEXT:   AUTPAC 2, 42, [[COPY6]], 3, 123, [[COPY7]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-NEXT:   [[COPY8:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-NEXT:   $x0 = COPY [[COPY8]]
+  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-LABEL: name: blend_and_resign_different_bbs
+  ; GISEL: bb.1.entry:
+  ; GISEL-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; GISEL-NEXT:   liveins: $x0, $x1
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-NEXT:   [[MOVKXi1:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 123, 48
+  ; GISEL-NEXT:   CBZX [[COPY1]], %bb.3
+  ; GISEL-NEXT:   B %bb.2
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT: bb.2.next:
+  ; GISEL-NEXT:   successors: %bb.3(0x80000000)
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
+  ; GISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64common = COPY [[MOVKXi1]]
+  ; GISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]], 3866633 /* reguse:GPR64common */, [[COPY3]]
+  ; GISEL-NEXT: {{  $}}
+  ; GISEL-NEXT: bb.3.exit:
+  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   [[COPY5:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-NEXT:   AUTPAC 2, 42, [[COPY4]], 3, 123, [[COPY5]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-NEXT:   [[COPY6:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-NEXT:   $x0 = COPY [[COPY6]]
+  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+entry:
+  %addrdisc = load i64, ptr @discvar
+  %auth.disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
+  %sign.disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 123)
+  %cond.b = icmp ne i64 %cond, 0
+  br i1 %cond.b, label %next, label %exit
+
+next:
+  call void asm sideeffect "nop", "r,r"(i64 %auth.disc, i64 %sign.disc)
+  br label %exit
+
+exit:
+  %resigned = call i64 @llvm.ptrauth.resign(i64 %addr, i32 2, i64 %auth.disc, i32 3, i64 %sign.disc)
+  ret i64 %resigned
+}

>From 4f031ea52bc513543824fbabfe4f33384c6a562f Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 10 Jul 2025 16:04:43 +0300
Subject: [PATCH 3/6] Update tests

---
 .../Target/AArch64/AArch64ISelLowering.cpp    |   6 +-
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   1 +
 llvm/test/CodeGen/AArch64/ptrauth-isel.ll     | 251 ++++++++++++------
 3 files changed, 170 insertions(+), 88 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index c70505aabb283..6f6466a57d648 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3255,10 +3255,14 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
   case AArch64::MOVT_TIZ_PSEUDO:
     return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
 
-  case AArch64::AUT:
+  case AArch64::AUTx16x17:
     fixupBlendComponents(MI, BB, MI.getOperand(1), MI.getOperand(2),
                          &AArch64::GPR64noipRegClass);
     return BB;
+  case AArch64::AUTxMxN:
+    fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
+                         &AArch64::GPR64noipRegClass);
+    return BB;
   case AArch64::PAC:
     fixupPtrauthDiscriminator(MI, BB, MI.getOperand(3), MI.getOperand(4),
                               &AArch64::GPR64noipRegClass);
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index fe3de4f3c173f..35d96168a1518 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2155,6 +2155,7 @@ let Predicates = [HasPAuth] in {
     let Size = 32;
     let Defs = [NZCV];
     let Uses = [];
+    let usesCustomInserter = 1;
   }
 
   // PAC pseudo instruction. Is AsmPrinter, it is expanded into an actual PAC*
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
index 84f8ccbd15b74..0559fd783f5a3 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-isel.ll
@@ -1,12 +1,12 @@
 ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
 ; RUN: llc < %s -mtriple arm64e-apple-darwin             -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
-; RUN:     | FileCheck %s --check-prefixes=DAGISEL
+; RUN:     | FileCheck %s --check-prefixes=DAGISEL,DAGISEL-DARWIN
 ; RUN: llc < %s -mtriple arm64e-apple-darwin             -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
-; RUN:     | FileCheck %s --check-prefixes=GISEL
+; RUN:     | FileCheck %s --check-prefixes=GISEL,GISEL-DARWIN
 ; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=0 \
-; RUN:     | FileCheck %s --check-prefixes=DAGISEL
+; RUN:     | FileCheck %s --check-prefixes=DAGISEL,DAGISEL-ELF
 ; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 \
-; RUN:     | FileCheck %s --check-prefixes=GISEL
+; RUN:     | FileCheck %s --check-prefixes=GISEL,GISEL-ELF
 
 ; Check MIR produced by the instruction selector to validate properties that
 ; cannot be reliably tested by only inspecting the final asm output.
@@ -166,36 +166,62 @@ entry:
 }
 
 define i64 @blend_and_auth_same_bb(i64 %addr) {
-  ; DAGISEL-LABEL: name: blend_and_auth_same_bb
-  ; DAGISEL: bb.0.entry:
-  ; DAGISEL-NEXT:   liveins: $x0
-  ; DAGISEL-NEXT: {{  $}}
-  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
-  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
-  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
-  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
-  ; DAGISEL-NEXT:   $x16 = COPY [[COPY]]
-  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
-  ; DAGISEL-NEXT:   AUT 2, 42, killed [[COPY1]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
-  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64all = COPY $x16
-  ; DAGISEL-NEXT:   $x0 = COPY [[COPY2]]
-  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ; DAGISEL-DARWIN-LABEL: name: blend_and_auth_same_bb
+  ; DAGISEL-DARWIN: bb.0.entry:
+  ; DAGISEL-DARWIN-NEXT:   liveins: $x0
+  ; DAGISEL-DARWIN-NEXT: {{  $}}
+  ; DAGISEL-DARWIN-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-DARWIN-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-DARWIN-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-DARWIN-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-DARWIN-NEXT:   $x16 = COPY [[COPY]]
+  ; DAGISEL-DARWIN-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-DARWIN-NEXT:   AUTx16x17 2, 42, killed [[COPY1]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-DARWIN-NEXT:   [[COPY2:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-DARWIN-NEXT:   $x0 = COPY [[COPY2]]
+  ; DAGISEL-DARWIN-NEXT:   RET_ReallyLR implicit $x0
   ;
-  ; GISEL-LABEL: name: blend_and_auth_same_bb
-  ; GISEL: bb.1.entry:
-  ; GISEL-NEXT:   liveins: $x0
-  ; GISEL-NEXT: {{  $}}
-  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
-  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
-  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
-  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
-  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
-  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
-  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
-  ; GISEL-NEXT:   AUT 2, 42, [[COPY1]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
-  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY $x16
-  ; GISEL-NEXT:   $x0 = COPY [[COPY2]]
-  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+  ; GISEL-DARWIN-LABEL: name: blend_and_auth_same_bb
+  ; GISEL-DARWIN: bb.1.entry:
+  ; GISEL-DARWIN-NEXT:   liveins: $x0
+  ; GISEL-DARWIN-NEXT: {{  $}}
+  ; GISEL-DARWIN-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-DARWIN-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-DARWIN-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-DARWIN-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-DARWIN-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-DARWIN-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-DARWIN-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-DARWIN-NEXT:   AUTx16x17 2, 42, [[COPY1]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-DARWIN-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-DARWIN-NEXT:   $x0 = COPY [[COPY2]]
+  ; GISEL-DARWIN-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; DAGISEL-ELF-LABEL: name: blend_and_auth_same_bb
+  ; DAGISEL-ELF: bb.0.entry:
+  ; DAGISEL-ELF-NEXT:   liveins: $x0
+  ; DAGISEL-ELF-NEXT: {{  $}}
+  ; DAGISEL-ELF-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-ELF-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-ELF-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-ELF-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-ELF-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-ELF-NEXT:   [[AUTxMxN:%[0-9]+]]:gpr64, [[AUTxMxN1:%[0-9]+]]:gpr64common = AUTxMxN [[COPY]], 2, 42, killed [[COPY1]], implicit-def dead $nzcv
+  ; DAGISEL-ELF-NEXT:   $x0 = COPY [[AUTxMxN]]
+  ; DAGISEL-ELF-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-ELF-LABEL: name: blend_and_auth_same_bb
+  ; GISEL-ELF: bb.1.entry:
+  ; GISEL-ELF-NEXT:   liveins: $x0
+  ; GISEL-ELF-NEXT: {{  $}}
+  ; GISEL-ELF-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; GISEL-ELF-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-ELF-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-ELF-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-ELF-NEXT:   [[COPY1:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-ELF-NEXT:   [[AUTxMxN:%[0-9]+]]:gpr64, [[AUTxMxN1:%[0-9]+]]:gpr64common = AUTxMxN [[COPY]], 2, 42, [[COPY1]], implicit-def dead $nzcv
+  ; GISEL-ELF-NEXT:   $x0 = COPY [[AUTxMxN]]
+  ; GISEL-ELF-NEXT:   RET_ReallyLR implicit $x0
 entry:
   %addrdisc = load i64, ptr @discvar
   %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)
@@ -284,61 +310,112 @@ entry:
 ; making them harder to express via ISD::PtrAuthGlobalAddress.
 
 define i64 @blend_and_auth_different_bbs(i64 %addr, i64 %cond) {
-  ; DAGISEL-LABEL: name: blend_and_auth_different_bbs
-  ; DAGISEL: bb.0.entry:
-  ; DAGISEL-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
-  ; DAGISEL-NEXT:   liveins: $x0, $x1
-  ; DAGISEL-NEXT: {{  $}}
-  ; DAGISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
-  ; DAGISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
-  ; DAGISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
-  ; DAGISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
-  ; DAGISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
-  ; DAGISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
-  ; DAGISEL-NEXT:   CBZX [[COPY]], %bb.2
-  ; DAGISEL-NEXT:   B %bb.1
-  ; DAGISEL-NEXT: {{  $}}
-  ; DAGISEL-NEXT: bb.1.next:
-  ; DAGISEL-NEXT:   successors: %bb.2(0x80000000)
-  ; DAGISEL-NEXT: {{  $}}
-  ; DAGISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]]
-  ; DAGISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]]
-  ; DAGISEL-NEXT: {{  $}}
-  ; DAGISEL-NEXT: bb.2.exit:
-  ; DAGISEL-NEXT:   $x16 = COPY [[COPY1]]
-  ; DAGISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
-  ; DAGISEL-NEXT:   AUT 2, 42, [[COPY4]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
-  ; DAGISEL-NEXT:   [[COPY5:%[0-9]+]]:gpr64all = COPY $x16
-  ; DAGISEL-NEXT:   $x0 = COPY [[COPY5]]
-  ; DAGISEL-NEXT:   RET_ReallyLR implicit $x0
+  ; DAGISEL-DARWIN-LABEL: name: blend_and_auth_different_bbs
+  ; DAGISEL-DARWIN: bb.0.entry:
+  ; DAGISEL-DARWIN-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
+  ; DAGISEL-DARWIN-NEXT:   liveins: $x0, $x1
+  ; DAGISEL-DARWIN-NEXT: {{  $}}
+  ; DAGISEL-DARWIN-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+  ; DAGISEL-DARWIN-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-DARWIN-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-DARWIN-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-DARWIN-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-DARWIN-NEXT:   [[COPY2:%[0-9]+]]:gpr64noip = COPY [[MOVKXi]]
+  ; DAGISEL-DARWIN-NEXT:   CBZX [[COPY]], %bb.2
+  ; DAGISEL-DARWIN-NEXT:   B %bb.1
+  ; DAGISEL-DARWIN-NEXT: {{  $}}
+  ; DAGISEL-DARWIN-NEXT: bb.1.next:
+  ; DAGISEL-DARWIN-NEXT:   successors: %bb.2(0x80000000)
+  ; DAGISEL-DARWIN-NEXT: {{  $}}
+  ; DAGISEL-DARWIN-NEXT:   [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]]
+  ; DAGISEL-DARWIN-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]]
+  ; DAGISEL-DARWIN-NEXT: {{  $}}
+  ; DAGISEL-DARWIN-NEXT: bb.2.exit:
+  ; DAGISEL-DARWIN-NEXT:   $x16 = COPY [[COPY1]]
+  ; DAGISEL-DARWIN-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-DARWIN-NEXT:   AUTx16x17 2, 42, [[COPY4]], implicit-def $x16, implicit-def dead $x17, implicit-def dead $nzcv, implicit $x16
+  ; DAGISEL-DARWIN-NEXT:   [[COPY5:%[0-9]+]]:gpr64all = COPY $x16
+  ; DAGISEL-DARWIN-NEXT:   $x0 = COPY [[COPY5]]
+  ; DAGISEL-DARWIN-NEXT:   RET_ReallyLR implicit $x0
   ;
-  ; GISEL-LABEL: name: blend_and_auth_different_bbs
-  ; GISEL: bb.1.entry:
-  ; GISEL-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
-  ; GISEL-NEXT:   liveins: $x0, $x1
-  ; GISEL-NEXT: {{  $}}
-  ; GISEL-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
-  ; GISEL-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
-  ; GISEL-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
-  ; GISEL-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
-  ; GISEL-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
-  ; GISEL-NEXT:   CBZX [[COPY1]], %bb.3
-  ; GISEL-NEXT:   B %bb.2
-  ; GISEL-NEXT: {{  $}}
-  ; GISEL-NEXT: bb.2.next:
-  ; GISEL-NEXT:   successors: %bb.3(0x80000000)
-  ; GISEL-NEXT: {{  $}}
-  ; GISEL-NEXT:   [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
-  ; GISEL-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]]
-  ; GISEL-NEXT: {{  $}}
-  ; GISEL-NEXT: bb.3.exit:
-  ; GISEL-NEXT:   $x16 = COPY [[COPY]]
-  ; GISEL-NEXT:   $x17 = IMPLICIT_DEF
-  ; GISEL-NEXT:   [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
-  ; GISEL-NEXT:   AUT 2, 42, [[COPY3]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
-  ; GISEL-NEXT:   [[COPY4:%[0-9]+]]:gpr64 = COPY $x16
-  ; GISEL-NEXT:   $x0 = COPY [[COPY4]]
-  ; GISEL-NEXT:   RET_ReallyLR implicit $x0
+  ; GISEL-DARWIN-LABEL: name: blend_and_auth_different_bbs
+  ; GISEL-DARWIN: bb.1.entry:
+  ; GISEL-DARWIN-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; GISEL-DARWIN-NEXT:   liveins: $x0, $x1
+  ; GISEL-DARWIN-NEXT: {{  $}}
+  ; GISEL-DARWIN-NEXT:   [[COPY:%[0-9]+]]:gpr64all = COPY $x0
+  ; GISEL-DARWIN-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+  ; GISEL-DARWIN-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-DARWIN-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-DARWIN-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64noip = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-DARWIN-NEXT:   CBZX [[COPY1]], %bb.3
+  ; GISEL-DARWIN-NEXT:   B %bb.2
+  ; GISEL-DARWIN-NEXT: {{  $}}
+  ; GISEL-DARWIN-NEXT: bb.2.next:
+  ; GISEL-DARWIN-NEXT:   successors: %bb.3(0x80000000)
+  ; GISEL-DARWIN-NEXT: {{  $}}
+  ; GISEL-DARWIN-NEXT:   [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
+  ; GISEL-DARWIN-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]]
+  ; GISEL-DARWIN-NEXT: {{  $}}
+  ; GISEL-DARWIN-NEXT: bb.3.exit:
+  ; GISEL-DARWIN-NEXT:   $x16 = COPY [[COPY]]
+  ; GISEL-DARWIN-NEXT:   $x17 = IMPLICIT_DEF
+  ; GISEL-DARWIN-NEXT:   [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-DARWIN-NEXT:   AUTx16x17 2, 42, [[COPY3]], implicit-def $x16, implicit-def $x17, implicit-def dead $nzcv, implicit $x16
+  ; GISEL-DARWIN-NEXT:   [[COPY4:%[0-9]+]]:gpr64 = COPY $x16
+  ; GISEL-DARWIN-NEXT:   $x0 = COPY [[COPY4]]
+  ; GISEL-DARWIN-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; DAGISEL-ELF-LABEL: name: blend_and_auth_different_bbs
+  ; DAGISEL-ELF: bb.0.entry:
+  ; DAGISEL-ELF-NEXT:   successors: %bb.1(0x50000000), %bb.2(0x30000000)
+  ; DAGISEL-ELF-NEXT:   liveins: $x0, $x1
+  ; DAGISEL-ELF-NEXT: {{  $}}
+  ; DAGISEL-ELF-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x1
+  ; DAGISEL-ELF-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x0
+  ; DAGISEL-ELF-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; DAGISEL-ELF-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui killed [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; DAGISEL-ELF-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; DAGISEL-ELF-NEXT:   [[COPY2:%[0-9]+]]:gpr64 = COPY [[MOVKXi]]
+  ; DAGISEL-ELF-NEXT:   CBZX [[COPY]], %bb.2
+  ; DAGISEL-ELF-NEXT:   B %bb.1
+  ; DAGISEL-ELF-NEXT: {{  $}}
+  ; DAGISEL-ELF-NEXT: bb.1.next:
+  ; DAGISEL-ELF-NEXT:   successors: %bb.2(0x80000000)
+  ; DAGISEL-ELF-NEXT: {{  $}}
+  ; DAGISEL-ELF-NEXT:   [[COPY3:%[0-9]+]]:gpr64common = COPY [[COPY2]]
+  ; DAGISEL-ELF-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY3]]
+  ; DAGISEL-ELF-NEXT: {{  $}}
+  ; DAGISEL-ELF-NEXT: bb.2.exit:
+  ; DAGISEL-ELF-NEXT:   [[COPY4:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; DAGISEL-ELF-NEXT:   [[AUTxMxN:%[0-9]+]]:gpr64, [[AUTxMxN1:%[0-9]+]]:gpr64common = AUTxMxN [[COPY1]], 2, 42, [[COPY4]], implicit-def dead $nzcv
+  ; DAGISEL-ELF-NEXT:   $x0 = COPY [[AUTxMxN]]
+  ; DAGISEL-ELF-NEXT:   RET_ReallyLR implicit $x0
+  ;
+  ; GISEL-ELF-LABEL: name: blend_and_auth_different_bbs
+  ; GISEL-ELF: bb.1.entry:
+  ; GISEL-ELF-NEXT:   successors: %bb.2(0x50000000), %bb.3(0x30000000)
+  ; GISEL-ELF-NEXT:   liveins: $x0, $x1
+  ; GISEL-ELF-NEXT: {{  $}}
+  ; GISEL-ELF-NEXT:   [[COPY:%[0-9]+]]:gpr64 = COPY $x0
+  ; GISEL-ELF-NEXT:   [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
+  ; GISEL-ELF-NEXT:   [[ADRP:%[0-9]+]]:gpr64common = ADRP target-flags(aarch64-page) @discvar
+  ; GISEL-ELF-NEXT:   [[LDRXui:%[0-9]+]]:gpr64 = LDRXui [[ADRP]], target-flags(aarch64-pageoff, aarch64-nc) @discvar :: (dereferenceable load (s64) from @discvar)
+  ; GISEL-ELF-NEXT:   [[MOVKXi:%[0-9]+]]:gpr64 = MOVKXi [[LDRXui]], 42, 48
+  ; GISEL-ELF-NEXT:   CBZX [[COPY1]], %bb.3
+  ; GISEL-ELF-NEXT:   B %bb.2
+  ; GISEL-ELF-NEXT: {{  $}}
+  ; GISEL-ELF-NEXT: bb.2.next:
+  ; GISEL-ELF-NEXT:   successors: %bb.3(0x80000000)
+  ; GISEL-ELF-NEXT: {{  $}}
+  ; GISEL-ELF-NEXT:   [[COPY2:%[0-9]+]]:gpr64common = COPY [[MOVKXi]]
+  ; GISEL-ELF-NEXT:   INLINEASM &nop, 1 /* sideeffect attdialect */, 3866633 /* reguse:GPR64common */, [[COPY2]]
+  ; GISEL-ELF-NEXT: {{  $}}
+  ; GISEL-ELF-NEXT: bb.3.exit:
+  ; GISEL-ELF-NEXT:   [[COPY3:%[0-9]+]]:gpr64noip = COPY [[LDRXui]]
+  ; GISEL-ELF-NEXT:   [[AUTxMxN:%[0-9]+]]:gpr64, [[AUTxMxN1:%[0-9]+]]:gpr64common = AUTxMxN [[COPY]], 2, 42, [[COPY3]], implicit-def dead $nzcv
+  ; GISEL-ELF-NEXT:   $x0 = COPY [[AUTxMxN]]
+  ; GISEL-ELF-NEXT:   RET_ReallyLR implicit $x0
 entry:
   %addrdisc = load i64, ptr @discvar
   %disc = call i64 @llvm.ptrauth.blend(i64 %addrdisc, i64 42)

>From f00d4a8684d2fefa4f071c7de5042954008a830c Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 10 Jul 2025 21:39:24 +0300
Subject: [PATCH 4/6] s/fixupBlendComponents/fixupPtrauthDiscriminator/

---
 llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 6f6466a57d648..7749f63213026 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3256,22 +3256,22 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
     return EmitZTInstr(MI, BB, AArch64::MOVT_TIZ, /*Op0IsDef=*/true);
 
   case AArch64::AUTx16x17:
-    fixupBlendComponents(MI, BB, MI.getOperand(1), MI.getOperand(2),
-                         &AArch64::GPR64noipRegClass);
+    fixupPtrauthDiscriminator(MI, BB, MI.getOperand(1), MI.getOperand(2),
+                              &AArch64::GPR64noipRegClass);
     return BB;
   case AArch64::AUTxMxN:
-    fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
-                         &AArch64::GPR64noipRegClass);
+    fixupPtrauthDiscriminator(MI, BB, MI.getOperand(4), MI.getOperand(5),
+                              &AArch64::GPR64noipRegClass);
     return BB;
   case AArch64::PAC:
     fixupPtrauthDiscriminator(MI, BB, MI.getOperand(3), MI.getOperand(4),
                               &AArch64::GPR64noipRegClass);
     return BB;
   case AArch64::AUTPAC:
-    fixupBlendComponents(MI, BB, MI.getOperand(1), MI.getOperand(2),
-                         &AArch64::GPR64noipRegClass);
-    fixupBlendComponents(MI, BB, MI.getOperand(4), MI.getOperand(5),
-                         &AArch64::GPR64noipRegClass);
+    fixupPtrauthDiscriminator(MI, BB, MI.getOperand(1), MI.getOperand(2),
+                              &AArch64::GPR64noipRegClass);
+    fixupPtrauthDiscriminator(MI, BB, MI.getOperand(4), MI.getOperand(5),
+                              &AArch64::GPR64noipRegClass);
     return BB;
   }
 }

>From 318279e5d7237165105d601b0dd3de1537579d90 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Mon, 10 Mar 2025 15:14:55 +0300
Subject: [PATCH 5/6] [AArch64][PAC] Precommit tests on merging
 MOVaddr/LOADgotAUTH with PAC*

---
 .../GlobalISel/ptrauth-constant-in-code.ll    | 76 +++++++++++++++++++
 .../AArch64/ptrauth-constant-in-code.ll       | 71 +++++++++++++++++
 2 files changed, 147 insertions(+)

diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
index 12a3448111fcb..140e29f942a79 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
@@ -78,6 +78,82 @@ define ptr @foo() {
   ret ptr ptrauth (ptr @g, i32 0)
 }
 
+;--- finalize-isel.ll
+
+; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \
+; RUN:   FileCheck --check-prefixes=ISEL,ISEL-ELF %s
+; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \
+; RUN:   FileCheck --check-prefixes=ISEL %s
+
+ at const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null]
+ at const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null]
+
+define void @store_signed_const_local(ptr %dest) {
+; ISEL-LABEL: name: store_signed_const_local
+; ISEL:       body:
+; ISEL:         %0:gpr64common = COPY $x0
+; ISEL-NEXT:    %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
+; ISEL-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
+; ISEL-NEXT:    %15:gpr64noip = COPY %0
+; ISEL-NEXT:    %4:gpr64 = PAC %10, 2, 1234, %15, implicit-def dead $x17
+; ISEL-NEXT:    %14:gpr64 = COPY %4
+; ISEL-NEXT:    STRXui %14, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+define void @store_signed_const_got(ptr %dest) {
+; ISEL-ELF-LABEL: name: store_signed_const_got
+; ISEL-ELF:       body:
+; ISEL-ELF:         %0:gpr64common = COPY $x0
+; ISEL-ELF-NEXT:    %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got
+; ISEL-ELF-NEXT:    %6:gpr64common = ADDXri %7, 8, 0
+; ISEL-ELF-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
+; ISEL-ELF-NEXT:    %12:gpr64noip = COPY %0
+; ISEL-ELF-NEXT:    %4:gpr64 = PAC %6, 2, 1234, %12, implicit-def dead $x17
+; ISEL-ELF-NEXT:    %10:gpr64 = COPY %4
+; ISEL-ELF-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-ELF-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+define void @store_signed_arg(ptr %dest, ptr %p) {
+; ISEL-LABEL: name: store_signed_arg
+; ISEL:       body:
+; ISEL:         %0:gpr64common = COPY $x0
+; ISEL-NEXT:    %1:gpr64common = COPY $x1
+; ISEL-NEXT:    %3:gpr64noip = MOVKXi %0, 1234
+; ISEL-NEXT:    %6:gpr64common = ADDXri %1, 8, 0
+; ISEL-NEXT:    %12:gpr64noip = COPY %0
+; ISEL-NEXT:    %8:gpr64 = PAC %6, 2, 1234, %12, implicit-def dead $x17
+; ISEL-NEXT:    %10:gpr64 = COPY %8
+; ISEL-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1
+  %p.offset.i = ptrtoint ptr %p.offset to i64
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 %p.offset.i, i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 8, !"ptrauth-elf-got", i32 1}
+
 ;--- ok.ll
 
 ; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
index 76339a7cc5791..429ff6e5489aa 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
@@ -69,6 +69,77 @@ define ptr @foo() {
   ret ptr ptrauth (ptr @g, i32 0)
 }
 
+;--- finalize-isel.ll
+
+; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL,ISEL-ELF %s
+; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL %s
+
+ at const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null]
+ at const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null]
+
+define void @store_signed_const_local(ptr %dest) {
+; ISEL-LABEL: name: store_signed_const_local
+; ISEL:       body:
+; ISEL:         %0:gpr64common = COPY $x0
+; ISEL-NEXT:    %1:gpr64noip = MOVKXi %0, 1234
+; ISEL-NEXT:    %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
+; ISEL-NEXT:    %4:gpr64noip = COPY %0
+; ISEL-NEXT:    %3:gpr64 = PAC %2, 2, 1234, killed %4, implicit-def dead $x17
+; ISEL-NEXT:    STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+define void @store_signed_const_got(ptr %dest) {
+; ISEL-ELF-LABEL: name: store_signed_const_got
+; ISEL-ELF:       body:
+; ISEL-ELF:         %0:gpr64common = COPY $x0
+; ISEL-ELF-NEXT:    %1:gpr64noip = MOVKXi %0, 1234
+; ISEL-ELF-NEXT:    %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv
+; ISEL-ELF-NEXT:    %3:gpr64common = ADDXri killed %2, 8, 0
+; ISEL-ELF-NEXT:    %5:gpr64noip = COPY %0
+; ISEL-ELF-NEXT:    %4:gpr64 = PAC %3, 2, 1234, killed %5, implicit-def dead $x17
+; ISEL-ELF-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-ELF-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+define void @store_signed_arg(ptr %dest, ptr %p) {
+; ISEL-LABEL: name: store_signed_arg
+; ISEL:       body:
+; ISEL:         %1:gpr64common = COPY $x1
+; ISEL-NEXT:    %0:gpr64common = COPY $x0
+; ISEL-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
+; ISEL-NEXT:    %3:gpr64common = ADDXri %1, 8, 0
+; ISEL-NEXT:    %5:gpr64noip = COPY %0
+; ISEL-NEXT:    %4:gpr64 = PAC %3, 2, 1234, killed %5, implicit-def dead $x17
+; ISEL-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-NEXT:    RET_ReallyLR
+  %dest.i = ptrtoint ptr %dest to i64
+  %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
+  %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1
+  %p.offset.i = ptrtoint ptr %p.offset to i64
+  %signed.i = call i64 @llvm.ptrauth.sign(i64 %p.offset.i, i32 2, i64 %discr)
+  %signed.ptr = inttoptr i64 %signed.i to ptr
+  store ptr %signed.ptr, ptr %dest
+  ret void
+}
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 8, !"ptrauth-elf-got", i32 1}
+
 ;--- ok.ll
 
 ; RUN: llc < ok.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \

>From 948ffd1c39e38bc9c9d8defe8b298b8a562c65ad Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Mon, 30 Jun 2025 19:19:13 +0300
Subject: [PATCH 6/6] [AArch64][PAC] Combine signing with address
 materialization

In pauthtest ABI, it is common to store a pointer signed with address
diversity to a heap-allocated object (namely, storing a signed pointer
to VTable as part of new object construction). This patch tries to
prevent introducing a signing oracle by combining pointer
materialization and its (re)signing into a single pseudo instruction
which is not expanded until AsmPrinter, if possible.

One of the typical patterns is materializing an unsigned pointer with
`MOVaddr` pseudo and then signing it with `PAC[ID][AB]` instruction,
which can be moved far away from `MOVaddr` by one of the passes in the
machine pipeline. As the storage address is not a `Constant` value, one
cannot simply emit a `ptrauth` constant in the frontend, which would be
selected into `MOVaddrPAC` pseudo.

Another pattern is fetching a pointer to VTable from a signed GOT entry
using `LOADgotAUTH` pseudo, authenticating and checking it, and then
re-signing after adding an offset.

This commit adds an instruction insertion hook for `PAC[ID][AB]` which
detects the above patterns and replaces it either with `MOVaddrPAC` or
`LOADgotPAC` instruction.
---
 .../Target/AArch64/AArch64ISelLowering.cpp    |  81 ++++++++++--
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |   3 +
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   3 +
 .../GlobalISel/ptrauth-constant-in-code.ll    | 122 +++++++++++++-----
 .../AArch64/ptrauth-constant-in-code.ll       | 114 +++++++++++-----
 .../CodeGen/AArch64/ptrauth-tiny-model-pic.ll |   4 +-
 .../AArch64/ptrauth-tiny-model-static.ll      |   4 +-
 7 files changed, 254 insertions(+), 77 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 7749f63213026..400287a5c3244 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -3079,10 +3079,13 @@ AArch64TargetLowering::EmitGetSMESaveSize(MachineInstr &MI,
   return BB;
 }
 
-// Helper function to find the instruction that defined a virtual register.
-// If unable to find such instruction, returns nullptr.
-static const MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI,
-                                           Register Reg) {
+// Helper function to find the instruction that defined a virtual register,
+// stripping and accumulating optional offset.
+// If unable to find such instruction, returns nullptr (Offset is unspecified).
+static const MachineInstr *
+stripAndAccumulateOffset(const MachineRegisterInfo &MRI, Register Reg,
+                         int64_t &Offset) {
+  Offset = 0;
   while (Reg.isVirtual()) {
     MachineInstr *DefMI = MRI.getVRegDef(Reg);
     assert(DefMI && "Virtual register definition not found");
@@ -3100,7 +3103,17 @@ static const MachineInstr *stripVRegCopies(const MachineRegisterInfo &MRI,
       continue;
     }
 
-    return DefMI;
+    // If this is neither a copy, nor inc/dec instruction, we are done.
+    if (Opcode != AArch64::ADDXri && Opcode != AArch64::SUBXri)
+      return DefMI;
+    // Inc/dec with shifted immediates are not handled.
+    if (DefMI->getOperand(3).getImm() != 0)
+      return DefMI;
+
+    int64_t Imm = DefMI->getOperand(2).getImm();
+    Offset += (Opcode == AArch64::ADDXri) ? Imm : -Imm;
+
+    Reg = DefMI->getOperand(1).getReg();
   }
   return nullptr;
 }
@@ -3116,8 +3129,13 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
   int64_t IntDisc = IntDiscOp.getImm();
   assert(IntDisc == 0 && "Blend components are already expanded");
 
-  const MachineInstr *DiscMI = stripVRegCopies(MRI, AddrDisc);
-  if (DiscMI) {
+  int64_t Offset = 0;
+  const MachineInstr *DiscMI = stripAndAccumulateOffset(MRI, AddrDisc, Offset);
+
+  // The result of any recognized discriminator computation may be copied, but
+  // without adding any offset. Nevertheless, perform the remaining fix-ups
+  // even on an opaque, pre-computed discriminator.
+  if (DiscMI && Offset == 0) {
     switch (DiscMI->getOpcode()) {
     case AArch64::MOVKXi:
       // blend(addr, imm) which is lowered as "MOVK addr, #imm, #48".
@@ -3156,6 +3174,53 @@ void AArch64TargetLowering::fixupPtrauthDiscriminator(
   IntDiscOp.setImm(IntDisc);
 }
 
+MachineBasicBlock *
+AArch64TargetLowering::tryRewritingPAC(MachineInstr &MI,
+                                       MachineBasicBlock *BB) const {
+  const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+  MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
+  const DebugLoc &DL = MI.getDebugLoc();
+
+  Register Val = MI.getOperand(1).getReg();
+  unsigned Key = MI.getOperand(2).getImm();
+  int64_t IntDisc = MI.getOperand(3).getImm();
+  Register AddrDisc = MI.getOperand(4).getReg();
+
+  // Try to find a known address-setting instruction, accumulating the offset
+  // along the way. If no known pattern is found, keep everything as-is.
+
+  int64_t AddrOffset = 0;
+  const MachineInstr *AddrDefInstr =
+      stripAndAccumulateOffset(MRI, Val, AddrOffset);
+  if (!AddrDefInstr)
+    return BB;
+
+  unsigned NewOpcode;
+  if (AddrDefInstr->getOpcode() == AArch64::LOADgotAUTH)
+    NewOpcode = AArch64::LOADgotPAC;
+  else if (AddrDefInstr->getOpcode() == AArch64::MOVaddr)
+    NewOpcode = AArch64::MOVaddrPAC;
+  else
+    return BB; // Unknown opcode.
+
+  const MachineOperand &AddrOp = AddrDefInstr->getOperand(1);
+  unsigned TargetFlags = AddrOp.getTargetFlags() & ~AArch64II::MO_PAGE;
+  const GlobalValue *GV = AddrOp.getGlobal();
+  AddrOffset += AddrOp.getOffset();
+
+  BuildMI(*BB, MI, DL, TII->get(NewOpcode))
+      .addGlobalAddress(GV, AddrOffset, TargetFlags)
+      .addImm(Key)
+      .addReg(AddrDisc)
+      .addImm(IntDisc);
+
+  BuildMI(*BB, MI, DL, TII->get(AArch64::COPY), MI.getOperand(0).getReg())
+      .addReg(AArch64::X16);
+
+  MI.removeFromParent();
+  return BB;
+}
+
 MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
     MachineInstr &MI, MachineBasicBlock *BB) const {
 
@@ -3266,7 +3331,7 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
   case AArch64::PAC:
     fixupPtrauthDiscriminator(MI, BB, MI.getOperand(3), MI.getOperand(4),
                               &AArch64::GPR64noipRegClass);
-    return BB;
+    return tryRewritingPAC(MI, BB);
   case AArch64::AUTPAC:
     fixupPtrauthDiscriminator(MI, BB, MI.getOperand(1), MI.getOperand(2),
                               &AArch64::GPR64noipRegClass);
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index 41c4560a1d453..74ea9f1c3df91 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -189,6 +189,9 @@ class AArch64TargetLowering : public TargetLowering {
                                  MachineOperand &AddrDiscOp,
                                  const TargetRegisterClass *AddrDiscRC) const;
 
+  MachineBasicBlock *tryRewritingPAC(MachineInstr &MI,
+                                     MachineBasicBlock *BB) const;
+
   MachineBasicBlock *
   EmitInstrWithCustomInserter(MachineInstr &MI,
                               MachineBasicBlock *MBB) const override;
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 35d96168a1518..08c0122bf056e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2220,6 +2220,9 @@ let Predicates = [HasPAuth] in {
 
   def LOADgotAUTH : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), []>,
                Sched<[WriteI, ReadI]> {
+    // Make it possible to eliminate dead instruction after folding it
+    // into LOADgotPAC.
+    let hasSideEffects = 0;
     let Defs = [X16,X17,NZCV];
     let Size = 44;
   }
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
index 140e29f942a79..b2081a2bea713 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/ptrauth-constant-in-code.ll
@@ -82,25 +82,50 @@ define ptr @foo() {
 
 ; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
 ; RUN:   -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \
-; RUN:   FileCheck --check-prefixes=ISEL,ISEL-ELF %s
+; RUN:   FileCheck --check-prefixes=ISEL-MIR,ISEL-MIR-ELF %s
 ; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \
 ; RUN:   -verify-machineinstrs -global-isel-abort=1 -stop-after=finalize-isel | \
-; RUN:   FileCheck --check-prefixes=ISEL %s
+; RUN:   FileCheck --check-prefixes=ISEL-MIR %s
+; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 -asm-verbose=0 | \
+; RUN:   FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-ELF %s
+; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=1 \
+; RUN:   -verify-machineinstrs -global-isel-abort=1 -asm-verbose=0 | \
+; RUN:   FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-MACHO %s
 
 @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null]
 @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null]
 
+; Test that after post-processing in finalize-isel, MOVaddrPAC (or LOADgotPAC,
+; respectively) has both $AddrDisc and $Disc operands set. MOVaddr (or LOADgotAUTH,
+; respectively) and MOVKXi are not used anymore and are dead-code-eliminated
+; by the later passes.
+
 define void @store_signed_const_local(ptr %dest) {
-; ISEL-LABEL: name: store_signed_const_local
-; ISEL:       body:
-; ISEL:         %0:gpr64common = COPY $x0
-; ISEL-NEXT:    %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
-; ISEL-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
-; ISEL-NEXT:    %15:gpr64noip = COPY %0
-; ISEL-NEXT:    %4:gpr64 = PAC %10, 2, 1234, %15, implicit-def dead $x17
-; ISEL-NEXT:    %14:gpr64 = COPY %4
-; ISEL-NEXT:    STRXui %14, %0, 0 :: (store (p0) into %ir.dest)
-; ISEL-NEXT:    RET_ReallyLR
+; ISEL-MIR-LABEL: name: store_signed_const_local
+; ISEL-MIR:       body:
+; ISEL-MIR:         %0:gpr64common = COPY $x0
+; ISEL-MIR-NEXT:    %10:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
+; ISEL-MIR-NEXT:    %2:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-NEXT:    %15:gpr64noip = COPY %0
+; ISEL-MIR-NEXT:    MOVaddrPAC @const_table_local + 8, 2, %15, 1234, implicit-def $x16, implicit-def $x17
+; ISEL-MIR-NEXT:    %4:gpr64 = COPY $x16
+; ISEL-MIR-NEXT:    %14:gpr64 = COPY %4
+; ISEL-MIR-NEXT:    STRXui %14, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-MIR-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-LABEL: store_signed_const_local:
+; ISEL-ASM-NEXT:    .cfi_startproc
+; ISEL-ASM-ELF-NEXT:    adrp    x16, const_table_local
+; ISEL-ASM-ELF-NEXT:    add     x16, x16, :lo12:const_table_local
+; ISEL-ASM-MACHO-NEXT:  adrp    x16, _const_table_local at PAGE
+; ISEL-ASM-MACHO-NEXT:  add     x16, x16, _const_table_local at PAGEOFF
+; ISEL-ASM-NEXT:    add     x16, x16, #8
+; ISEL-ASM-NEXT:    mov     x17, x0
+; ISEL-ASM-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-NEXT:    pacda   x16, x17
+; ISEL-ASM-NEXT:    str     x16, [x0]
+; ISEL-ASM-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr)
@@ -110,17 +135,37 @@ define void @store_signed_const_local(ptr %dest) {
 }
 
 define void @store_signed_const_got(ptr %dest) {
-; ISEL-ELF-LABEL: name: store_signed_const_got
-; ISEL-ELF:       body:
-; ISEL-ELF:         %0:gpr64common = COPY $x0
-; ISEL-ELF-NEXT:    %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got
-; ISEL-ELF-NEXT:    %6:gpr64common = ADDXri %7, 8, 0
-; ISEL-ELF-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
-; ISEL-ELF-NEXT:    %12:gpr64noip = COPY %0
-; ISEL-ELF-NEXT:    %4:gpr64 = PAC %6, 2, 1234, %12, implicit-def dead $x17
-; ISEL-ELF-NEXT:    %10:gpr64 = COPY %4
-; ISEL-ELF-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
-; ISEL-ELF-NEXT:    RET_ReallyLR
+; ISEL-MIR-ELF-LABEL: name: store_signed_const_got
+; ISEL-MIR-ELF:       body:
+; ISEL-MIR-ELF:         %0:gpr64common = COPY $x0
+; ISEL-MIR-ELF-NEXT:    %7:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got
+; ISEL-MIR-ELF-NEXT:    %6:gpr64common = ADDXri %7, 8, 0
+; ISEL-MIR-ELF-NEXT:    %2:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-ELF-NEXT:    %12:gpr64noip = COPY %0
+; ISEL-MIR-ELF-NEXT:    LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %12, 1234, implicit-def $x16, implicit-def $x17, implicit-def $nzcv
+; ISEL-MIR-ELF-NEXT:    %4:gpr64 = COPY $x16
+; ISEL-MIR-ELF-NEXT:    %10:gpr64 = COPY %4
+; ISEL-MIR-ELF-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-MIR-ELF-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-ELF-LABEL: store_signed_const_got:
+; ISEL-ASM-ELF-NEXT:    .cfi_startproc
+; ISEL-ASM-ELF-NEXT:    adrp    x17, :got_auth:const_table_got
+; ISEL-ASM-ELF-NEXT:    add     x17, x17, :got_auth_lo12:const_table_got
+; ISEL-ASM-ELF-NEXT:    ldr     x16, [x17]
+; ISEL-ASM-ELF-NEXT:    autda   x16, x17
+; ISEL-ASM-ELF-NEXT:    mov     x17, x16
+; ISEL-ASM-ELF-NEXT:    xpacd   x17
+; ISEL-ASM-ELF-NEXT:    cmp     x16, x17
+; ISEL-ASM-ELF-NEXT:    b.eq    .Lauth_success_0
+; ISEL-ASM-ELF-NEXT:    brk     #0xc472
+; ISEL-ASM-ELF-NEXT:  .Lauth_success_0:
+; ISEL-ASM-ELF-NEXT:    add     x16, x16, #8
+; ISEL-ASM-ELF-NEXT:    mov     x17, x0
+; ISEL-ASM-ELF-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-ELF-NEXT:    pacda   x16, x17
+; ISEL-ASM-ELF-NEXT:    str     x16, [x0]
+; ISEL-ASM-ELF-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr)
@@ -130,17 +175,26 @@ define void @store_signed_const_got(ptr %dest) {
 }
 
 define void @store_signed_arg(ptr %dest, ptr %p) {
-; ISEL-LABEL: name: store_signed_arg
-; ISEL:       body:
-; ISEL:         %0:gpr64common = COPY $x0
-; ISEL-NEXT:    %1:gpr64common = COPY $x1
-; ISEL-NEXT:    %3:gpr64noip = MOVKXi %0, 1234
-; ISEL-NEXT:    %6:gpr64common = ADDXri %1, 8, 0
-; ISEL-NEXT:    %12:gpr64noip = COPY %0
-; ISEL-NEXT:    %8:gpr64 = PAC %6, 2, 1234, %12, implicit-def dead $x17
-; ISEL-NEXT:    %10:gpr64 = COPY %8
-; ISEL-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
-; ISEL-NEXT:    RET_ReallyLR
+; ISEL-MIR-LABEL: name: store_signed_arg
+; ISEL-MIR:       body:
+; ISEL-MIR:         %0:gpr64common = COPY $x0
+; ISEL-MIR-NEXT:    %1:gpr64common = COPY $x1
+; ISEL-MIR-NEXT:    %3:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-NEXT:    %6:gpr64common = ADDXri %1, 8, 0
+; ISEL-MIR-NEXT:    %12:gpr64noip = COPY %0
+; ISEL-MIR-NEXT:    %8:gpr64 = PAC %6, 2, 1234, %12, implicit-def dead $x17
+; ISEL-MIR-NEXT:    %10:gpr64 = COPY %8
+; ISEL-MIR-NEXT:    STRXui %10, %0, 0 :: (store (p0) into %ir.dest)
+; ISEL-MIR-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-LABEL: store_signed_arg:
+; ISEL-ASM-NEXT:    .cfi_startproc
+; ISEL-ASM-NEXT:    add     x8, x1, #8
+; ISEL-ASM-NEXT:    mov     x17, x0
+; ISEL-ASM-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-NEXT:    pacda   x8, x17
+; ISEL-ASM-NEXT:    str     x8, [x0]
+; ISEL-ASM-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
index 429ff6e5489aa..37f6ff1ec0818 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-constant-in-code.ll
@@ -72,23 +72,46 @@ define ptr @foo() {
 ;--- finalize-isel.ll
 
 ; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \
-; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL,ISEL-ELF %s
+; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL-MIR,ISEL-MIR-ELF %s
 ; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \
-; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL %s
+; RUN:   -verify-machineinstrs -stop-after=finalize-isel | FileCheck --check-prefixes=ISEL-MIR %s
+; RUN: llc < finalize-isel.ll -mtriple aarch64-elf -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs -asm-verbose=0 | FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-ELF %s
+; RUN: llc < finalize-isel.ll -mtriple arm64-apple-ios -mattr=+pauth -global-isel=0 \
+; RUN:   -verify-machineinstrs -asm-verbose=0 | FileCheck --check-prefixes=ISEL-ASM,ISEL-ASM-MACHO %s
 
 @const_table_local = dso_local constant [3 x ptr] [ptr null, ptr null, ptr null]
 @const_table_got = constant [3 x ptr] [ptr null, ptr null, ptr null]
 
+; Test that after post-processing in finalize-isel, MOVaddrPAC (or LOADgotPAC,
+; respectively) has both $AddrDisc and $Disc operands set. MOVaddr (or LOADgotAUTH,
+; respectively) and MOVKXi are not used anymore and are dead-code-eliminated
+; by the later passes.
+
 define void @store_signed_const_local(ptr %dest) {
-; ISEL-LABEL: name: store_signed_const_local
-; ISEL:       body:
-; ISEL:         %0:gpr64common = COPY $x0
-; ISEL-NEXT:    %1:gpr64noip = MOVKXi %0, 1234
-; ISEL-NEXT:    %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
-; ISEL-NEXT:    %4:gpr64noip = COPY %0
-; ISEL-NEXT:    %3:gpr64 = PAC %2, 2, 1234, killed %4, implicit-def dead $x17
-; ISEL-NEXT:    STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest)
-; ISEL-NEXT:    RET_ReallyLR
+; ISEL-MIR-LABEL: name: store_signed_const_local
+; ISEL-MIR:       body:
+; ISEL-MIR:         %0:gpr64common = COPY $x0
+; ISEL-MIR-NEXT:    %1:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-NEXT:    %2:gpr64common = MOVaddr target-flags(aarch64-page) @const_table_local + 8, target-flags(aarch64-pageoff, aarch64-nc) @const_table_local + 8
+; ISEL-MIR-NEXT:    %4:gpr64noip = COPY %0
+; ISEL-MIR-NEXT:    MOVaddrPAC @const_table_local + 8, 2, %4, 1234, implicit-def $x16, implicit-def $x17
+; ISEL-MIR-NEXT:    %3:gpr64 = COPY $x16
+; ISEL-MIR-NEXT:    STRXui killed %3, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-MIR-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-LABEL: store_signed_const_local:
+; ISEL-ASM-NEXT:    .cfi_startproc
+; ISEL-ASM-ELF-NEXT:   adrp    x16, const_table_local
+; ISEL-ASM-ELF-NEXT:   add     x16, x16, :lo12:const_table_local
+; ISEL-ASM-MACHO-NEXT: adrp    x16, _const_table_local at PAGE
+; ISEL-ASM-MACHO-NEXT: add     x16, x16, _const_table_local at PAGEOFF
+; ISEL-ASM-NEXT:    add     x16, x16, #8
+; ISEL-ASM-NEXT:    mov     x17, x0
+; ISEL-ASM-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-NEXT:    pacda   x16, x17
+; ISEL-ASM-NEXT:    str     x16, [x0]
+; ISEL-ASM-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_local, i32 0, i32 1) to i64), i32 2, i64 %discr)
@@ -98,16 +121,36 @@ define void @store_signed_const_local(ptr %dest) {
 }
 
 define void @store_signed_const_got(ptr %dest) {
-; ISEL-ELF-LABEL: name: store_signed_const_got
-; ISEL-ELF:       body:
-; ISEL-ELF:         %0:gpr64common = COPY $x0
-; ISEL-ELF-NEXT:    %1:gpr64noip = MOVKXi %0, 1234
-; ISEL-ELF-NEXT:    %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv
-; ISEL-ELF-NEXT:    %3:gpr64common = ADDXri killed %2, 8, 0
-; ISEL-ELF-NEXT:    %5:gpr64noip = COPY %0
-; ISEL-ELF-NEXT:    %4:gpr64 = PAC %3, 2, 1234, killed %5, implicit-def dead $x17
-; ISEL-ELF-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
-; ISEL-ELF-NEXT:    RET_ReallyLR
+; ISEL-MIR-ELF-LABEL: name: store_signed_const_got
+; ISEL-MIR-ELF:       body:
+; ISEL-MIR-ELF:         %0:gpr64common = COPY $x0
+; ISEL-MIR-ELF-NEXT:    %1:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-ELF-NEXT:    %2:gpr64common = LOADgotAUTH target-flags(aarch64-got) @const_table_got, implicit-def dead $x16, implicit-def dead $x17, implicit-def dead $nzcv
+; ISEL-MIR-ELF-NEXT:    %3:gpr64common = ADDXri killed %2, 8, 0
+; ISEL-MIR-ELF-NEXT:    %5:gpr64noip = COPY %0
+; ISEL-MIR-ELF-NEXT:    LOADgotPAC target-flags(aarch64-got) @const_table_got + 8, 2, %5, 1234, implicit-def $x16, implicit-def $x17, implicit-def $nzcv
+; ISEL-MIR-ELF-NEXT:    %4:gpr64 = COPY $x16
+; ISEL-MIR-ELF-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-MIR-ELF-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-ELF-LABEL: store_signed_const_got:
+; ISEL-ASM-ELF-NEXT:    .cfi_startproc
+; ISEL-ASM-ELF-NEXT:    adrp    x17, :got_auth:const_table_got
+; ISEL-ASM-ELF-NEXT:    add     x17, x17, :got_auth_lo12:const_table_got
+; ISEL-ASM-ELF-NEXT:    ldr     x16, [x17]
+; ISEL-ASM-ELF-NEXT:    autda   x16, x17
+; ISEL-ASM-ELF-NEXT:    mov     x17, x16
+; ISEL-ASM-ELF-NEXT:    xpacd   x17
+; ISEL-ASM-ELF-NEXT:    cmp     x16, x17
+; ISEL-ASM-ELF-NEXT:    b.eq    .Lauth_success_0
+; ISEL-ASM-ELF-NEXT:    brk     #0xc472
+; ISEL-ASM-ELF-NEXT: .Lauth_success_0:
+; ISEL-ASM-ELF-NEXT:    add     x16, x16, #8
+; ISEL-ASM-ELF-NEXT:    mov     x17, x0
+; ISEL-ASM-ELF-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-ELF-NEXT:    pacda   x16, x17
+; ISEL-ASM-ELF-NEXT:    str     x16, [x0]
+; ISEL-ASM-ELF-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %signed.i = call i64 @llvm.ptrauth.sign(i64 ptrtoint (ptr getelementptr ([2 x ptr], ptr @const_table_got, i32 0, i32 1) to i64), i32 2, i64 %discr)
@@ -117,16 +160,25 @@ define void @store_signed_const_got(ptr %dest) {
 }
 
 define void @store_signed_arg(ptr %dest, ptr %p) {
-; ISEL-LABEL: name: store_signed_arg
-; ISEL:       body:
-; ISEL:         %1:gpr64common = COPY $x1
-; ISEL-NEXT:    %0:gpr64common = COPY $x0
-; ISEL-NEXT:    %2:gpr64noip = MOVKXi %0, 1234
-; ISEL-NEXT:    %3:gpr64common = ADDXri %1, 8, 0
-; ISEL-NEXT:    %5:gpr64noip = COPY %0
-; ISEL-NEXT:    %4:gpr64 = PAC %3, 2, 1234, killed %5, implicit-def dead $x17
-; ISEL-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
-; ISEL-NEXT:    RET_ReallyLR
+; ISEL-MIR-LABEL: name: store_signed_arg
+; ISEL-MIR:       body:
+; ISEL-MIR:         %1:gpr64common = COPY $x1
+; ISEL-MIR-NEXT:    %0:gpr64common = COPY $x0
+; ISEL-MIR-NEXT:    %2:gpr64noip = MOVKXi %0, 1234, 48
+; ISEL-MIR-NEXT:    %3:gpr64common = ADDXri %1, 8, 0
+; ISEL-MIR-NEXT:    %5:gpr64noip = COPY %0
+; ISEL-MIR-NEXT:    %4:gpr64 = PAC %3, 2, 1234, killed %5, implicit-def dead $x17
+; ISEL-MIR-NEXT:    STRXui killed %4, %0, 0 :: (store (s64) into %ir.dest)
+; ISEL-MIR-NEXT:    RET_ReallyLR
+;
+; ISEL-ASM-LABEL: store_signed_arg:
+; ISEL-ASM-NEXT:    .cfi_startproc
+; ISEL-ASM-NEXT:    add     x8, x1, #8
+; ISEL-ASM-NEXT:    mov     x17, x0
+; ISEL-ASM-NEXT:    movk    x17, #1234, lsl #48
+; ISEL-ASM-NEXT:    pacda   x8, x17
+; ISEL-ASM-NEXT:    str     x8, [x0]
+; ISEL-ASM-NEXT:    ret
   %dest.i = ptrtoint ptr %dest to i64
   %discr = call i64 @llvm.ptrauth.blend(i64 %dest.i, i64 1234)
   %p.offset = getelementptr [2 x ptr], ptr %p, i32 0, i32 1
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll
index 9d13714bbefe3..cb8f1f4021eea 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-pic.ll
@@ -34,7 +34,6 @@ define dso_preemptable void @foo1() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_0:
 ; TRAP-NEXT:     mov   x8,  x16
-; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    adr   x17, :got_auth:dst
 ; NOTRAP-NEXT:   ldr   x9,  [x17]
 ; NOTRAP-NEXT:   autda x9,  x17
@@ -47,6 +46,7 @@ define dso_preemptable void @foo1() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_1:
 ; TRAP-NEXT:     mov   x9,  x16
+; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    strb  w8,  [x9]
 ; CHECK-NEXT:    ret
 
@@ -106,7 +106,6 @@ define dso_preemptable void @foo3() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_4:
 ; TRAP-NEXT:     mov   x8,  x16
-; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    adr   x17, :got_auth:ptr
 ; NOTRAP-NEXT:   ldr   x9,  [x17]
 ; NOTRAP-NEXT:   autda x9,  x17
@@ -119,6 +118,7 @@ define dso_preemptable void @foo3() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_5:
 ; TRAP-NEXT:     mov   x9,  x16
+; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    ldr   x9,  [x9]
 ; CHECK-NEXT:    strb  w8,  [x9]
 ; CHECK-NEXT:    ret
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll
index 2d098b70acccc..0bf54ab49381e 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-tiny-model-static.ll
@@ -34,7 +34,6 @@ define dso_local void @foo1() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_0:
 ; TRAP-NEXT:     mov   x8,  x16
-; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    adr   x17, :got_auth:dst
 ; NOTRAP-NEXT:   ldr   x9,  [x17]
 ; NOTRAP-NEXT:   autda x9,  x17
@@ -47,6 +46,7 @@ define dso_local void @foo1() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_1:
 ; TRAP-NEXT:     mov   x9,  x16
+; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    strb  w8,  [x9]
 ; CHECK-NEXT:    ret
 
@@ -106,7 +106,6 @@ define dso_local void @foo3() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_4:
 ; TRAP-NEXT:     mov   x8,  x16
-; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    adr   x17, :got_auth:ptr
 ; NOTRAP-NEXT:   ldr   x9,  [x17]
 ; NOTRAP-NEXT:   autda x9,  x17
@@ -119,6 +118,7 @@ define dso_local void @foo3() {
 ; TRAP-NEXT:     brk   #0xc472
 ; TRAP-NEXT:   .Lauth_success_5:
 ; TRAP-NEXT:     mov   x9,  x16
+; CHECK-NEXT:    ldrb  w8,  [x8]
 ; CHECK-NEXT:    ldr   x9,  [x9]
 ; CHECK-NEXT:    strb  w8,  [x9]
 ; CHECK-NEXT:    ret



More information about the llvm-branch-commits mailing list