[llvm] [AArch64][PAC] Implement code generation for @llvm.ptrauth.auth (PR #72502)

Anatoly Trosinenko via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 16 10:44:43 PST 2023


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

>From 99d008170bfa66941ac76b89fbdc69b4101ff5f1 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 19 Oct 2023 17:03:51 +0300
Subject: [PATCH 1/2] [AArch64][PAC] Implement code generation for
 @llvm.ptrauth.auth

This patch introduces PAUTH_AUTH pseudo instruction that can encode
well-known discriminator computations in its operands:
- small immediate integer discriminator
- blend of a GPR64 register and an immediate integer
- arbitrary GPR64 register as a fallback

For convenience, a PAUTH_BLEND pseudo instruction is introduced as well
that is selected for @llvm.ptrauth.blend intrinsic.

For @llvm.ptrauth.auth, the TableGen-erated code selects a PAUTH_AUTH
instruction in its "fallback" form. After that, custom inserter tries
to detect a well-known signing schema and refines the operands of
PAUTH_AUTH instruction, if possible.

It may be necessary to use fixed X17 and X16 for pointer and scratch
registers, either for security or compatibility with Armv8.2. For that
purpose, implicit defs of X16 and X17 are added by TableGen-erated code,
to make sure that custom inserter can safely use these registers as
pointer and scratch operands. These temporary implicit-def operands are
removed by custom inserter.

As it is worth asking register allocator to place $reg_disc right in the
$scratch register, these operands are tied. Thus, as a special case it is
permitted to assign XZR to $scratch and provide the real scratch register
as an implicit-def operand. While it would be possible to use 2 separate
pseudo instructions: one for immediate integer discriminator and one for
everything else, it would require 2*2 pseudos for expressing
@llvm.ptrauth.resign the same way (or even 3*3 if clearly separating
register/immediate/blended discriminator cases).
---
 .../Target/AArch64/AArch64ISelLowering.cpp    | 127 +++++
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |   3 +
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |  29 +-
 .../lib/Target/AArch64/AArch64PointerAuth.cpp | 227 +++++++-
 llvm/lib/Target/AArch64/AArch64PointerAuth.h  |  19 +
 llvm/lib/Target/AArch64/AArch64Subtarget.cpp  |  42 ++
 llvm/lib/Target/AArch64/AArch64Subtarget.h    |   6 +
 .../CodeGen/AArch64/ptrauth-intrinsic-auth.ll | 501 ++++++++++++++++++
 .../AArch64/sign-return-address-tailcall.ll   |   8 +-
 9 files changed, 952 insertions(+), 10 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll

diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 9ff6d6f0f565edb..0e3ef3ffb3410e1 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2801,6 +2801,130 @@ AArch64TargetLowering::EmitZero(MachineInstr &MI, MachineBasicBlock *BB) const {
   return BB;
 }
 
+MachineBasicBlock *
+AArch64TargetLowering::EmitPAuthInstr(MachineInstr &MI,
+                                      MachineBasicBlock *BB) const {
+  const AArch64InstrInfo *TII = Subtarget->getInstrInfo();
+  MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
+  DebugLoc DL = MI.getDebugLoc();
+
+  // The discriminator should be expressed by consecutive operands
+  // (raw_register, immediate_integer, is_blend). This function accepts
+  // (reg, 0, 0) operands generated by the instruction selector and tries
+  // to detect either small immediate discriminator expressed as
+  // (XZR, small_int, 0), blend(something, small_int) expressed as
+  // (something, small_int, 1) or keeps the operands as-is otherwise.
+  auto DetectDiscriminator = [&](unsigned RegDiscOpIndex) {
+    MachineOperand &RegOp = MI.getOperand(RegDiscOpIndex);
+    MachineOperand &ImmOp = MI.getOperand(RegDiscOpIndex + 1);
+    MachineOperand &IsBlendOp = MI.getOperand(RegDiscOpIndex + 2);
+    assert(ImmOp.getImm() == 0 && "Operand was already initialized");
+    assert(IsBlendOp.getImm() == 0 && "Operand was already initialized");
+
+    // Walk through the chain of copy-like instructions until we find
+    // a known signing schema, if any.
+    Register AddrDisc;
+    uint64_t ImmDisc;
+    for (Register DiscReg = RegOp.getReg(); DiscReg.isVirtual();) {
+      MachineInstr *DefiningMI = MRI.getVRegDef(DiscReg);
+      switch (DefiningMI->getOpcode()) {
+      case AArch64::COPY:
+        DiscReg = DefiningMI->getOperand(1).getReg();
+        if (DiscReg == AArch64::XZR) {
+          // Zero discriminator: (XZR, 0, 0).
+          RegOp.setReg(AArch64::XZR);
+          return;
+        }
+        break;
+      case AArch64::SUBREG_TO_REG:
+        DiscReg = DefiningMI->getOperand(2).getReg();
+        break;
+      case AArch64::MOVi32imm:
+        ImmDisc = DefiningMI->getOperand(1).getImm();
+        // If ImmDisc does not fit in 16 bits,
+        // consider it as custom computation.
+        if ((ImmDisc & 0xffff) == ImmDisc) {
+          // Small immediate integer: (XZR, imm, 0).
+          RegOp.setReg(AArch64::XZR);
+          ImmOp.setImm(ImmDisc);
+        }
+        return;
+      case AArch64::PAUTH_BLEND:
+        AddrDisc = DefiningMI->getOperand(1).getReg();
+        ImmDisc = DefiningMI->getOperand(2).getImm();
+        assert((ImmDisc & 0xffff) == ImmDisc &&
+               "Expected 16-bit integer operand in PAUTH_BLEND");
+        RegOp.setReg(AddrDisc);
+        ImmOp.setImm(ImmDisc);
+        IsBlendOp.setImm(1);
+        return;
+      default:
+        // Custom computation, leave it as-is.
+        return;
+      }
+    }
+  };
+
+  auto PopImplicitDef = [&](Register ExpectedReg) {
+    (void)ExpectedReg;
+    unsigned Index = MI.getNumOperands() - 1;
+    assert(MI.getOperand(Index).isImplicit());
+    assert(MI.getOperand(Index).isDef());
+    assert(MI.getOperand(Index).getReg() == ExpectedReg);
+    MI.removeOperand(Index);
+  };
+
+  auto AdjustDefinedRegisters = [&](unsigned TiedRegDiscOpIndex) {
+    Register RegDisc = MI.getOperand(TiedRegDiscOpIndex).getReg();
+
+    // The instruction, as selected by TableGen-erated code, has X16 and X17
+    // registers implicitly defined, to make sure they are safe to clobber.
+    //
+    // Remove these generic implicit defs here and re-add them as needed and
+    // if needed. If assertions are enabled, additionally check that the two
+    // implicit operands are the expected ones.
+    PopImplicitDef(AArch64::X17);
+    PopImplicitDef(AArch64::X16);
+
+    // $scratch operand is tied to $reg_disc, thus if an immediate integer
+    // discriminator is used, $scratch ends up being XZR. In that case, add
+    // an implicit-def scratch register - this is a special case known by
+    // aarch64-ptrauth pass.
+    MachineOperand *RealScratchOp = &MI.getOperand(1);
+    if (RegDisc == AArch64::XZR) {
+      MI.getOperand(1).setReg(AArch64::XZR);
+      Register ScratchReg = MRI.createVirtualRegister(&AArch64::GPR64RegClass);
+      MI.addOperand(MachineOperand::CreateReg(ScratchReg, /*isDef=*/true,
+                                              /*isImp=*/true));
+      RealScratchOp = &MI.getOperand(MI.getNumOperands() - 1);
+    }
+
+    assert((RegDisc == AArch64::XZR || RegDisc.isVirtual()) &&
+           "Accidentally clobbering register?");
+
+    // If target CPU does not support FEAT_PAuth, IA and IB keys are still
+    // usable via HINT-encoded instructions.
+    if (!Subtarget->hasPAuth()) {
+      Register AutedReg = MI.getOperand(0).getReg();
+
+      MI.getOperand(0).setReg(AArch64::X17);
+      RealScratchOp->setReg(AArch64::X16);
+      BuildMI(*BB, MI.getNextNode(), DL, TII->get(AArch64::COPY), AutedReg)
+          .addReg(AArch64::X17);
+    }
+  };
+
+  switch (MI.getOpcode()) {
+  default:
+    llvm_unreachable("Unhandled opcode");
+  case AArch64::PAUTH_AUTH:
+    DetectDiscriminator(/*RegDiscOpIndex=*/3);
+    AdjustDefinedRegisters(/*TiedRegDiscOpIndex=*/3);
+    break;
+  }
+  return BB;
+}
+
 MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
     MachineInstr &MI, MachineBasicBlock *BB) const {
 
@@ -2854,6 +2978,9 @@ MachineBasicBlock *AArch64TargetLowering::EmitInstrWithCustomInserter(
   case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL:
     return BB;
 
+  case AArch64::PAUTH_AUTH:
+    return EmitPAuthInstr(MI, BB);
+
   case AArch64::CATCHRET:
     return EmitLoweredCatchRet(MI, BB);
   case AArch64::LD1_MXIPXX_H_PSEUDO_B:
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
index b638084f98dadb8..0ab8b113d3bbede 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -612,6 +612,9 @@ class AArch64TargetLowering : public TargetLowering {
                                      bool IsSpill) const;
   MachineBasicBlock *EmitZero(MachineInstr &MI, MachineBasicBlock *BB) const;
 
+  MachineBasicBlock *EmitPAuthInstr(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 290c79f7bacdb8f..f69d27c1269eba7 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -1533,6 +1533,27 @@ def PAUTH_PROLOGUE : Pseudo<(outs), (ins), []>, Sched<[]>;
 def PAUTH_EPILOGUE : Pseudo<(outs), (ins), []>, Sched<[]>;
 }
 
+def PAUTH_BLEND : Pseudo<(outs GPR64:$disc), (ins GPR64:$addr_disc, i32imm:$int_disc), []>, Sched<[]>;
+
+// Two tasks are handled by custom inserter:
+// 1. It tries to detect known signing schemas: either small immediate integer
+//    discriminator or an arbitrary register blended with a small integer -
+//    if such schema is detected, it is saved into the instruction's operands.
+// 2. It is worth to reuse $reg_disc as a scratch register unless we use
+//    immediate integer as a discriminator (in that case $reg_disc is XZR).
+//    In the latter case $scratch is technically XZR, but another def-ed
+//    register is added as an implicit operand by the inserter.
+//
+// See the comments in custom inserter code for explanation of the reason
+// to specify "Defs = [X16, X17]" here.
+let usesCustomInserter = 1, Defs = [X16, X17] in {
+def PAUTH_AUTH : Pseudo<(outs GPR64common:$auted, GPR64:$scratch),
+                        (ins GPR64common:$signed,
+                             GPR64:$reg_disc, i32imm:$int_disc,
+                             i32imm:$is_blended, i32imm:$key_id), [],
+                        "$auted = $signed, $scratch = $reg_disc">, Sched<[]>;
+}
+
 // These pointer authentication instructions require armv8.3a
 let Predicates = [HasPAuth] in {
 
@@ -9146,12 +9167,14 @@ let Predicates = [HasMOPS, HasMTE], Defs = [NZCV], Size = 12, mayLoad = 0, maySt
 //-----------------------------------------------------------------------------
 // v8.3 Pointer Authentication late patterns
 
-let Predicates = [HasPAuth] in {
 def : Pat<(int_ptrauth_blend GPR64:$Rd, imm64_0_65535:$imm),
-          (MOVKXi GPR64:$Rd, (trunc_imm imm64_0_65535:$imm), 48)>;
+          (PAUTH_BLEND GPR64:$Rd, (trunc_imm imm64_0_65535:$imm))>;
 def : Pat<(int_ptrauth_blend GPR64:$Rd, GPR64:$Rn),
           (BFMXri GPR64:$Rd, GPR64:$Rn, 16, 15)>;
-}
+
+def : Pat<(int_ptrauth_auth GPR64:$signed,
+                            timm:$key_id, GPR64:$reg_disc),
+          (PAUTH_AUTH GPR64:$signed, GPR64:$reg_disc, 0, 0, timm:$key_id)>;
 
 //-----------------------------------------------------------------------------
 
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
index 7576d2a899d1afb..8ae38af4a3b43d2 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.cpp
@@ -12,9 +12,11 @@
 #include "AArch64InstrInfo.h"
 #include "AArch64MachineFunctionInfo.h"
 #include "AArch64Subtarget.h"
+#include "Utils/AArch64BaseInfo.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/IR/Intrinsics.h"
 
 using namespace llvm;
 using namespace llvm::AArch64PAuth;
@@ -34,8 +36,8 @@ class AArch64PointerAuth : public MachineFunctionPass {
   StringRef getPassName() const override { return AARCH64_POINTER_AUTH_NAME; }
 
 private:
-  /// An immediate operand passed to BRK instruction, if it is ever emitted.
-  const unsigned BrkOperand = 0xc471;
+  /// An immediate operand passed to BRK instruction is (0xc470 + KeyId).
+  const unsigned BrkOperandBase = 0xc470;
 
   const AArch64Subtarget *Subtarget = nullptr;
   const AArch64InstrInfo *TII = nullptr;
@@ -46,9 +48,77 @@ class AArch64PointerAuth : public MachineFunctionPass {
   void authenticateLR(MachineFunction &MF,
                       MachineBasicBlock::iterator MBBI) const;
 
+  /// Stores blend(AddrDisc, IntDisc) to the Result register.
+  void emitBlend(MachineBasicBlock::iterator MBBI, Register Result,
+                 Register AddrDisc, unsigned IntDisc) const;
+
+  /// Stores the discriminator value to the Result register.
+  ///
+  /// This is an utility function used when expanding several PAUTH_*
+  /// pseudo instructions that follow the same conventions on expressing
+  /// the requested signing schema.
+  void storeDiscriminator(MachineBasicBlock::iterator MBBI, Register Result,
+                          bool IsBlended, Register RegDisc, unsigned IntDisc,
+                          bool ShouldStoreZero) const;
+
+  /// Emits discriminator computation followed by AUT* or PAC* instruction.
+  ///
+  /// By encoding the common cases of discriminator computation right in
+  /// the instruction's operands, this pass strives to emit blend operation
+  /// or move-immediate as close to AUT* or PAC* instruction as possible.
+  ///
+  /// The instruction is expected to have operand list starting with
+  /// - def $dst_ptr
+  /// - def $scratch
+  /// - use $src_ptr (tied to $dst_ptr)
+  /// and a contiguous sequence of operands describing the signing schema:
+  /// - use $reg_disc
+  /// - use $int_disc
+  /// - use $is_blended
+  /// - use $key_id
+  ///
+  /// As tying $scratch operand to (one of) $reg_disc is beneficial for
+  /// eliminating excessive register moves, it is allowed as an exception to
+  /// express immediate-only discriminator as $reg_disc (and thus $scratch)
+  /// being XZR. In that case, custom inserter should provide the actual
+  /// scratch register as an implicit def.
+  void expandAutOrSignWithDiscriminator(
+      MachineBasicBlock::iterator MBBI, unsigned RegDiscOpIndex,
+      unsigned (*GetHintOpcode)(Register, Register, AArch64PACKey::ID),
+      unsigned (*GetOpcode)(AArch64PACKey::ID, bool)) const;
+
+  /// Checks pointer that was authenticated.
+  ///
+  /// The instruction is expected to have operand list starting with
+  /// - def $dst_ptr
+  /// - def $scratch
+  /// as well as $key_id and optional implicit def
+  /// (see expandAutOrSignWithDiscriminator for explanation).
+  void expandAddressCheck(MachineBasicBlock::iterator MBBI,
+                          unsigned KeyIdOpIndex,
+                          Intrinsic::ID IntrinsicId) const;
+
+  /// Expands PAUTH_AUTH pseudo instruction.
+  void expandPAuthAuth(MachineBasicBlock::iterator MBBI) const;
+
   bool checkAuthenticatedLR(MachineBasicBlock::iterator TI) const;
 };
 
+unsigned getHintAUTOpcode(Register Pointer, Register Discriminator,
+                          AArch64PACKey::ID KeyId) {
+  if (Pointer != AArch64::X17 || Discriminator != AArch64::X16)
+    return 0;
+
+  switch (KeyId) {
+  case AArch64PACKey::IA:
+    return AArch64::AUTIA1716;
+  case AArch64PACKey::IB:
+    return AArch64::AUTIB1716;
+  default:
+    return 0;
+  }
+}
+
 } // end anonymous namespace
 
 INITIALIZE_PASS(AArch64PointerAuth, "aarch64-ptrauth",
@@ -174,7 +244,7 @@ MachineBasicBlock &llvm::AArch64PAuth::checkAuthenticatedRegister(
     return MBB;
   case AuthCheckMethod::DummyLoad:
     BuildMI(MBB, MBBI, DL, TII->get(AArch64::LDRWui), getWRegFromXReg(TmpReg))
-        .addReg(AArch64::LR)
+        .addReg(AuthenticatedReg)
         .addImm(0)
         .addMemOperand(createCheckMemOperand(MF, Subtarget));
     return MBB;
@@ -230,6 +300,22 @@ MachineBasicBlock &llvm::AArch64PAuth::checkAuthenticatedRegister(
         .addImm(AArch64CC::NE)
         .addMBB(BreakBlock);
     return *SuccessBlock;
+  case AuthCheckMethod::XPAC:
+    BuildMI(CheckBlock, DL, TII->get(AArch64::ORRXrs), TmpReg)
+        .addReg(AArch64::XZR)
+        .addReg(AuthenticatedReg)
+        .addImm(0);
+    BuildMI(CheckBlock, DL, TII->get(UseIKey ? AArch64::XPACI : AArch64::XPACD),
+            TmpReg)
+        .addReg(TmpReg);
+    BuildMI(CheckBlock, DL, TII->get(AArch64::SUBSXrs), AArch64::XZR)
+        .addReg(TmpReg)
+        .addReg(AuthenticatedReg)
+        .addImm(0);
+    BuildMI(CheckBlock, DL, TII->get(AArch64::Bcc))
+        .addImm(AArch64CC::NE)
+        .addMBB(BreakBlock);
+    return *SuccessBlock;
   }
   llvm_unreachable("Unknown AuthCheckMethod enum");
 }
@@ -244,12 +330,18 @@ unsigned llvm::AArch64PAuth::getCheckerSizeInBytes(AuthCheckMethod Method) {
     return 12;
   case AuthCheckMethod::XPACHint:
     return 20;
+  case AuthCheckMethod::XPAC:
+    return 20;
   }
   llvm_unreachable("Unknown AuthCheckMethod enum");
 }
 
 bool AArch64PointerAuth::checkAuthenticatedLR(
     MachineBasicBlock::iterator TI) const {
+  const AArch64FunctionInfo *MFnI = TI->getMF()->getInfo<AArch64FunctionInfo>();
+  unsigned BrkOperand =
+      MFnI->shouldSignWithBKey() ? (BrkOperandBase + 1) : BrkOperandBase;
+
   AuthCheckMethod Method = Subtarget->getAuthenticatedLRCheckMethod();
 
   if (Method == AuthCheckMethod::None)
@@ -295,6 +387,123 @@ bool AArch64PointerAuth::checkAuthenticatedLR(
   return true;
 }
 
+void AArch64PointerAuth::emitBlend(MachineBasicBlock::iterator MBBI,
+                                   Register Result, Register AddrDisc,
+                                   unsigned IntDisc) const {
+  MachineBasicBlock &MBB = *MBBI->getParent();
+  DebugLoc DL = MBBI->getDebugLoc();
+
+  if (Result != AddrDisc)
+    BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), Result)
+        .addReg(AArch64::XZR)
+        .addReg(AddrDisc)
+        .addImm(0);
+
+  BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVKXi), Result)
+      .addReg(Result)
+      .addImm(IntDisc)
+      .addImm(48);
+}
+
+void AArch64PointerAuth::storeDiscriminator(MachineBasicBlock::iterator MBBI,
+                                            Register Result, bool IsBlended,
+                                            Register RegDisc, unsigned IntDisc,
+                                            bool ShouldStoreZero) const {
+  MachineBasicBlock &MBB = *MBBI->getParent();
+  DebugLoc DL = MBBI->getDebugLoc();
+
+  if (IsBlended) {
+    // Discriminator is blend(RegDisc, IntDisc).
+    emitBlend(MBBI, Result, RegDisc, IntDisc);
+  } else if (RegDisc != AArch64::XZR) {
+    // Discriminator is RegDisc.
+    assert(IntDisc == 0 &&
+           "Cannot use both reg and int discriminators without blending");
+    if (Result != RegDisc)
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::ORRXrs), Result)
+          .addReg(AArch64::XZR)
+          .addReg(RegDisc)
+          .addImm(0);
+  } else {
+    // Discriminator is IntDisc (possibly, zero at all).
+    assert(RegDisc == AArch64::XZR &&
+           "Cannot use both reg and int discriminators without blending");
+    if (IntDisc != 0 || ShouldStoreZero)
+      BuildMI(MBB, MBBI, DL, TII->get(AArch64::MOVZXi), Result)
+          .addImm(IntDisc)
+          .addImm(0);
+  }
+}
+
+void AArch64PointerAuth::expandAutOrSignWithDiscriminator(
+    MachineBasicBlock::iterator MBBI, unsigned RegDiscOpIndex,
+    unsigned (*GetHintOpcode)(Register, Register, AArch64PACKey::ID),
+    unsigned (*GetOpcode)(AArch64PACKey::ID, bool)) const {
+  MachineBasicBlock &MBB = *MBBI->getParent();
+  DebugLoc DL = MBBI->getDebugLoc();
+
+  Register PointerReg = MBBI->getOperand(0).getReg();
+  Register ScratchReg = MBBI->getOperand(1).getReg();
+  if (ScratchReg == AArch64::XZR)
+    ScratchReg = MBBI->getOperand(MBBI->getNumOperands() - 1).getReg();
+
+  Register RegDisc = MBBI->getOperand(RegDiscOpIndex).getReg();
+  unsigned IntDisc = MBBI->getOperand(RegDiscOpIndex + 1).getImm();
+  bool IsBlended = MBBI->getOperand(RegDiscOpIndex + 2).getImm();
+  auto KeyId = (AArch64PACKey::ID)MBBI->getOperand(RegDiscOpIndex + 3).getImm();
+
+  // Try using an instruction encoded as HINT, if possible.
+  unsigned HintOpcode = GetHintOpcode(PointerReg, ScratchReg, KeyId);
+  assert(HintOpcode || Subtarget->hasPAuth());
+
+  // Compute discriminator value.
+  storeDiscriminator(MBBI, ScratchReg, IsBlended, RegDisc, IntDisc,
+                     /*ShouldStoreZero=*/HintOpcode != 0);
+
+  // Now, the discriminator value is in the ScratchReg register,
+  // if not using zero-discriminator opcode variant.
+
+  if (HintOpcode) {
+    // All other opcodes require FEAT_PAuth, so check this first.
+    BuildMI(MBB, MBBI, DL, TII->get(HintOpcode));
+  } else {
+    bool IsZeroDisc = RegDisc == AArch64::XZR && IntDisc == 0;
+    unsigned RegularOpcode = GetOpcode(KeyId, IsZeroDisc);
+
+    if (IsZeroDisc) {
+      BuildMI(MBB, MBBI, DL, TII->get(RegularOpcode), PointerReg)
+          .addReg(PointerReg);
+    } else {
+      BuildMI(MBB, MBBI, DL, TII->get(RegularOpcode), PointerReg)
+          .addReg(PointerReg)
+          .addReg(ScratchReg);
+    }
+  }
+}
+
+void AArch64PointerAuth::expandAddressCheck(MachineBasicBlock::iterator MBBI,
+                                            unsigned KeyIdOpIndex,
+                                            Intrinsic::ID IntrinsicId) const {
+  Register PointerReg = MBBI->getOperand(0).getReg();
+  Register ScratchReg = MBBI->getOperand(1).getReg();
+  if (ScratchReg == AArch64::XZR)
+    ScratchReg = MBBI->getOperand(MBBI->getNumOperands() - 1).getReg();
+  auto KeyId = (AArch64PACKey::ID)MBBI->getOperand(KeyIdOpIndex).getImm();
+
+  bool UseIKey = KeyId == AArch64PACKey::IA || KeyId == AArch64PACKey::IB;
+  AuthCheckMethod Method =
+      Subtarget->getPAuthIntrinsicCheckMethod(IntrinsicId, KeyId);
+  checkAuthenticatedRegister(MBBI, Method, PointerReg, ScratchReg, UseIKey,
+                             BrkOperandBase + KeyId);
+}
+
+void AArch64PointerAuth::expandPAuthAuth(
+    MachineBasicBlock::iterator MBBI) const {
+  expandAutOrSignWithDiscriminator(MBBI, /*RegDiscOpIndex=*/3, getHintAUTOpcode,
+                                   getAUTOpcodeForKey);
+  expandAddressCheck(MBBI, /*KeyIdOpIndex=*/6, Intrinsic::ptrauth_auth);
+}
+
 bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) {
   const auto *MFnI = MF.getInfo<AArch64FunctionInfo>();
 
@@ -326,6 +535,8 @@ bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) {
         break;
       case AArch64::PAUTH_PROLOGUE:
       case AArch64::PAUTH_EPILOGUE:
+      case AArch64::PAUTH_AUTH:
+      case AArch64::PAUTH_BLEND:
         assert(!MI.isBundled());
         PAuthPseudoInstrs.push_back(MI.getIterator());
         break;
@@ -342,6 +553,16 @@ bool AArch64PointerAuth::runOnMachineFunction(MachineFunction &MF) {
       authenticateLR(MF, It);
       HasAuthenticationInstrs = true;
       break;
+    case AArch64::PAUTH_AUTH:
+      expandPAuthAuth(It);
+      break;
+    case AArch64::PAUTH_BLEND: {
+      Register ResultReg = It->getOperand(0).getReg();
+      Register AddrDisc = It->getOperand(1).getReg();
+      unsigned IntDisc = It->getOperand(2).getImm();
+      emitBlend(It, ResultReg, AddrDisc, IntDisc);
+      break;
+    }
     default:
       llvm_unreachable("Unhandled opcode");
     }
diff --git a/llvm/lib/Target/AArch64/AArch64PointerAuth.h b/llvm/lib/Target/AArch64/AArch64PointerAuth.h
index e1ceaed58abe47c..e9f1379c66a7f23 100644
--- a/llvm/lib/Target/AArch64/AArch64PointerAuth.h
+++ b/llvm/lib/Target/AArch64/AArch64PointerAuth.h
@@ -71,6 +71,18 @@ enum class AuthCheckMethod {
   ///   b.ne break_block
   /// ```
   XPACHint,
+  /// Check by comparing the authenticated value with an XPAC-ed one (handles
+  /// arbitrary register and key combination, requires FEAT_PAuth).
+  ///
+  /// This method modifies control flow and inserts the following checker:
+  ///
+  /// ```
+  ///   mov Xtmp, Xn
+  ///   xpac(i|d) Xtmp
+  ///   cmp Xtmp, Xn
+  ///   b.ne break_block
+  /// ```
+  XPAC,
 };
 
 #define AUTH_CHECK_METHOD_CL_VALUES_COMMON                                     \
@@ -82,11 +94,18 @@ enum class AuthCheckMethod {
                  "high-bits-notbi",                                            \
                  "Compare bits 62 and 61 of address (TBI should be disabled)")
 
+/// The methods applicable to LR register authenticated using IA or IB key.
 #define AUTH_CHECK_METHOD_CL_VALUES_LR                                         \
       AUTH_CHECK_METHOD_CL_VALUES_COMMON,                                      \
       clEnumValN(AArch64PAuth::AuthCheckMethod::XPACHint, "xpac-hint",         \
                  "Compare with the result of XPACLRI")
 
+/// The methods applicable to any register authenticated using any key.
+#define AUTH_CHECK_METHOD_CL_VALUES_GENERIC                                    \
+      AUTH_CHECK_METHOD_CL_VALUES_COMMON,                                      \
+      clEnumValN(AArch64PAuth::AuthCheckMethod::XPAC, "xpac",                  \
+                 "Compare with the result of XPAC (needs FEAT_PAuth)")
+
 /// Explicitly checks that pointer authentication succeeded.
 ///
 /// Assuming AuthenticatedReg contains a value returned by one of the AUT*
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
index ff14fcf5dfcc0f6..20acc4fc9005244 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.cpp
@@ -77,6 +77,12 @@ static cl::opt<AArch64PAuth::AuthCheckMethod>
                                         "to authenticated LR during tail call"),
                                cl::values(AUTH_CHECK_METHOD_CL_VALUES_LR));
 
