aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcxx/include/__config4
-rw-r--r--libcxx/include/__force_nonstandard_layout2
-rw-r--r--libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp6
-rw-r--r--libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp2
-rw-r--r--libcxxabi/include/__cxxabi_config.h2
-rw-r--r--lld/ELF/Relocations.cpp5
-rw-r--r--llvm/docs/LangRef.rst4
-rw-r--r--llvm/include/llvm/Transforms/Utils/Local.h7
-rw-r--r--llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp118
-rw-r--r--llvm/lib/IR/Verifier.cpp5
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp4
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp2
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp2
-rw-r--r--llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll171
-rw-r--r--llvm/test/Transforms/SROA/protected-field-pointer.ll60
-rw-r--r--llvm/test/Transforms/Util/phi-protected-field-ptr.ll27
-rw-r--r--llvm/test/Verifier/ptrauth-constant.ll6
17 files changed, 279 insertions, 148 deletions
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 60bbcb8..7222cf2 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -490,7 +490,7 @@ typedef __char32_t char32_t;
# define _LIBCPP_EXCEPTIONS_SIG e
# endif
-# if __has_feature(pointer_field_protection)
+# if __has_extension(pointer_field_protection)
# define _LIBCPP_PFP_SIG p
# else
# define _LIBCPP_PFP_SIG
@@ -1275,7 +1275,7 @@ typedef __char32_t char32_t;
# define _LIBCPP_HAS_EXPLICIT_THIS_PARAMETER 0
# endif
-# if __has_feature(pointer_field_protection)
+# if __has_extension(pointer_field_protection)
# define _LIBCPP_NO_PFP [[clang::no_field_protection]]
# else
# define _LIBCPP_NO_PFP
diff --git a/libcxx/include/__force_nonstandard_layout b/libcxx/include/__force_nonstandard_layout
index 6cc748f..319ddd4 100644
--- a/libcxx/include/__force_nonstandard_layout
+++ b/libcxx/include/__force_nonstandard_layout
@@ -32,7 +32,7 @@ class __force_nonstandard_layout_base2 : __force_nonstandard_layout_base1 {};
class __force_nonstandard_layout : __force_nonstandard_layout_base1, __force_nonstandard_layout_base2 {};
_LIBCPP_DIAGNOSTIC_POP
-#if __has_feature(pointer_field_protection)
+#if __has_extension(pointer_field_protection)
# define _LIBCPP_MAYBE_FORCE_NONSTANDARD_LAYOUT : __force_nonstandard_layout
#else
# define _LIBCPP_MAYBE_FORCE_NONSTANDARD_LAYOUT
diff --git a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
index d849149..402c5ad 100644
--- a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
+++ b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
@@ -256,7 +256,7 @@ void unique_ptr_test() {
ComparePrettyPrintToRegex(std::move(forty_two),
R"(std::unique_ptr<int> containing = {__ptr_ = 0x[a-f0-9]+})");
-#if !__has_feature(pointer_field_protection)
+#if !__has_extension(pointer_field_protection)
// GDB doesn't know how to read PFP fields correctly yet.
std::unique_ptr<int> this_is_null;
ComparePrettyPrintToChars(std::move(this_is_null),
@@ -479,7 +479,7 @@ void vector_test() {
"std::vector of length "
"3, capacity 3 = {5, 6, 7}");
-#if !__has_feature(pointer_field_protection)
+#if !__has_extension(pointer_field_protection)
// GDB doesn't know how to read PFP fields correctly yet.
std::vector<int, UncompressibleAllocator<int>> test3({7, 8});
ComparePrettyPrintToChars(std::move(test3),
@@ -656,7 +656,7 @@ void shared_ptr_test() {
test0,
R"(std::shared_ptr<int> count [3\?], weak [0\?]( \(libc\+\+ missing debug info\))? containing = {__ptr_ = 0x[a-f0-9]+})");
-#if !__has_feature(pointer_field_protection)
+#if !__has_extension(pointer_field_protection)
// GDB doesn't know how to read PFP fields correctly yet.
std::shared_ptr<const int> test3;
ComparePrettyPrintToChars(test3, "std::shared_ptr is nullptr");
diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
index 3b9d7e1..4149a7a 100644
--- a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
+++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.compile.pass.cpp
@@ -28,7 +28,7 @@
# include <locale>
#endif
-#if __has_feature(pointer_field_protection)
+#if __has_extension(pointer_field_protection)
constexpr bool pfp_disabled = false;
#else
constexpr bool pfp_disabled = true;
diff --git a/libcxxabi/include/__cxxabi_config.h b/libcxxabi/include/__cxxabi_config.h
index 00e1357..2e8ab66 100644
--- a/libcxxabi/include/__cxxabi_config.h
+++ b/libcxxabi/include/__cxxabi_config.h
@@ -110,7 +110,7 @@
#endif
#if defined(_LIBCXXABI_COMPILER_CLANG)
-# if __has_feature(pointer_field_protection)
+# if __has_extension(pointer_field_protection)
# define _LIBCXXABI_NO_PFP [[clang::no_field_protection]]
# else
# define _LIBCXXABI_NO_PFP
diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp
index 2573cf5..e2f594f 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1175,9 +1175,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset,
<< " cannot be used against ifunc symbol '" << &sym << "'";
printLocation(diag, *sec, sym, offset);
} else {
- part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset,
- DynamicReloc::AddendOnlyWithTargetVA, sym,
- addend, R_ABS});
+ part.relaDyn->addReloc({ctx.target->iRelativeRel, sec, offset, false,
+ sym, addend, R_ABS});
return;
}
}
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 9a9635b..96dcb21 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -31200,14 +31200,14 @@ 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 struct address before being stored, and authenticated after being
+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. When the third argument is 0, it is
rotated left by 16 bits and the discriminator is subtracted before being
stored, and the discriminator is added and the pointer is rotated right
by 16 bits after being loaded.
-If the pointer is used otherwise than for loading or storing (e.g. its
+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
diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
index 557f610..926cb73 100644
--- a/llvm/include/llvm/Transforms/Utils/Local.h
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
@@ -182,9 +182,10 @@ LLVM_ABI bool EliminateDuplicatePHINodes(BasicBlock *BB);
LLVM_ABI bool EliminateDuplicatePHINodes(BasicBlock *BB,
SmallPtrSetImpl<PHINode *> &ToRemove);
-/// Returns whether it is allowed and beneficial for optimizations to transform
-/// phi(load(ptr)) into load(phi(ptr)) or a similar transformation for stores.
-bool shouldFoldLoadStoreWithPointerOperandThroughPhi(const Value *Ptr);
+/// Returns whether it is allowed and beneficial for optimizations to fold this
+/// operand through a phi, for example when transforming phi(load(ptr)) into
+/// load(phi(ptr)).
+bool shouldFoldOperandThroughPhi(const Value *Ptr);
/// This function is used to do simplification of a CFG. For example, it
/// adjusts branches to branches to eliminate the extra hop, it eliminates
diff --git a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
index 480e263..5d7129a 100644
--- a/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
+++ b/llvm/lib/CodeGen/PreISelIntrinsicLowering.cpp
@@ -39,8 +39,6 @@
#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
#include "llvm/Transforms/Utils/LowerVectorIntrinsics.h"
-#include <set>
-
using namespace llvm;
/// Threshold to leave statically sized memory intrinsic calls. Calls of known
@@ -476,8 +474,8 @@ enum class PointerEncoding {
bool expandProtectedFieldPtr(Function &Intr) {
Module &M = *Intr.getParent();
- std::set<GlobalValue *> DSsToDeactivate;
- std::set<Instruction *> LoadsStores;
+ SmallPtrSet<GlobalValue *, 2> DSsToDeactivate;
+ SmallPtrSet<Instruction *, 2> LoadsStores;
Type *Int8Ty = Type::getInt8Ty(M.getContext());
Type *Int64Ty = Type::getInt64Ty(M.getContext());
@@ -520,84 +518,46 @@ bool expandProtectedFieldPtr(Function &Intr) {
for (User *U : Intr.users()) {
auto *Call = cast<CallInst>(U);
auto *DS = GetDeactivationSymbol(Call);
- std::set<PHINode *> VisitedPhis;
-
- std::function<void(Instruction *)> FindLoadsStores;
- FindLoadsStores = [&](Instruction *I) {
- for (Use &U : I->uses()) {
- if (auto *LI = dyn_cast<LoadInst>(U.getUser())) {
- if (isa<PointerType>(LI->getType())) {
- LoadsStores.insert(LI);
- continue;
- }
- }
- if (auto *SI = dyn_cast<StoreInst>(U.getUser())) {
- if (U.getOperandNo() == 1 &&
- isa<PointerType>(SI->getValueOperand()->getType())) {
- LoadsStores.insert(SI);
- continue;
- }
- }
- if (auto *P = dyn_cast<PHINode>(U.getUser())) {
- if (VisitedPhis.insert(P).second)
- FindLoadsStores(P);
+
+ for (Use &U : Call->uses()) {
+ if (auto *LI = dyn_cast<LoadInst>(U.getUser())) {
+ if (isa<PointerType>(LI->getType())) {
+ LoadsStores.insert(LI);
continue;
}
- // Comparisons against null cannot be used to recover the original
- // pointer so we allow them.
- if (auto *CI = dyn_cast<ICmpInst>(U.getUser())) {
- if (auto *Op = dyn_cast<Constant>(CI->getOperand(0)))
- if (Op->isNullValue())
- continue;
- if (auto *Op = dyn_cast<Constant>(CI->getOperand(1)))
- if (Op->isNullValue())
- continue;
- }
- if (DS)
- DSsToDeactivate.insert(DS);
}
- };
-
- FindLoadsStores(Call);
- }
-
- for (Instruction *I : LoadsStores) {
- std::set<Value *> Pointers;
- std::set<Value *> Discs;
- std::set<GlobalValue *> DSs;
- std::set<PHINode *> VisitedPhis;
- bool UseHWEncoding = false;
-
- std::function<void(Value *)> FindFields;
- FindFields = [&](Value *V) {
- if (auto *Call = dyn_cast<CallInst>(V)) {
- if (Call->getCalledOperand() == &Intr) {
- Pointers.insert(Call->getArgOperand(0));
- Discs.insert(Call->getArgOperand(1));
- if (cast<ConstantInt>(Call->getArgOperand(2))->getZExtValue())
- UseHWEncoding = true;
- DSs.insert(GetDeactivationSymbol(Call));
- return;
+ if (auto *SI = dyn_cast<StoreInst>(U.getUser())) {
+ if (U.getOperandNo() == 1 &&
+ isa<PointerType>(SI->getValueOperand()->getType())) {
+ LoadsStores.insert(SI);
+ continue;
}
}
- if (auto *P = dyn_cast<PHINode>(V)) {
- if (VisitedPhis.insert(P).second)
- for (Value *V : P->incoming_values())
- FindFields(V);
- return;
+ // Comparisons against null cannot be used to recover the original
+ // pointer so we allow them.
+ if (auto *CI = dyn_cast<ICmpInst>(U.getUser())) {
+ if (auto *Op = dyn_cast<Constant>(CI->getOperand(0)))
+ if (Op->isNullValue())
+ continue;
+ if (auto *Op = dyn_cast<Constant>(CI->getOperand(1)))
+ if (Op->isNullValue())
+ continue;
}
- Pointers.insert(nullptr);
- };
- FindFields(isa<StoreInst>(I) ? cast<StoreInst>(I)->getPointerOperand()
- : cast<LoadInst>(I)->getPointerOperand());
- if (Pointers.size() != 1 || Discs.size() != 1 || DSs.size() != 1) {
- for (GlobalValue *DS : DSs)
- if (DS)
- DSsToDeactivate.insert(DS);
- continue;
+ if (DS)
+ DSsToDeactivate.insert(DS);
}
+ }
+
+ for (Instruction *I : LoadsStores) {
+ auto *PointerOperand = isa<StoreInst>(I)
+ ? cast<StoreInst>(I)->getPointerOperand()
+ : cast<LoadInst>(I)->getPointerOperand();
+ auto *Call = cast<CallInst>(PointerOperand);
+
+ auto *Disc = Call->getArgOperand(1);
+ bool UseHWEncoding = cast<ConstantInt>(Call->getArgOperand(2))->getZExtValue();
- GlobalValue *DS = *DSs.begin();
+ GlobalValue *DS = GetDeactivationSymbol(Call);
OperandBundleDef DSBundle("deactivation-symbol", DS);
if (auto *LI = dyn_cast<LoadInst>(I)) {
@@ -605,26 +565,28 @@ bool expandProtectedFieldPtr(Function &Intr) {
auto *LIInt = cast<Instruction>(B.CreatePtrToInt(LI, B.getInt64Ty()));
Value *Auth;
if (UseHWEncoding) {
- Auth = CreateAuth(B, LIInt, *Discs.begin(), DSBundle);
+ Auth = CreateAuth(B, LIInt, Disc, DSBundle);
} else {
- Auth = B.CreateAdd(LIInt, *Discs.begin());
+ Auth = B.CreateAdd(LIInt, Disc);
Auth = B.CreateIntrinsic(
Auth->getType(), Intrinsic::fshr,
{Auth, Auth, ConstantInt::get(Auth->getType(), 16)});
}
LI->replaceAllUsesWith(B.CreateIntToPtr(Auth, B.getPtrTy()));
LIInt->setOperand(0, LI);
- } else if (auto *SI = dyn_cast<StoreInst>(I)) {
+ } else {
+ auto *SI = cast<StoreInst>(I);
IRBuilder<> B(SI);
auto *SIValInt =
B.CreatePtrToInt(SI->getValueOperand(), B.getInt64Ty());
Value *Sign;
if (UseHWEncoding) {
- Sign = CreateSign(B, SIValInt, *Discs.begin(), DSBundle);
+ Sign = CreateSign(B, SIValInt, Disc, DSBundle);
} else {
Sign = B.CreateIntrinsic(
SIValInt->getType(), Intrinsic::fshl,
{SIValInt, SIValInt, ConstantInt::get(SIValInt->getType(), 16)});
+ Sign = B.CreateSub(Sign, Disc);
}
SI->setOperand(0, B.CreateIntToPtr(Sign, B.getPtrTy()));
}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 3ff9895..3478c2c 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -2627,6 +2627,11 @@ void Verifier::visitConstantPtrAuth(const ConstantPtrAuth *CPA) {
Check(CPA->getDiscriminator()->getBitWidth() == 64,
"signed ptrauth constant discriminator must be i64 constant integer");
+
+ Check(isa<GlobalValue>(CPA->getDeactivationSymbol()) ||
+ CPA->getDeactivationSymbol()->isNullValue(),
+ "signed ptrauth constant deactivation symbol must be a global value "
+ "or null");
}
bool Verifier::verifyAttributeCount(AttributeList Attrs, unsigned Params) {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index f156883..316e5b2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -697,7 +697,7 @@ static bool isSafeAndProfitableToSinkLoad(LoadInst *L) {
Instruction *InstCombinerImpl::foldPHIArgLoadIntoPHI(PHINode &PN) {
LoadInst *FirstLI = cast<LoadInst>(PN.getIncomingValue(0));
- if (!shouldFoldLoadStoreWithPointerOperandThroughPhi(FirstLI->getOperand(0)))
+ if (!shouldFoldOperandThroughPhi(FirstLI->getOperand(0)))
return nullptr;
// FIXME: This is overconservative; this transform is allowed in some cases
@@ -736,7 +736,7 @@ Instruction *InstCombinerImpl::foldPHIArgLoadIntoPHI(PHINode &PN) {
LI->getPointerAddressSpace() != LoadAddrSpace)
return nullptr;
- if (!shouldFoldLoadStoreWithPointerOperandThroughPhi(LI->getOperand(0)))
+ if (!shouldFoldOperandThroughPhi(LI->getOperand(0)))
return nullptr;
// We can't sink the load if the loaded value could be modified between
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index e2bf56b..f9aa845 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3846,7 +3846,7 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) {
if (Op->getType()->isMetadataTy())
return false;
- if (!shouldFoldLoadStoreWithPointerOperandThroughPhi(Op))
+ if (!shouldFoldOperandThroughPhi(Op))
return false;
// Cannot replace alloca argument with phi/select.
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 6b7a05b..a9c88987 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -2134,7 +2134,7 @@ static bool replacingOperandWithVariableIsCheap(const Instruction *I,
return !isa<IntrinsicInst>(I);
}
-bool llvm::shouldFoldLoadStoreWithPointerOperandThroughPhi(const Value *Ptr) {
+bool llvm::shouldFoldOperandThroughPhi(const Value *Ptr) {
// swifterror pointers can only be used by a load or store; sinking a load
// or store would require introducing a select for the pointer operand,
// which isn't allowed for swifterror pointers.
diff --git a/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll
index a8656a8..173240c 100644
--- a/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll
+++ b/llvm/test/Transforms/PreISelIntrinsicLowering/protected-field-pointer.ll
@@ -1,46 +1,167 @@
-; RUN: opt -passes=pre-isel-intrinsic-lowering -S < %s | FileCheck --check-prefixes=CHECK,NOPAUTH %s
-; RUN: opt -passes=pre-isel-intrinsic-lowering -mattr=+pauth -S < %s | FileCheck --check-prefixes=CHECK,PAUTH %s
+; 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"
-; CHECK: @ds1 = external global i8
@ds1 = external global i8
-; CHECK: @ds2 = external global i8
@ds2 = external global i8
-; CHECK: @ds3 = hidden alias i8, inttoptr (i64 3573751839 to ptr)
@ds3 = external global i8
+@ds4 = external global i8
+@ds5 = external global i8
+@ds6 = external global i8
-; CHECK: define ptr @f1
-define ptr @f1(ptr %ptrptr) {
- ; CHECK: %ptr = load ptr, ptr %ptrptr, align 8
- ; CHECK: %1 = ptrtoint ptr %ptr to i64
- ; NOPAUTH: %2 = call i64 @__emupac_autda(i64 %1, i64 1) [ "deactivation-symbol"(ptr @ds1) ]
- ; PAUTH: %2 = call i64 @llvm.ptrauth.auth(i64 %1, i32 2, i64 1) [ "deactivation-symbol"(ptr @ds1) ]
- ; CHECK: %3 = inttoptr i64 %2 to ptr
- ; CHECK: ret ptr %3
+;.
+; NOPAUTH: @ds1 = external global i8
+; NOPAUTH: @ds2 = external global i8
+; NOPAUTH: @ds3 = external global i8
+; NOPAUTH: @ds4 = external global i8
+; NOPAUTH: @ds5 = external global i8
+; NOPAUTH: @ds6 = 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 = external global i8
+; PAUTH: @ds5 = external global i8
+; PAUTH: @ds6 = 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(ptr %ptrptr, i64 1, i1 true) [ "deactivation-symbol"(ptr @ds1) ]
%ptr = load ptr, ptr %protptrptr
ret ptr %ptr
}
-; CHECK: define void @f2
-define void @f2(ptr %ptrptr, ptr %ptr) {
- ; CHECK: %1 = ptrtoint ptr %ptr to i64
- ; NOPAUTH: %2 = call i64 @__emupac_pacda(i64 %1, i64 2) [ "deactivation-symbol"(ptr @ds2) ]
- ; PAUTH: %2 = call i64 @llvm.ptrauth.sign(i64 %1, i32 2, i64 2) [ "deactivation-symbol"(ptr @ds2) ]
- ; CHECK: %3 = inttoptr i64 %2 to ptr
- ; CHECK: store ptr %3, ptr %ptrptr, align 8
- ; CHECK: ret void
+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(ptr %ptrptr, i64 2, i1 true) [ "deactivation-symbol"(ptr @ds2) ]
store ptr %ptr, ptr %protptrptr
ret void
}
-; CHECK: define ptr @f3
-define ptr @f3(ptr %ptrptr) {
- ; CHECK: ret ptr %ptrptr
- %protptrptr = call ptr @llvm.protected.field.ptr(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds3) ]
+define ptr @load_sw(ptr %ptrptr) {
+; NOPAUTH-LABEL: define ptr @load_sw(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]]) {
+; NOPAUTH-NEXT: [[PTR:%.*]] = load ptr, ptr [[PTRPTR]], align 8
+; NOPAUTH-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 1
+; NOPAUTH-NEXT: [[TMP3:%.*]] = call i64 @llvm.fshr.i64(i64 [[TMP2]], i64 [[TMP2]], i64 16)
+; NOPAUTH-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; NOPAUTH-NEXT: ret ptr [[TMP4]]
+;
+; PAUTH-LABEL: define ptr @load_sw(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT: [[PTR:%.*]] = load ptr, ptr [[PTRPTR]], align 8
+; PAUTH-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 1
+; PAUTH-NEXT: [[TMP3:%.*]] = call i64 @llvm.fshr.i64(i64 [[TMP2]], i64 [[TMP2]], i64 16)
+; PAUTH-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; PAUTH-NEXT: ret ptr [[TMP4]]
+;
+ %protptrptr = call ptr @llvm.protected.field.ptr(ptr %ptrptr, i64 1, i1 false) [ "deactivation-symbol"(ptr @ds3) ]
+ %ptr = load ptr, ptr %protptrptr
+ ret ptr %ptr
+}
+
+define void @store_sw(ptr %ptrptr, ptr %ptr) {
+; NOPAUTH-LABEL: define void @store_sw(
+; NOPAUTH-SAME: ptr [[PTRPTR:%.*]], ptr [[PTR:%.*]]) {
+; NOPAUTH-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; NOPAUTH-NEXT: [[TMP2:%.*]] = call i64 @llvm.fshl.i64(i64 [[TMP1]], i64 [[TMP1]], i64 16)
+; NOPAUTH-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], 2
+; NOPAUTH-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; NOPAUTH-NEXT: store ptr [[TMP4]], ptr [[PTRPTR]], align 8
+; NOPAUTH-NEXT: ret void
+;
+; PAUTH-LABEL: define void @store_sw(
+; PAUTH-SAME: ptr [[PTRPTR:%.*]], ptr [[PTR:%.*]]) #[[ATTR0]] {
+; PAUTH-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
+; PAUTH-NEXT: [[TMP2:%.*]] = call i64 @llvm.fshl.i64(i64 [[TMP1]], i64 [[TMP1]], i64 16)
+; PAUTH-NEXT: [[TMP3:%.*]] = sub i64 [[TMP2]], 2
+; PAUTH-NEXT: [[TMP4:%.*]] = inttoptr i64 [[TMP3]] to ptr
+; PAUTH-NEXT: store ptr [[TMP4]], ptr [[PTRPTR]], align 8
+; PAUTH-NEXT: ret void
+;
+ %protptrptr = call ptr @llvm.protected.field.ptr(ptr %ptrptr, i64 2, i1 false) [ "deactivation-symbol"(ptr @ds4) ]
+ 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(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds5) ]
+ %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(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds6) ]
ret ptr %protptrptr
}
declare ptr @llvm.protected.field.ptr(ptr, i64, i1 immarg)
+;.
+; NOPAUTH: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) }
+; NOPAUTH: attributes #[[ATTR1:[0-9]+]] = { nounwind memory(none) }
+; NOPAUTH: attributes #[[ATTR2:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn 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) }
+; PAUTH: attributes #[[ATTR4:[0-9]+]] = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
+;.
diff --git a/llvm/test/Transforms/SROA/protected-field-pointer.ll b/llvm/test/Transforms/SROA/protected-field-pointer.ll
index 49a88cb..d4d3432 100644
--- a/llvm/test/Transforms/SROA/protected-field-pointer.ll
+++ b/llvm/test/Transforms/SROA/protected-field-pointer.ll
@@ -1,9 +1,13 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -passes=sroa -S < %s | FileCheck %s
-target triple = "aarch64-unknown-linux-gnu"
-
-; CHECK: define void @slice
define void @slice(ptr %ptr1, ptr %ptr2, ptr %out1, ptr %out2) {
+; CHECK-LABEL: define void @slice(
+; CHECK-SAME: ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], ptr [[OUT1:%.*]], ptr [[OUT2:%.*]]) {
+; CHECK-NEXT: store ptr [[PTR1]], ptr [[OUT1]], align 8
+; CHECK-NEXT: store ptr [[PTR2]], ptr [[OUT2]], align 8
+; CHECK-NEXT: ret void
+;
%alloca = alloca { ptr, ptr }
%protptrptr1.1 = call ptr @llvm.protected.field.ptr(ptr %alloca, i64 1, i1 true)
@@ -13,29 +17,57 @@ define void @slice(ptr %ptr1, ptr %ptr2, ptr %out1, ptr %out2) {
%gep = getelementptr { ptr, ptr }, ptr %alloca, i64 0, i32 1
%protptrptr2.1 = call ptr @llvm.protected.field.ptr(ptr %gep, i64 2, i1 true)
- store ptr %ptr2, ptr %protptrptr1.1
+ store ptr %ptr2, ptr %protptrptr2.1
%protptrptr2.2 = call ptr @llvm.protected.field.ptr(ptr %gep, i64 2, i1 true)
- %ptr2a = load ptr, ptr %protptrptr1.2
+ %ptr2a = load ptr, ptr %protptrptr2.2
- ; CHECK-NEXT: store ptr %ptr1, ptr %out1, align 8
store ptr %ptr1a, ptr %out1
- ; CHECK-NEXT: store ptr %ptr2, ptr %out2, align 8
store ptr %ptr2a, ptr %out2
ret void
}
-; CHECK: define ptr @mixed
define ptr @mixed(ptr %ptr) {
- ; CHECK-NEXT: %alloca = alloca ptr, align 8
+; CHECK-LABEL: define ptr @mixed(
+; CHECK-SAME: ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ALLOCA:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: store ptr [[PTR]], ptr [[ALLOCA]], align 8
+; CHECK-NEXT: [[PROTPTRPTR1_2:%.*]] = call ptr @llvm.protected.field.ptr(ptr [[ALLOCA]], i64 1, i1 true)
+; CHECK-NEXT: [[PTR1A:%.*]] = load ptr, ptr [[PROTPTRPTR1_2]], align 8
+; CHECK-NEXT: ret ptr [[PTR1A]]
+;
%alloca = alloca ptr
- ; CHECK-NEXT: store ptr %ptr, ptr %alloca, align 8
store ptr %ptr, ptr %alloca
- ; CHECK-NEXT: %protptrptr1.2 = call ptr @llvm.protected.field.ptr(ptr %alloca, i64 1, i1 true)
%protptrptr1.2 = call ptr @llvm.protected.field.ptr(ptr %alloca, i64 1, i1 true)
- ; CHECK-NEXT: %ptr1a = load ptr, ptr %protptrptr1.2, align 8
%ptr1a = load ptr, ptr %protptrptr1.2
- ; CHECK-NEXT: ret ptr %ptr
- ret ptr %ptr
+ ret ptr %ptr1a
+}
+
+define void @split_non_promotable(ptr %ptr1, ptr %ptr2, ptr %out1, ptr %out2) {
+; CHECK-LABEL: define void @split_non_promotable(
+; CHECK-SAME: ptr [[PTR1:%.*]], ptr [[PTR2:%.*]], ptr [[OUT1:%.*]], ptr [[OUT2:%.*]]) {
+; CHECK-NEXT: [[ALLOCA_SROA_2:%.*]] = alloca ptr, align 8
+; CHECK-NEXT: store volatile ptr [[PTR2]], ptr [[ALLOCA_SROA_2]], align 8
+; CHECK-NEXT: [[PTR2A:%.*]] = load volatile ptr, ptr [[ALLOCA_SROA_2]], align 8
+; CHECK-NEXT: store ptr [[PTR1]], ptr [[OUT1]], align 8
+; CHECK-NEXT: store ptr [[PTR2A]], ptr [[OUT2]], align 8
+; CHECK-NEXT: ret void
+;
+ %alloca = alloca { ptr, ptr }
+
+ %protptrptr1.1 = call ptr @llvm.protected.field.ptr(ptr %alloca, i64 1, i1 true)
+ store ptr %ptr1, ptr %protptrptr1.1
+ %protptrptr1.2 = call ptr @llvm.protected.field.ptr(ptr %alloca, i64 1, i1 true)
+ %ptr1a = load ptr, ptr %protptrptr1.2
+
+ %gep = getelementptr { ptr, ptr }, ptr %alloca, i64 0, i32 1
+ %protptrptr2.1 = call ptr @llvm.protected.field.ptr(ptr %gep, i64 2, i1 true)
+ store volatile ptr %ptr2, ptr %protptrptr2.1
+ %protptrptr2.2 = call ptr @llvm.protected.field.ptr(ptr %gep, i64 2, i1 true)
+ %ptr2a = load volatile ptr, ptr %protptrptr2.2
+
+ store ptr %ptr1a, ptr %out1
+ store ptr %ptr2a, ptr %out2
+ ret void
}
diff --git a/llvm/test/Transforms/Util/phi-protected-field-ptr.ll b/llvm/test/Transforms/Util/phi-protected-field-ptr.ll
index 2c66712..8481654 100644
--- a/llvm/test/Transforms/Util/phi-protected-field-ptr.ll
+++ b/llvm/test/Transforms/Util/phi-protected-field-ptr.ll
@@ -1,33 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt -O2 -S < %s | FileCheck %s
; Test that no optimization run at -O2 moves the loads into the exit block,
; as this causes unnecessary address escapes with pointer field protection.
-target triple = "aarch64-unknown-linux-gnu"
-
define ptr @phi_prot_ptr(i1 %sel, ptr %p1, ptr %p2) {
+; CHECK-LABEL: define ptr @phi_prot_ptr(
+; CHECK-SAME: i1 [[SEL:%.*]], ptr readonly [[P1:%.*]], ptr readonly [[P2:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: br i1 [[SEL]], label %[[T:.*]], label %[[F:.*]]
+; CHECK: [[T]]:
+; CHECK-NEXT: [[PROTP1:%.*]] = tail call ptr @llvm.protected.field.ptr(ptr [[P1]], i64 1, i1 true)
+; CHECK-NEXT: [[LOAD1:%.*]] = load ptr, ptr [[PROTP1]], align 8
+; CHECK-NEXT: br label %[[EXIT:.*]]
+; CHECK: [[F]]:
+; CHECK-NEXT: [[PROTP2:%.*]] = tail call ptr @llvm.protected.field.ptr(ptr [[P2]], i64 2, i1 true)
+; CHECK-NEXT: [[LOAD2:%.*]] = load ptr, ptr [[PROTP2]], align 8
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[LOAD1]], %[[T]] ], [ [[LOAD2]], %[[F]] ]
+; CHECK-NEXT: ret ptr [[RETVAL]]
+;
br i1 %sel, label %t, label %f
-; CHECK: t:
t:
- ; CHECK-NEXT: call
%protp1 = call ptr @llvm.protected.field.ptr(ptr %p1, i64 1, i1 true)
- ; CHECK-NEXT: load
%load1 = load ptr, ptr %protp1
br label %exit
-; CHECK: f:
f:
- ; CHECK-NEXT: call
%protp2 = call ptr @llvm.protected.field.ptr(ptr %p2, i64 2, i1 true)
- ; CHECK-NEXT: load
%load2 = load ptr, ptr %protp2
br label %exit
-; CHECK: exit:
exit:
- ; CHECK-NEXT: phi
%retval = phi ptr [ %load1, %t ], [ %load2, %f ]
- ; CHECK-NEXT: ret
ret ptr %retval
}
diff --git a/llvm/test/Verifier/ptrauth-constant.ll b/llvm/test/Verifier/ptrauth-constant.ll
new file mode 100644
index 0000000..fdd6352
--- /dev/null
+++ b/llvm/test/Verifier/ptrauth-constant.ll
@@ -0,0 +1,6 @@
+; RUN: not opt -passes=verify < %s 2>&1 | FileCheck %s
+
+@g = external global i8
+
+; CHECK: signed ptrauth constant deactivation symbol must be a global variable or null
+@ptr = global ptr ptrauth (ptr @g, i32 0, i64 65535, ptr null, ptr inttoptr (i64 16 to ptr))