[llvm] 4afc256 - Add llvm.protected.field.ptr intrinsic and pre-ISel lowering.

via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 3 17:40:29 PST 2025


Author: Peter Collingbourne
Date: 2025-12-03T17:40:25-08:00
New Revision: 4afc2562fb79eecb218777fe85cbc420b903a70e

URL: https://github.com/llvm/llvm-project/commit/4afc2562fb79eecb218777fe85cbc420b903a70e
DIFF: https://github.com/llvm/llvm-project/commit/4afc2562fb79eecb218777fe85cbc420b903a70e.diff

LOG: Add llvm.protected.field.ptr intrinsic and pre-ISel lowering.

This intrinsic is used to implement pointer field protection.
For more information, see the included LangRef update and the RFC:
https://discourse.llvm.org/t/rfc-structure-protection-a-family-of-uaf-mitigation-techniques/85555

Reviewers: nikic, fmayer, ahmedbougacha

Reviewed By: nikic, fmayer

Pull Request: https://github.com/llvm/llvm-project/pull/151647

Added: 
    llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer-addrspace1.ll
    llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll

Modified: 
    llvm/docs/LangRef.rst
    llvm/include/llvm/IR/Intrinsics.td
    llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 02865f8a29c67..7e93c67a9a31d 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -31721,3 +31721,55 @@ Semantics:
 
 The '``llvm.preserve.struct.access.index``' intrinsic produces the same result
 as a getelementptr with base ``base`` and access operands ``{0, gep_index}``.