+static cl::opt<AArch64PAuth::AuthCheckMethod> PAuthIntrinsicCheckMethod(
+    "aarch64-intrinsic-check-method", cl::Hidden,
+    cl::desc("Override the variant of check performed by ptrauth_auth "
+             "intrinsic"),
+    cl::values(AUTH_CHECK_METHOD_CL_VALUES_GENERIC));
+
 static cl::opt<unsigned> AArch64MinimumJumpTableEntries(
     "aarch64-min-jump-table-entries", cl::init(13), cl::Hidden,
     cl::desc("Set minimum number of entries to use a jump table on AArch64"));
@@ -530,3 +536,39 @@ AArch64Subtarget::getAuthenticatedLRCheckMethod() const {
   // performance regression or incompatibility with execute-only mappings.
   return AArch64PAuth::AuthCheckMethod::None;
 }
+
+// Various int_ptrauth_* intrinsics may need to check the authenticated pointer
+// to prevent introducing an oracle. The decision on the particular method to
+// use to check the pointer may depend on whether the target CPU is known to
+// support FEAT_FPAC, the desired security/performance trade-off, etc.
+AArch64PAuth::AuthCheckMethod
+AArch64Subtarget::getPAuthIntrinsicCheckMethod(Intrinsic::ID IntrinsicId,
+                                               AArch64PACKey::ID KeyId) const {
+  using namespace AArch64PAuth;
+
+  bool UseIKey =
+      KeyId == AArch64PACKey::ID::IA || KeyId == AArch64PACKey::ID::IB;
+  AuthCheckMethod Method = AuthCheckMethod::None;
+  cl::opt<AuthCheckMethod> *OverrideOpt = nullptr;
+
+  switch (IntrinsicId) {
+  case Intrinsic::ptrauth_auth:
+    if (!hasPAuth()) {
+      // If generating Armv8.2-compatible code, only I-keys can be used in
+      // authentication.
+      assert(UseIKey && "Authenticating using D-keys without FEAT_PAuth");
+      Method = AuthCheckMethod::None;
+    } else {
+      // DummyLoad should be the fastest method but breaks execute-only code.
+      Method = UseIKey ? AuthCheckMethod::XPAC : AuthCheckMethod::DummyLoad;
+    }
+    OverrideOpt = &PAuthIntrinsicCheckMethod;
+    break;
+  }
+
+  assert(OverrideOpt && "Unhandled intrinsic");
+  if (OverrideOpt->getNumOccurrences())
+    return OverrideOpt->getValue();
+
+  return Method;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64Subtarget.h b/llvm/lib/Target/AArch64/AArch64Subtarget.h
index b2ee2e76d0e8ea8..dd86afd93cba235 100644
--- a/llvm/lib/Target/AArch64/AArch64Subtarget.h
+++ b/llvm/lib/Target/AArch64/AArch64Subtarget.h
@@ -443,6 +443,12 @@ class AArch64Subtarget final : public AArch64GenSubtargetInfo {
   /// Choose a method of checking LR before performing a tail call.
   AArch64PAuth::AuthCheckMethod getAuthenticatedLRCheckMethod() const;
 
+  /// Choose a method of checking the authenticated pointer when lowering
+  /// the PAuth intrinsic.
+  AArch64PAuth::AuthCheckMethod
+  getPAuthIntrinsicCheckMethod(Intrinsic::ID IntrinsicId,
+                               AArch64PACKey::ID KeyId) const;
+
   const PseudoSourceValue *getAddressCheckPSV() const {
     return AddressCheckPSV.get();
   }
diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll
new file mode 100644
index 000000000000000..c1d3b64e89f1746
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll
@@ -0,0 +1,501 @@
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0              -stop-after=finalize-isel < %s \
+; RUN:     | FileCheck --check-prefixes=MIR-HINT %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -stop-after=finalize-isel < %s \
+; RUN:     | FileCheck --check-prefixes=MIR-V83 %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0              -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 < %s \
+; RUN:     | FileCheck --check-prefixes=MIR-HINT %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -stop-after=finalize-isel -global-isel=1 -global-isel-abort=1 < %s \
+; RUN:     | FileCheck --check-prefixes=MIR-V83 %s
+
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0              < %s \
+; RUN:     | FileCheck --check-prefixes=HINT-DEFAULT %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a < %s \
+; RUN:     | FileCheck --check-prefixes=V83,V83-DEFAULT %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -aarch64-intrinsic-check-method=none            < %s \
+; RUN:     | FileCheck --check-prefixes=V83,V83-NONE %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -aarch64-intrinsic-check-method=load            < %s \
+; RUN:     | FileCheck --check-prefixes=V83,V83-LDR %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -aarch64-intrinsic-check-method=high-bits-notbi < %s \
+; RUN:     | FileCheck --check-prefixes=V83,V83-BITS-NOTBI %s
+; RUN: llc -mtriple=aarch64 -verify-machineinstrs -asm-verbose=0 -mattr=v8.3a -aarch64-intrinsic-check-method=xpac            < %s \
+; RUN:     | FileCheck --check-prefixes=V83,V83-XPAC %s
+
+; Check that the expected instruction sequences are emitted between
+; authentication and return from function.
+define i64 @test_check_methods(i64 %signed) {
+; V83-NONE-LABEL:  test_check_methods:
+; V83-NONE-NEXT:     .cfi_startproc
+; V83-NONE-NEXT:     autiza x0
+; V83-NONE-NEXT:     ret
+
+; V83-LDR-LABEL:  test_check_methods:
+; V83-LDR-NEXT:     .cfi_startproc
+; V83-LDR-NEXT:     autiza x0
+; V83-LDR-NEXT:     ldr w8, [x0]
+; V83-LDR-NEXT:     ret
+
+; V83-BITS-NOTBI-LABEL:  test_check_methods:
+; V83-BITS-NOTBI-NEXT:     .cfi_startproc
+; V83-BITS-NOTBI-NEXT:     autiza  x0
+; V83-BITS-NOTBI-NEXT:     eor x8, x0, x0, lsl #1
+; V83-BITS-NOTBI-NEXT:     tbnz x8, #62, .[[FAIL:LBB[_0-9]+]]
+; V83-BITS-NOTBI-NEXT:     ret
+; V83-BITS-NOTBI-NEXT:   .[[FAIL]]:
+; V83-BITS-NOTBI-NEXT:     brk #0xc470
+
+; V83-XPAC-LABEL:  test_check_methods:
+; V83-XPAC-NEXT:     .cfi_startproc
+; V83-XPAC-NEXT:     autiza x0
+; V83-XPAC-NEXT:     mov x8, x0
+; V83-XPAC-NEXT:     xpaci x8
+; V83-XPAC-NEXT:     cmp x8, x0
+; V83-XPAC-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-XPAC-NEXT:     ret
+; V83-XPAC-NEXT:   .[[FAIL]]:
+; V83-XPAC-NEXT:     brk #0xc470
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 0, i64 0)
+  ret i64 %auted
+}
+
+; Check for correct XPAC(I|D) instruction and operand of BRK instruction,
+; once per key.
+
+define i64 @test_xpac_and_brk_ia(i64 %signed) {
+; V83-XPAC-LABEL:  test_xpac_and_brk_ia:
+; V83-XPAC-NEXT:     .cfi_startproc
+; V83-XPAC-NEXT:     autiza x0
+; V83-XPAC-NEXT:     mov x8, x0
+; V83-XPAC-NEXT:     xpaci x8
+; V83-XPAC-NEXT:     cmp x8, x0
+; V83-XPAC-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-XPAC-NEXT:     ret
+; V83-XPAC-NEXT:   .[[FAIL]]:
+; V83-XPAC-NEXT:     brk #0xc470
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 0, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_xpac_and_brk_ib(i64 %signed) {
+; V83-XPAC-LABEL:  test_xpac_and_brk_ib:
+; V83-XPAC-NEXT:     .cfi_startproc
+; V83-XPAC-NEXT:     autizb x0
+; V83-XPAC-NEXT:     mov x8, x0
+; V83-XPAC-NEXT:     xpaci x8
+; V83-XPAC-NEXT:     cmp x8, x0
+; V83-XPAC-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-XPAC-NEXT:     ret
+; V83-XPAC-NEXT:   .[[FAIL]]:
+; V83-XPAC-NEXT:     brk #0xc471
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_xpac_and_brk_da(i64 %signed) "target-features"="+v8.3a" {
+; V83-XPAC-LABEL:  test_xpac_and_brk_da:
+; V83-XPAC-NEXT:     .cfi_startproc
+; V83-XPAC-NEXT:     autdza x0
+; V83-XPAC-NEXT:     mov x8, x0
+; V83-XPAC-NEXT:     xpacd x8
+; V83-XPAC-NEXT:     cmp x8, x0
+; V83-XPAC-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-XPAC-NEXT:     ret
+; V83-XPAC-NEXT:   .[[FAIL]]:
+; V83-XPAC-NEXT:     brk #0xc472
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 2, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_xpac_and_brk_db(i64 %signed) "target-features"="+v8.3a" {
+; V83-XPAC-LABEL:  test_xpac_and_brk_db:
+; V83-XPAC-NEXT:     .cfi_startproc
+; V83-XPAC-NEXT:     autdzb x0
+; V83-XPAC-NEXT:     mov x8, x0
+; V83-XPAC-NEXT:     xpacd x8
+; V83-XPAC-NEXT:     cmp x8, x0
+; V83-XPAC-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-XPAC-NEXT:     ret
+; V83-XPAC-NEXT:   .[[FAIL]]:
+; V83-XPAC-NEXT:     brk #0xc473
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 3, i64 0)
+  ret i64 %auted
+}
+
+; Check for correct AUT* instruction (raw discriminator)
+; and default check method.
+
+define i64 @test_aut_ia(i64 %signed, i64 %disc) {
+; HINT-DEFAULT-LABEL:  test_aut_ia:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov x17, x0
+; HINT-DEFAULT-NEXT:     mov x16, x1
+; HINT-DEFAULT-NEXT:     hint #12
+; HINT-DEFAULT-NEXT:     mov x0, x17
+; HINT-DEFAULT-NEXT:     ret
+
+; V83-DEFAULT-LABEL:  test_aut_ia:
+; V83-DEFAULT-NEXT:     .cfi_startproc
+; V83-DEFAULT-NEXT:     autia x0, x1
+; V83-DEFAULT-NEXT:     mov x1, x0
+; V83-DEFAULT-NEXT:     xpaci x1
+; V83-DEFAULT-NEXT:     cmp x1, x0
+; V83-DEFAULT-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-DEFAULT-NEXT:     ret
+; V83-DEFAULT-NEXT:   .[[FAIL]]:
+; V83-DEFAULT-NEXT:     brk #0xc470
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 0, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_aut_ib(i64 %signed, i64 %disc) {
+; HINT-DEFAULT-LABEL:  test_aut_ib:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov x17, x0
+; HINT-DEFAULT-NEXT:     mov x16, x1
+; HINT-DEFAULT-NEXT:     hint #14
+; HINT-DEFAULT-NEXT:     mov x0, x17
+; HINT-DEFAULT-NEXT:     ret
+
+; V83-DEFAULT-LABEL:  test_aut_ib:
+; V83-DEFAULT-NEXT:     .cfi_startproc
+; V83-DEFAULT-NEXT:     autib x0, x1
+; V83-DEFAULT-NEXT:     mov x1, x0
+; V83-DEFAULT-NEXT:     xpaci x1
+; V83-DEFAULT-NEXT:     cmp x1, x0
+; V83-DEFAULT-NEXT:     b.ne .[[FAIL:LBB[_0-9]+]]
+; V83-DEFAULT-NEXT:     ret
+; V83-DEFAULT-NEXT:   .[[FAIL]]:
+; V83-DEFAULT-NEXT:     brk #0xc471
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_aut_da(i64 %signed, i64 %disc) "target-features"="+v8.3a" {
+; V83-DEFAULT-LABEL:  test_aut_da:
+; V83-DEFAULT-NEXT:     .cfi_startproc
+; V83-DEFAULT-NEXT:     autda x0, x1
+; V83-DEFAULT-NEXT:     ldr w1, [x0]
+; V83-DEFAULT-NEXT:     ret
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 2, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_aut_db(i64 %signed, i64 %disc) "target-features"="+v8.3a" {
+; V83-DEFAULT-LABEL:  test_aut_db:
+; V83-DEFAULT-NEXT:     .cfi_startproc
+; V83-DEFAULT-NEXT:     autdb x0, x1
+; V83-DEFAULT-NEXT:     ldr w1, [x0]
+; V83-DEFAULT-NEXT:     ret
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 3, i64 %disc)
+  ret i64 %auted
+}
+
+; Check for correct AUT* instruction (zero discriminator).
+
+define i64 @test_aut_ia_zero(i64 %signed) {
+; HINT-DEFAULT-LABEL:  test_aut_ia_zero:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov x17, x0
+; HINT-DEFAULT-NEXT:     mov x16, #0
+; HINT-DEFAULT-NEXT:     hint #12
+
+; V83-LABEL:  test_aut_ia_zero:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autiza x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 0, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_aut_ib_zero(i64 %signed) {
+; HINT-DEFAULT-LABEL:  test_aut_ib_zero:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov x17, x0
+; HINT-DEFAULT-NEXT:     mov x16, #0
+; HINT-DEFAULT-NEXT:     hint #14
+
+; V83-LABEL:  test_aut_ib_zero:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autizb x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_aut_da_zero(i64 %signed) "target-features"="+v8.3a" {
+; V83-LABEL:  test_aut_da_zero:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autdza x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 2, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_aut_db_zero(i64 %signed) "target-features"="+v8.3a" {
+; V83-LABEL:  test_aut_db_zero:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autdzb x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 3, i64 0)
+  ret i64 %auted
+}
+
+; Check different signing schemas, both assembler output and MIR instructions.
+;
+; IB key is used instead of IA just because it is not encoded as zero
+; by AArch64 backend.
+
+define i64 @test_zero_disc(i64 %signed) {
+; HINT-DEFAULT-LABEL:  test_zero_disc:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, #0
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_zero_disc:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autizb x0
+
+; MIR-HINT-LABEL:  name: test_zero_disc
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT:            $x17, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 0, 0, 1, implicit-def $x16{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_zero_disc
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 0, 0, 1, implicit-def %{{[0-9]+}}{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 0)
+  ret i64 %auted
+}
+
+define i64 @test_immediate_disc(i64 %signed) {
+; HINT-DEFAULT-LABEL:  test_immediate_disc:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, #42
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_immediate_disc:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     mov x8, #42
+; V83-NEXT:     autib x0, x8
+
+; MIR-HINT-LABEL:  name: test_immediate_disc
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT:            $x17, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 42, 0, 1, implicit-def $x16{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_immediate_disc
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 42, 0, 1, implicit-def %{{[0-9]+}}{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 42)
+  ret i64 %auted
+}
+
+define i64 @test_raw_disc(i64 %signed, i64 %raw_disc) {
+; HINT-DEFAULT-LABEL:  test_raw_disc:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, x1
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_raw_disc:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     autib x0, x1
+
+; MIR-HINT-LABEL:  name: test_raw_disc
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0, $x1
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT-DAG:        %[[RAW_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[RAW_DISC]], 0, 0, 1{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_raw_disc
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0, $x1
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83-DAG:        %[[RAW_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[RAW_DISC]], 0, 0, 1{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %raw_disc)
+  ret i64 %auted
+}
+
+define i64 @test_blended_disc(i64 %signed, i64 %addr_disc) {
+; HINT-DEFAULT-LABEL:  test_blended_disc:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, x1
+; HINT-DEFAULT-NEXT:     movk    x16, #42, lsl #48
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_blended_disc:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     movk x1, #42, lsl #48
+; V83-NEXT:     autib x0, x1
+
+; MIR-HINT-LABEL:  name: test_blended_disc
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0, $x1
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 42, 1, 1{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_blended_disc
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0, $x1
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 42, 1, 1{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %disc = call i64 @llvm.ptrauth.blend(i64 %addr_disc, i64 42)
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_blended_with_zero(i64 %signed, i64 %addr_disc) {
+; HINT-DEFAULT-LABEL:  test_blended_with_zero:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, x1
+; HINT-DEFAULT-NEXT:     movk    x16, #0, lsl #48
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_blended_with_zero:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     movk x1, #0, lsl #48
+; V83-NEXT:     autib x0, x1
+
+; MIR-HINT-LABEL:  name: test_blended_with_zero
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0, $x1
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 0, 1, 1{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_blended_with_zero
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0, $x1
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 0, 1, 1{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %disc = call i64 @llvm.ptrauth.blend(i64 %addr_disc, i64 0)
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_null_blend(i64 %signed) {
+; HINT-DEFAULT-LABEL:  test_null_blend:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     mov     x17, x0
+; HINT-DEFAULT-NEXT:     mov     x16, xzr
+; HINT-DEFAULT-NEXT:     movk    x16, #42, lsl #48
+; HINT-DEFAULT-NEXT:     hint    #14
+
+; V83-LABEL:  test_null_blend:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     mov x8, xzr
+; V83-NEXT:     movk x8, #42, lsl #48
+; V83-NEXT:     autib x0, x8
+
+; MIR-HINT-LABEL:  name: test_null_blend
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT-DAG:        %[[ZERO:[0-9]+]]:gpr64 = COPY $xzr
+; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ZERO]], 42, 1, 1{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_null_blend
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83-DAG:        %[[ZERO:[0-9]+]]:gpr64 = COPY $xzr
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ZERO]], 42, 1, 1{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %disc = call i64 @llvm.ptrauth.blend(i64 0, i64 42)
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
+  ret i64 %auted
+}
+
+define i64 @test_custom_discriminator(i64 %signed, i64 %n) {
+; HINT-DEFAULT-LABEL:  test_custom_discriminator:
+; HINT-DEFAULT-NEXT:     .cfi_startproc
+; HINT-DEFAULT-NEXT:     add x16, x1, #42
+; HINT-DEFAULT-NEXT:     mov x17, x0
+; HINT-DEFAULT-NEXT:     hint #14
+
+; V83-LABEL:  test_custom_discriminator:
+; V83-NEXT:     .cfi_startproc
+; V83-NEXT:     add     x8, x1, #42
+; V83-NEXT:     autib   x0, x8
+
+; MIR-HINT-LABEL:  name: test_custom_discriminator
+; MIR-HINT:        body:
+; MIR-HINT:          bb{{.*}}:
+; MIR-HINT:            liveins: $x0, $x1
+; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-HINT-DAG:        %[[N:[0-9]+]]:gpr64{{.*}} = COPY $x1
+; MIR-HINT-DAG:        %[[DISC:[0-9]+]]:gpr64common = ADDXri %[[N]], 42, 0
+; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[DISC]], 0, 0, 1{{$}}
+; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            RET_ReallyLR implicit $x0
+
+; MIR-V83-LABEL:  name: test_custom_discriminator
+; MIR-V83:        body:
+; MIR-V83:          bb{{.*}}:
+; MIR-V83:            liveins: $x0, $x1
+; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
+; MIR-V83-DAG:        %[[N:[0-9]+]]:gpr64{{.*}} = COPY $x1
+; MIR-V83-DAG:        %[[DISC:[0-9]+]]:gpr64common = ADDXri %[[N]], 42, 0
+; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[DISC]], 0, 0, 1{{$}}
+; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            RET_ReallyLR implicit $x0
+  %disc = add i64 %n, 42
+  %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
+  ret i64 %auted
+}
+
+declare ptr @llvm.frameaddress(i32)
+declare i64 @llvm.ptrauth.auth(i64, i32, i64)
+declare i64 @llvm.ptrauth.blend(i64, i64)
diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll b/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
index ec04e553cac6e37..4bf120400eef171 100644
--- a/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
+++ b/llvm/test/CodeGen/AArch64/sign-return-address-tailcall.ll
@@ -23,7 +23,7 @@ define i32 @tailcall_direct() "sign-return-address"="non-leaf" {
 ;
 ; COMMON-NEXT:    b callee
 ; BRK-NEXT:     .[[FAIL]]:
-; BRK-NEXT:       brk #0xc471
+; BRK-NEXT:       brk #0xc470
   tail call void asm sideeffect "", "~{lr}"()
   %call = tail call i32 @callee()
   ret i32 %call
@@ -48,7 +48,7 @@ define i32 @tailcall_indirect(ptr %fptr) "sign-return-address"="non-leaf" {
 ;
 ; COMMON-NEXT:    br x0
 ; BRK-NEXT:     .[[FAIL]]:
-; BRK-NEXT:       brk #0xc471
+; BRK-NEXT:       brk #0xc470
   tail call void asm sideeffect "", "~{lr}"()
   %call = tail call i32 %fptr()
   ret i32 %call
@@ -89,7 +89,7 @@ define i32 @tailcall_direct_noframe_sign_all() "sign-return-address"="all" {
 ;
 ; COMMON-NEXT:    b callee
 ; BRK-NEXT:     .[[FAIL]]:
-; BRK-NEXT:       brk #0xc471
+; BRK-NEXT:       brk #0xc470
   %call = tail call i32 @callee()
   ret i32 %call
 }
@@ -113,7 +113,7 @@ define i32 @tailcall_indirect_noframe_sign_all(ptr %fptr) "sign-return-address"=
 ;
 ; COMMON-NEXT:    br x0
 ; BRK-NEXT:     .[[FAIL]]:
-; BRK-NEXT:       brk #0xc471
+; BRK-NEXT:       brk #0xc470
   %call = tail call i32 %fptr()
   ret i32 %call
 }

>From 0ffbcf7961d1792a58fccb9a129d488eb09901d6 Mon Sep 17 00:00:00 2001
From: Anatoly Trosinenko <atrosinenko at accesssoftek.com>
Date: Thu, 16 Nov 2023 20:00:34 +0300
Subject: [PATCH 2/2] [test] Drop superfluous -DAG modifiers: output of
 PAUTH_AUTH (inherently ordered instructions)

---
 .../CodeGen/AArch64/ptrauth-intrinsic-auth.ll | 42 +++++++++----------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll
index c1d3b64e89f1746..b186c3ada49286d 100644
--- a/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll
+++ b/llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth.ll
@@ -257,8 +257,8 @@ define i64 @test_zero_disc(i64 %signed) {
 ; MIR-HINT:            liveins: $x0
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT:            $x17, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 0, 0, 1, implicit-def $x16{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_zero_disc
@@ -267,7 +267,7 @@ define i64 @test_zero_disc(i64 %signed) {
 ; MIR-V83:            liveins: $x0
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 0, 0, 1, implicit-def %{{[0-9]+}}{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 0)
   ret i64 %auted
@@ -291,8 +291,8 @@ define i64 @test_immediate_disc(i64 %signed) {
 ; MIR-HINT:            liveins: $x0
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT:            $x17, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 42, 0, 1, implicit-def $x16{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_immediate_disc
@@ -301,7 +301,7 @@ define i64 @test_immediate_disc(i64 %signed) {
 ; MIR-V83:            liveins: $x0
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}$xzr = PAUTH_AUTH %[[SIGNED]], $xzr, 42, 0, 1, implicit-def %{{[0-9]+}}{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 42)
   ret i64 %auted
@@ -325,8 +325,8 @@ define i64 @test_raw_disc(i64 %signed, i64 %raw_disc) {
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT-DAG:        %[[RAW_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[RAW_DISC]], 0, 0, 1{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_raw_disc
@@ -336,7 +336,7 @@ define i64 @test_raw_disc(i64 %signed, i64 %raw_disc) {
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83-DAG:        %[[RAW_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[RAW_DISC]], 0, 0, 1{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %raw_disc)
   ret i64 %auted
@@ -362,8 +362,8 @@ define i64 @test_blended_disc(i64 %signed, i64 %addr_disc) {
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 42, 1, 1{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_blended_disc
@@ -373,7 +373,7 @@ define i64 @test_blended_disc(i64 %signed, i64 %addr_disc) {
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 42, 1, 1{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %disc = call i64 @llvm.ptrauth.blend(i64 %addr_disc, i64 42)
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
@@ -400,8 +400,8 @@ define i64 @test_blended_with_zero(i64 %signed, i64 %addr_disc) {
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 0, 1, 1{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_blended_with_zero
@@ -411,7 +411,7 @@ define i64 @test_blended_with_zero(i64 %signed, i64 %addr_disc) {
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83-DAG:        %[[ADDR_DISC:[0-9]+]]:gpr64 = COPY $x1
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ADDR_DISC]], 0, 1, 1{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %disc = call i64 @llvm.ptrauth.blend(i64 %addr_disc, i64 0)
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
@@ -439,8 +439,8 @@ define i64 @test_null_blend(i64 %signed) {
 ; MIR-HINT-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-HINT-DAG:        %[[ZERO:[0-9]+]]:gpr64 = COPY $xzr
 ; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[ZERO]], 42, 1, 1{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_null_blend
@@ -450,7 +450,7 @@ define i64 @test_null_blend(i64 %signed) {
 ; MIR-V83-DAG:        %[[SIGNED:[0-9]+]]:gpr64common = COPY $x0
 ; MIR-V83-DAG:        %[[ZERO:[0-9]+]]:gpr64 = COPY $xzr
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[ZERO]], 42, 1, 1{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %disc = call i64 @llvm.ptrauth.blend(i64 0, i64 42)
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)
@@ -477,8 +477,8 @@ define i64 @test_custom_discriminator(i64 %signed, i64 %n) {
 ; MIR-HINT-DAG:        %[[N:[0-9]+]]:gpr64{{.*}} = COPY $x1
 ; MIR-HINT-DAG:        %[[DISC:[0-9]+]]:gpr64common = ADDXri %[[N]], 42, 0
 ; MIR-HINT:            $x17, {{(dead )?}}$x16 = PAUTH_AUTH %[[SIGNED]], %[[DISC]], 0, 0, 1{{$}}
-; MIR-HINT-DAG:        %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
-; MIR-HINT-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-HINT:            %[[AUTED:[0-9]+]]:gpr64common = COPY $x17
+; MIR-HINT:            $x0 = COPY %[[AUTED]]
 ; MIR-HINT:            RET_ReallyLR implicit $x0
 
 ; MIR-V83-LABEL:  name: test_custom_discriminator
@@ -489,7 +489,7 @@ define i64 @test_custom_discriminator(i64 %signed, i64 %n) {
 ; MIR-V83-DAG:        %[[N:[0-9]+]]:gpr64{{.*}} = COPY $x1
 ; MIR-V83-DAG:        %[[DISC:[0-9]+]]:gpr64common = ADDXri %[[N]], 42, 0
 ; MIR-V83:            %[[AUTED:[0-9]+]]:gpr64common, {{(dead )?}}%{{[0-9]+}}:gpr64 = PAUTH_AUTH %[[SIGNED]], %[[DISC]], 0, 0, 1{{$}}
-; MIR-V83-DAG:        $x0 = COPY %[[AUTED]]
+; MIR-V83:            $x0 = COPY %[[AUTED]]
 ; MIR-V83:            RET_ReallyLR implicit $x0
   %disc = add i64 %n, 42
   %auted = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 %disc)



More information about the llvm-commits mailing list