[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