+
+'``llvm.protected.field.ptr``' Intrinsic
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Syntax:
+"""""""
+
+::
+
+      declare ptr @llvm.protected.field.ptr(ptr ptr, i64 disc, i1 use_hw_encoding)
+
+Overview:
+"""""""""
+
+The '``llvm.protected.field.ptr``' intrinsic returns a pointer to the
+storage location of a pointer that has special properties as described
+below.
+
+Arguments:
+""""""""""
+
+The first argument is the pointer specifying the location to store the
+pointer. The second argument is the discriminator, which is used as an
+input for the pointer encoding. The third argument specifies whether to
+use a target-specific mechanism to encode the pointer.
+
+Semantics:
+""""""""""
+
+This intrinsic returns a pointer which may be used to store a
+pointer at the specified address that is encoded using the specified
+discriminator. Stores via the pointer will cause the stored pointer to be
+blended with the second argument before being stored. The blend operation
+shall be either a weak but cheap and target-independent operation (if
+the third argument is 0) or a stronger target-specific operation (if the
+third argument is 1). When loading from the pointer, the inverse operation
+is done on the loaded pointer after it is loaded. Specifically, when the
+third argument is 1, the pointer is signed (using pointer authentication
+instructions or emulated PAC if not supported by the hardware) using
+the discriminator before being stored, and authenticated after being
+loaded. Note that it is currently unsupported to have the third argument
+be 1 on targets other than AArch64, and it is also currently unsupported
+to have the third argument be 0 at all.
+
+If the pointer is used other than for loading or storing (e.g. its
+address escapes), that will disable all blending operations using
+the deactivation symbol specified in the intrinsic's operand bundle.
+The deactivation symbol operand bundle is copied onto any sign and auth
+intrinsics that this intrinsic is lowered into. The intent is that the
+deactivation symbol represents a field identifier.
+
+This intrinsic is used to implement structure protection.

diff  --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 8f3cc54747074..c3c4718c3548f 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -2925,6 +2925,13 @@ def int_experimental_convergence_anchor
 def int_experimental_convergence_loop
   : DefaultAttrsIntrinsic<[llvm_token_ty], [], [IntrNoMem, IntrConvergent]>;
 
+//===----------------- Structure Protection Intrinsics --------------------===//
+
+def int_protected_field_ptr :
+  DefaultAttrsIntrinsic<[llvm_anyptr_ty],
+                        [LLVMMatchType<0>, llvm_i64_ty, llvm_i1_ty],
+                        [IntrNoMem, ImmArg<ArgIndex<2>>]>;
+
 //===----------------------------------------------------------------------===//
 // Target-specific intrinsics
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
index 72c3c566163e2..97da9abab0b7b 100644
--- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
+++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
@@ -22,9 +22,11 @@
 #include "llvm/CodeGen/TargetLowering.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalValue.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/IR/Metadata.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/RuntimeLibcalls.h"
 #include "llvm/IR/Type.h"
@@ -471,6 +473,144 @@ bool PreISelIntrinsicLowering::expandMemIntrinsicUses(
   return Changed;
 }
 
+static bool expandProtectedFieldPtr(Function &Intr) {
+  Module &M = *Intr.getParent();
+
+  SmallPtrSet<GlobalValue *, 2> DSsToDeactivate;
+
+  Type *Int8Ty = Type::getInt8Ty(M.getContext());
+  Type *Int64Ty = Type::getInt64Ty(M.getContext());
+  PointerType *PtrTy = PointerType::get(M.getContext(), 0);
+
+  Function *SignIntr =
+      Intrinsic::getOrInsertDeclaration(&M, Intrinsic::ptrauth_sign, {});
+  Function *AuthIntr =
+      Intrinsic::getOrInsertDeclaration(&M, Intrinsic::ptrauth_auth, {});
+
+  auto *EmuFnTy = FunctionType::get(Int64Ty, {Int64Ty, Int64Ty}, false);
+
+  auto CreateSign = [&](IRBuilder<> &B, Value *Val, Value *Disc,
+                        OperandBundleDef DSBundle) {
+    Function *F = B.GetInsertBlock()->getParent();
+    Attribute FSAttr = F->getFnAttribute("target-features");
+    if (FSAttr.isValid() && FSAttr.getValueAsString().contains("+pauth"))
+      return B.CreateCall(
+          SignIntr, {Val, B.getInt32(/*AArch64PACKey::DA*/ 2), Disc}, DSBundle);
+    FunctionCallee EmuSignIntr =
+        M.getOrInsertFunction("__emupac_pacda", EmuFnTy);
+    return B.CreateCall(EmuSignIntr, {Val, Disc}, DSBundle);
+  };
+
+  auto CreateAuth = [&](IRBuilder<> &B, Value *Val, Value *Disc,
+                        OperandBundleDef DSBundle) {
+    Function *F = B.GetInsertBlock()->getParent();
+    Attribute FSAttr = F->getFnAttribute("target-features");
+    if (FSAttr.isValid() && FSAttr.getValueAsString().contains("+pauth"))
+      return B.CreateCall(
+          AuthIntr, {Val, B.getInt32(/*AArch64PACKey::DA*/ 2), Disc}, DSBundle);
+    FunctionCallee EmuAuthIntr =
+        M.getOrInsertFunction("__emupac_autda", EmuFnTy);
+    return B.CreateCall(EmuAuthIntr, {Val, Disc}, DSBundle);
+  };
+
+  auto GetDeactivationSymbol = [&](CallInst *Call) -> GlobalValue * {
+    if (auto Bundle =
+            Call->getOperandBundle(LLVMContext::OB_deactivation_symbol))
+      return cast<GlobalValue>(Bundle->Inputs[0]);
+    return nullptr;
+  };
+
+  for (User *U : llvm::make_early_inc_range(Intr.users())) {
+    auto *Call = cast<CallInst>(U);
+
+    auto *Pointer = Call->getArgOperand(0);
+    auto *Disc = Call->getArgOperand(1);
+    bool UseHWEncoding =
+        cast<ConstantInt>(Call->getArgOperand(2))->getZExtValue();
+    if (!UseHWEncoding)
+      reportFatalUsageError("software encoding currently unsupported");
+
+    auto *DS = GetDeactivationSymbol(Call);
+    OperandBundleDef DSBundle("deactivation-symbol", DS);
+
+    for (Use &U : llvm::make_early_inc_range(Call->uses())) {
+      // Insert code to encode each pointer stored to the pointer returned by
+      // the intrinsic.
+      if (auto *SI = dyn_cast<StoreInst>(U.getUser())) {
+        if (U.getOperandNo() == 1 &&
+            isa<PointerType>(SI->getValueOperand()->getType())) {
+          IRBuilder<> B(SI);
+          auto *SIValInt =
+              B.CreatePtrToInt(SI->getValueOperand(), B.getInt64Ty());
+          Value *Sign = CreateSign(B, SIValInt, Disc, DSBundle);
+          SI->setOperand(0, B.CreateIntToPtr(Sign, B.getPtrTy()));
+          SI->setOperand(1, Pointer);
+          continue;
+        }
+      }
+
+      // Insert code to decode each pointer loaded from the pointer returned by
+      // the intrinsic. This is the inverse of the encode operation implemented
+      // above.
+      if (auto *LI = dyn_cast<LoadInst>(U.getUser())) {
+        if (isa<PointerType>(LI->getType())) {
+          IRBuilder<> B(LI);
+          auto *NewLI = cast<LoadInst>(LI->clone());
+          NewLI->setOperand(0, Pointer);
+          B.Insert(NewLI);
+          auto *LIInt = B.CreatePtrToInt(NewLI, B.getInt64Ty());
+          Value *Auth = CreateAuth(B, LIInt, Disc, DSBundle);
+          LI->replaceAllUsesWith(B.CreateIntToPtr(Auth, B.getPtrTy()));
+          LI->eraseFromParent();
+          continue;
+        }
+      }
+      // Comparisons against null cannot be used to recover the original
+      // pointer so we replace them with comparisons against the original
+      // pointer.
+      if (auto *CI = dyn_cast<ICmpInst>(U.getUser())) {
+        if (auto *Op = dyn_cast<Constant>(CI->getOperand(0))) {
+          if (Op->isNullValue()) {
+            CI->setOperand(1, Pointer);
+            continue;
+          }
+        }
+        if (auto *Op = dyn_cast<Constant>(CI->getOperand(1))) {
+          if (Op->isNullValue()) {
+            CI->setOperand(0, Pointer);
+            continue;
+          }
+        }
+      }
+
+      // We couldn't rewrite away this use of the intrinsic. Replace it with the
+      // pointer operand, and arrange to define a deactivation symbol.
+      U.set(Pointer);
+      if (DS)
+        DSsToDeactivate.insert(DS);
+    }
+
+    Call->eraseFromParent();
+  }
+
+  if (!DSsToDeactivate.empty()) {
+    // This is an AArch64 NOP instruction. When the deactivation symbol support
+    // is expanded to more architectures, there will likely need to be an API
+    // for retrieving this constant.
+    Constant *Nop =
+        ConstantExpr::getIntToPtr(ConstantInt::get(Int64Ty, 0xd503201f), PtrTy);
+    for (GlobalValue *OldDS : DSsToDeactivate) {
+      GlobalValue *DS = GlobalAlias::create(
+          Int8Ty, 0, GlobalValue::ExternalLinkage, OldDS->getName(), Nop, &M);
+      DS->setVisibility(GlobalValue::HiddenVisibility);
+      DS->takeName(OldDS);
+      OldDS->replaceAllUsesWith(DS);
+      OldDS->eraseFromParent();
+    }
+  }
+  return true;
+}
+
 bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
   // Map unique constants to globals.
   DenseMap<Constant *, GlobalVariable *> CMap;
@@ -613,6 +753,9 @@ bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
         return lowerUnaryVectorIntrinsicAsLoop(M, CI);
       });
       break;
+    case Intrinsic::protected_field_ptr:
+      Changed |= expandProtectedFieldPtr(F);
+      break;
     }
   }
   return Changed;

diff  --git a/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer-addrspace1.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer-addrspace1.ll
new file mode 100644
index 0000000000000..f98807c255383
--- /dev/null
+++ b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer-addrspace1.ll
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
+; RUN: opt -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefix=NOPAUTH %s
+; RUN: opt -passes=pre-isel-intrinsic-lowering -mattr=+pauth -S < %s | FileCheck --check-prefix=PAUTH %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+ at ds1 = external global i8
+ at ds2 = external global i8
+ at ds3 = external global i8
+ at ds4 = external global i8
+
+;.
+; NOPAUTH: @ds1 = external global i8
+; NOPAUTH: @ds2 = external global i8
+; NOPAUTH: @ds3 = external global i8
+; NOPAUTH: @ds4 = hidden alias i8, inttoptr (i64 3573751839 to ptr)
+;.
+; PAUTH: @ds1 = external global i8
+; PAUTH: @ds2 = external global i8
+; PAUTH: @ds3 = external global i8
+; PAUTH: @ds4 = hidden alias i8, inttoptr (i64 3573751839 to ptr)
+;.
+define ptr @load_hw(ptr addrspace(1) %ptrptr) {
+; NOPAUTH-LABEL: define ptr @load_hw(
+; NOPAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    [[PTR:%.*]] = load ptr, ptr addrspace(1) [[PTRPTR]], align 8
+; NOPAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT:    [[TMP2:%.*]] = call i64 @__emupac_autda(i64 [[TMP1]], i64 1) [ "deactivation-symbol"(ptr @ds1) ]
+; NOPAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; NOPAUTH-NEXT:    ret ptr [[TMP3]]
+;
+; PAUTH-LABEL: define ptr @load_hw(
+; PAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) #[[ATTR0:[0-9]+]] {
+; PAUTH-NEXT:    [[PTR:%.*]] = load ptr, ptr addrspace(1) [[PTRPTR]], align 8
+; PAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT:    [[TMP2:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TMP1]], i32 2, i64 1) [ "deactivation-symbol"(ptr @ds1) ]
+; PAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; PAUTH-NEXT:    ret ptr [[TMP3]]
+;
+  %protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 1, i1 true) [ "deactivation-symbol"(ptr @ds1) ]
+  %ptr = load ptr, ptr addrspace(1) %protptrptr
+  ret ptr %ptr
+}
+
+define void @store_hw(ptr addrspace(1) %ptrptr, ptr %ptr) {
+; NOPAUTH-LABEL: define void @store_hw(
+; NOPAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]], ptr [[PTR:%.*]]) {
+; NOPAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT:    [[TMP2:%.*]] = call i64 @__emupac_pacda(i64 [[TMP1]], i64 2) [ "deactivation-symbol"(ptr @ds2) ]
+; NOPAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; NOPAUTH-NEXT:    store ptr [[TMP3]], ptr addrspace(1) [[PTRPTR]], align 8
+; NOPAUTH-NEXT:    ret void
+;
+; PAUTH-LABEL: define void @store_hw(
+; PAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]], ptr [[PTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT:    [[TMP2:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[TMP1]], i32 2, i64 2) [ "deactivation-symbol"(ptr @ds2) ]
+; PAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; PAUTH-NEXT:    store ptr [[TMP3]], ptr addrspace(1) [[PTRPTR]], align 8
+; PAUTH-NEXT:    ret void
+;
+  %protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 2, i1 true) [ "deactivation-symbol"(ptr @ds2) ]
+  store ptr %ptr, ptr addrspace(1) %protptrptr
+  ret void
+}
+
+define i1 @compare(ptr addrspace(1) %ptrptr) {
+; NOPAUTH-LABEL: define i1 @compare(
+; NOPAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    [[CMP1:%.*]] = icmp eq ptr addrspace(1) [[PTRPTR]], null
+; NOPAUTH-NEXT:    [[CMP2:%.*]] = icmp eq ptr addrspace(1) null, [[PTRPTR]]
+; NOPAUTH-NEXT:    [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
+; NOPAUTH-NEXT:    ret i1 [[CMP]]
+;
+; PAUTH-LABEL: define i1 @compare(
+; PAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    [[CMP1:%.*]] = icmp eq ptr addrspace(1) [[PTRPTR]], null
+; PAUTH-NEXT:    [[CMP2:%.*]] = icmp eq ptr addrspace(1) null, [[PTRPTR]]
+; PAUTH-NEXT:    [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
+; PAUTH-NEXT:    ret i1 [[CMP]]
+;
+  %protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds3) ]
+  %cmp1 = icmp eq ptr addrspace(1) %protptrptr, null
+  %cmp2 = icmp eq ptr addrspace(1) null, %protptrptr
+  %cmp = or i1 %cmp1, %cmp2
+  ret i1 %cmp
+}
+
+define ptr addrspace(1) @escape(ptr addrspace(1) %ptrptr) {
+; NOPAUTH-LABEL: define ptr addrspace(1) @escape(
+; NOPAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    ret ptr addrspace(1) [[PTRPTR]]
+;
+; PAUTH-LABEL: define ptr addrspace(1) @escape(
+; PAUTH-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    ret ptr addrspace(1) [[PTRPTR]]
+;
+  %protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds4) ]
+  ret ptr addrspace(1) %protptrptr
+}
+
+declare ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1), i64, i1 immarg)
+;.
+; NOPAUTH: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
+; NOPAUTH: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(none) }
+;.
+; PAUTH: attributes #[[ATTR0]] = { "target-features"="+pauth" }
+; PAUTH: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) "target-features"="+pauth" }
+; PAUTH: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
+; PAUTH: attributes #[[ATTR3:[0-9]+]] = { nounwind memory(none) }
+;.

diff  --git a/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll
new file mode 100644
index 0000000000000..ba611fe4488bc
--- /dev/null
+++ b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll
@@ -0,0 +1,111 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 5
+; RUN: opt -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefix=NOPAUTH %s
+; RUN: opt -passes=pre-isel-intrinsic-lowering -mattr=+pauth -S < %s | FileCheck --check-prefix=PAUTH %s
+
+target triple = "aarch64-unknown-linux-gnu"
+
+ at ds1 = external global i8
+ at ds2 = external global i8
+ at ds3 = external global i8
+ at ds4 = external global i8
+
+;.
+; NOPAUTH: @ds1 = external global i8
+; NOPAUTH: @ds2 = external global i8
+; NOPAUTH: @ds3 = external global i8
+; NOPAUTH: @ds4 = hidden alias i8, inttoptr (i64 3573751839 to ptr)
+;.
+; PAUTH: @ds1 = external global i8
+; PAUTH: @ds2 = external global i8
+; PAUTH: @ds3 = external global i8
+; PAUTH: @ds4 = hidden alias i8, inttoptr (i64 3573751839 to ptr)
+;.
+define ptr @load_hw(ptr %ptrptr) {
+; NOPAUTH-LABEL: define ptr @load_hw(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    [[PTR:%.*]] = load ptr, ptr [[PTRPTR]], align 8
+; NOPAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT:    [[TMP2:%.*]] = call i64 @__emupac_autda(i64 [[TMP1]], i64 1) [ "deactivation-symbol"(ptr @ds1) ]
+; NOPAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; NOPAUTH-NEXT:    ret ptr [[TMP3]]
+;
+; PAUTH-LABEL: define ptr @load_hw(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0:[0-9]+]] {
+; PAUTH-NEXT:    [[PTR:%.*]] = load ptr, ptr [[PTRPTR]], align 8
+; PAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT:    [[TMP2:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TMP1]], i32 2, i64 1) [ "deactivation-symbol"(ptr @ds1) ]
+; PAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; PAUTH-NEXT:    ret ptr [[TMP3]]
+;
+  %protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 1, i1 true) [ "deactivation-symbol"(ptr @ds1) ]
+  %ptr = load ptr, ptr %protptrptr
+  ret ptr %ptr
+}
+
+define void @store_hw(ptr %ptrptr, ptr %ptr) {
+; NOPAUTH-LABEL: define void @store_hw(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]], ptr [[PTR:%.*]]) {
+; NOPAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT:    [[TMP2:%.*]] = call i64 @__emupac_pacda(i64 [[TMP1]], i64 2) [ "deactivation-symbol"(ptr @ds2) ]
+; NOPAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; NOPAUTH-NEXT:    store ptr [[TMP3]], ptr [[PTRPTR]], align 8
+; NOPAUTH-NEXT:    ret void
+;
+; PAUTH-LABEL: define void @store_hw(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]], ptr [[PTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT:    [[TMP2:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[TMP1]], i32 2, i64 2) [ "deactivation-symbol"(ptr @ds2) ]
+; PAUTH-NEXT:    [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
+; PAUTH-NEXT:    store ptr [[TMP3]], ptr [[PTRPTR]], align 8
+; PAUTH-NEXT:    ret void
+;
+  %protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 2, i1 true) [ "deactivation-symbol"(ptr @ds2) ]
+  store ptr %ptr, ptr %protptrptr
+  ret void
+}
+
+define i1 @compare(ptr %ptrptr) {
+; NOPAUTH-LABEL: define i1 @compare(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    [[CMP1:%.*]] = icmp eq ptr [[PTRPTR]], null
+; NOPAUTH-NEXT:    [[CMP2:%.*]] = icmp eq ptr null, [[PTRPTR]]
+; NOPAUTH-NEXT:    [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
+; NOPAUTH-NEXT:    ret i1 [[CMP]]
+;
+; PAUTH-LABEL: define i1 @compare(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    [[CMP1:%.*]] = icmp eq ptr [[PTRPTR]], null
+; PAUTH-NEXT:    [[CMP2:%.*]] = icmp eq ptr null, [[PTRPTR]]
+; PAUTH-NEXT:    [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
+; PAUTH-NEXT:    ret i1 [[CMP]]
+;
+  %protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds3) ]
+  %cmp1 = icmp eq ptr %protptrptr, null
+  %cmp2 = icmp eq ptr null, %protptrptr
+  %cmp = or i1 %cmp1, %cmp2
+  ret i1 %cmp
+}
+
+define ptr @escape(ptr %ptrptr) {
+; NOPAUTH-LABEL: define ptr @escape(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT:    ret ptr [[PTRPTR]]
+;
+; PAUTH-LABEL: define ptr @escape(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT:    ret ptr [[PTRPTR]]
+;
+  %protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds4) ]
+  ret ptr %protptrptr
+}
+
+declare ptr @llvm.protected.field.ptr.p0(ptr, i64, i1 immarg)
+;.
+; NOPAUTH: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
+; NOPAUTH: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(none) }
+;.
+; PAUTH: attributes #[[ATTR0]] = { "target-features"="+pauth" }
+; PAUTH: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) "target-features"="+pauth" }
+; PAUTH: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
+; PAUTH: attributes #[[ATTR3:[0-9]+]] = { nounwind memory(none) }
+;.


        


More information about the llvm-commits mailing list