Move {load,store}(llvm.protected.field.ptr) lowering to InstCombine.
The previous position of llvm.protected.field.ptr lowering for loads and stores was problematic as it not only inhibited optimizations such as DSE (as stores to a llvm.protected.field.ptr were not considered to must-alias stores to the non-protected.field pointer) but also required changes to other optimization passes to avoid transformations that would reduce PFP coverage. Address this by moving the load/store part of the lowering to InstCombine, where it will run earlier than the PFP-breaking and AA-relying transformations. The deactivation symbol, null comparison and EmuPAC parts of the lowering remain in PreISelLowering. Now that the transformation inhibitions are no longer needed, remove them (i.e. partially revert #151649, and revert #182976). This change resulted in a 2.4% reduction in Fleetbench .text size and the following improvements to PFP performance overhead for BM_PROTO_Arena on various microarchitectures: before after Apple M2 Ultra 3.5% 3.3% Google Axion C4A 3.3% 2.9% Google Axion N4A 2.7% 2.2% Reviewers: fmayer, nikic, vitalybuka Reviewed By: fmayer Pull Request: https://github.com/llvm/llvm-project/pull/186548
This commit is contained in:
parent
eb35aa90f6
commit
75bb30ddbf
@ -482,6 +482,52 @@ bool PreISelIntrinsicLowering::expandMemIntrinsicUses(
|
||||
return Changed;
|
||||
}
|
||||
|
||||
static GlobalValue *getDeactivationSymbol(CallInst *Call) {
|
||||
if (auto Bundle = Call->getOperandBundle(LLVMContext::OB_deactivation_symbol))
|
||||
return cast<GlobalValue>(Bundle->Inputs[0]);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static bool expandPtrauthForEmuPAC(Function &Intr) {
|
||||
Module &M = *Intr.getParent();
|
||||
if (Triple(M.getTargetTriple()).isArm64e())
|
||||
return false;
|
||||
|
||||
Type *Int64Ty = Type::getInt64Ty(M.getContext());
|
||||
|
||||
assert(Intr.getIntrinsicID() == Intrinsic::ptrauth_sign ||
|
||||
Intr.getIntrinsicID() == Intrinsic::ptrauth_auth);
|
||||
auto *EmuFnTy = FunctionType::get(Int64Ty, {Int64Ty, Int64Ty}, false);
|
||||
FunctionCallee EmuIntr = M.getOrInsertFunction(
|
||||
Intr.getIntrinsicID() == Intrinsic::ptrauth_auth ? "__emupac_autda"
|
||||
: "__emupac_pacda",
|
||||
EmuFnTy);
|
||||
|
||||
for (User *U : llvm::make_early_inc_range(Intr.users())) {
|
||||
auto *Call = cast<CallInst>(U);
|
||||
// We only support the DA key for now.
|
||||
if (auto *Key = dyn_cast<ConstantInt>(Call->getArgOperand(1));
|
||||
!Key || Key->getZExtValue() != /*AArch64PACKey::DA*/ 2)
|
||||
continue;
|
||||
|
||||
Function *F = Call->getParent()->getParent();
|
||||
Attribute FSAttr = F->getFnAttribute("target-features");
|
||||
if (FSAttr.isValid() && FSAttr.getValueAsString().contains("+pauth"))
|
||||
continue;
|
||||
|
||||
std::vector<OperandBundleDef> DSBundle;
|
||||
if (auto *DS = getDeactivationSymbol(Call))
|
||||
DSBundle.push_back(OperandBundleDef("deactivation-symbol", DS));
|
||||
|
||||
IRBuilder<> B(Call);
|
||||
auto *EmuCall = B.CreateCall(
|
||||
EmuIntr, {Call->getArgOperand(0), Call->getArgOperand(2)}, DSBundle);
|
||||
Call->replaceAllUsesWith(EmuCall);
|
||||
Call->eraseFromParent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool expandProtectedFieldPtr(Function &Intr) {
|
||||
Module &M = *Intr.getParent();
|
||||
|
||||
@ -491,89 +537,19 @@ static bool expandProtectedFieldPtr(Function &Intr) {
|
||||
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);
|
||||
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.
|
||||
@ -592,8 +568,12 @@ static bool expandProtectedFieldPtr(Function &Intr) {
|
||||
}
|
||||
}
|
||||
|
||||
// We couldn't rewrite away this use of the intrinsic. Replace it with the
|
||||
// pointer operand, and arrange to define a deactivation symbol.
|
||||
// If we are here, this means that we couldn't rewrite away this use of
|
||||
// the intrinsic. Any load or store uses were removed by InstCombine, and
|
||||
// in general, we can't rewrite away non-load/store uses of
|
||||
// llvm.protected.field.ptr because doing so could expose the encoded
|
||||
// pointer value to the program. Replace it with the pointer operand, and
|
||||
// arrange to define a deactivation symbol.
|
||||
U.set(Pointer);
|
||||
if (DS)
|
||||
DSsToDeactivate.insert(DS);
|
||||
@ -817,6 +797,10 @@ bool PreISelIntrinsicLowering::lowerIntrinsics(Module &M) const {
|
||||
return lowerUnaryVectorIntrinsicAsLoop(M, CI);
|
||||
});
|
||||
break;
|
||||
case Intrinsic::ptrauth_sign:
|
||||
case Intrinsic::ptrauth_auth:
|
||||
Changed |= expandPtrauthForEmuPAC(F);
|
||||
break;
|
||||
case Intrinsic::protected_field_ptr:
|
||||
Changed |= expandProtectedFieldPtr(F);
|
||||
break;
|
||||
|
||||
@ -3294,25 +3294,25 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
|
||||
}
|
||||
case Intrinsic::ptrauth_auth:
|
||||
case Intrinsic::ptrauth_resign: {
|
||||
// We don't support this optimization on intrinsic calls with deactivation
|
||||
// symbols, which are represented using operand bundles.
|
||||
if (II->hasOperandBundles())
|
||||
break;
|
||||
|
||||
// (sign|resign) + (auth|resign) can be folded by omitting the middle
|
||||
// sign+auth component if the key and discriminator match.
|
||||
bool NeedSign = II->getIntrinsicID() == Intrinsic::ptrauth_resign;
|
||||
Value *Ptr = II->getArgOperand(0);
|
||||
Value *Key = II->getArgOperand(1);
|
||||
Value *Disc = II->getArgOperand(2);
|
||||
Value *DS = nullptr;
|
||||
if (auto Bundle = II->getOperandBundle(LLVMContext::OB_deactivation_symbol))
|
||||
DS = Bundle->Inputs[0];
|
||||
|
||||
// AuthKey will be the key we need to end up authenticating against in
|
||||
// whatever we replace this sequence with.
|
||||
Value *AuthKey = nullptr, *AuthDisc = nullptr, *BasePtr;
|
||||
if (const auto *CI = dyn_cast<CallBase>(Ptr)) {
|
||||
// We don't support this optimization on intrinsic calls with deactivation
|
||||
// symbols, which are represented using operand bundles.
|
||||
if (CI->hasOperandBundles())
|
||||
Value *OtherDS = nullptr;
|
||||
if (auto Bundle =
|
||||
CI->getOperandBundle(LLVMContext::OB_deactivation_symbol))
|
||||
OtherDS = Bundle->Inputs[0];
|
||||
if (DS != OtherDS)
|
||||
break;
|
||||
|
||||
BasePtr = CI->getArgOperand(0);
|
||||
@ -3320,6 +3320,8 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
|
||||
if (CI->getArgOperand(1) != Key || CI->getArgOperand(2) != Disc)
|
||||
break;
|
||||
} else if (CI->getIntrinsicID() == Intrinsic::ptrauth_resign) {
|
||||
// The resign intrinsic does not support deactivation symbols.
|
||||
assert(!DS);
|
||||
if (CI->getArgOperand(3) != Key || CI->getArgOperand(4) != Disc)
|
||||
break;
|
||||
AuthKey = CI->getArgOperand(1);
|
||||
@ -3330,7 +3332,7 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
|
||||
// ptrauth constants are equivalent to a call to @llvm.ptrauth.sign for
|
||||
// our purposes, so check for that too.
|
||||
const auto *CPA = dyn_cast<ConstantPtrAuth>(PtrToInt->getOperand(0));
|
||||
if (!CPA || !CPA->isKnownCompatibleWith(Key, Disc, DL))
|
||||
if (!CPA || DS || !CPA->isKnownCompatibleWith(Key, Disc, DL))
|
||||
break;
|
||||
|
||||
// resign(ptrauth(p,ks,ds),ks,ds,kr,dr) -> ptrauth(p,kr,dr)
|
||||
@ -3379,9 +3381,13 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
|
||||
CallArgs.push_back(II->getArgOperand(4));
|
||||
}
|
||||
|
||||
std::vector<OperandBundleDef> Bundles;
|
||||
if (DS)
|
||||
Bundles.push_back(OperandBundleDef("deactivation-symbol", DS));
|
||||
|
||||
Function *NewFn =
|
||||
Intrinsic::getOrInsertDeclaration(II->getModule(), NewIntrin);
|
||||
return CallInst::Create(NewFn, CallArgs);
|
||||
return CallInst::Create(NewFn, CallArgs, Bundles);
|
||||
}
|
||||
case Intrinsic::arm_neon_vtbl1:
|
||||
case Intrinsic::arm_neon_vtbl2:
|
||||
|
||||
@ -1184,6 +1184,37 @@ Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) {
|
||||
if (Value *V = simplifyNonNullOperand(Op, /*HasDereferenceable=*/true))
|
||||
return replaceOperand(LI, 0, V);
|
||||
|
||||
// load(llvm.protected.field.ptr(ptr)) -> llvm.ptrauth.auth(load(ptr))
|
||||
if (isa<PointerType>(LI.getType())) {
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(Op)) {
|
||||
if (II->getIntrinsicID() == Intrinsic::protected_field_ptr) {
|
||||
std::vector<OperandBundleDef> DSBundle;
|
||||
if (auto Bundle =
|
||||
II->getOperandBundle(LLVMContext::OB_deactivation_symbol))
|
||||
DSBundle.push_back(OperandBundleDef(
|
||||
"deactivation-symbol", cast<GlobalValue>(Bundle->Inputs[0])));
|
||||
|
||||
IRBuilderBase::InsertPointGuard Guard(Builder);
|
||||
Builder.SetInsertPoint(&LI);
|
||||
|
||||
auto *NewLI = cast<LoadInst>(LI.clone());
|
||||
NewLI->setOperand(0, II->getOperand(0));
|
||||
Builder.Insert(NewLI);
|
||||
|
||||
Function *AuthIntr = Intrinsic::getOrInsertDeclaration(
|
||||
F.getParent(), Intrinsic::ptrauth_auth, {});
|
||||
auto *LIInt = Builder.CreatePtrToInt(NewLI, Builder.getInt64Ty());
|
||||
Value *Auth = Builder.CreateCall(
|
||||
AuthIntr,
|
||||
{LIInt, Builder.getInt32(/*AArch64PACKey::DA*/ 2),
|
||||
II->getOperand(1)},
|
||||
DSBundle);
|
||||
Auth = Builder.CreateIntToPtr(Auth, Builder.getPtrTy());
|
||||
return replaceInstUsesWith(LI, Auth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -1551,6 +1582,37 @@ Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) {
|
||||
if (Value *V = simplifyNonNullOperand(Ptr, /*HasDereferenceable=*/true))
|
||||
return replaceOperand(SI, 1, V);
|
||||
|
||||
// store(ptr1, llvm.protected.field.ptr(ptr2)) ->
|
||||
// store(llvm.ptrauth.sign(ptr1), ptr2)
|
||||
if (isa<PointerType>(Val->getType())) {
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(Ptr)) {
|
||||
if (II->getIntrinsicID() == Intrinsic::protected_field_ptr) {
|
||||
std::vector<OperandBundleDef> DSBundle;
|
||||
if (auto Bundle =
|
||||
II->getOperandBundle(LLVMContext::OB_deactivation_symbol))
|
||||
DSBundle.push_back(OperandBundleDef(
|
||||
"deactivation-symbol", cast<GlobalValue>(Bundle->Inputs[0])));
|
||||
|
||||
IRBuilderBase::InsertPointGuard Guard(Builder);
|
||||
Builder.SetInsertPoint(&SI);
|
||||
|
||||
Function *SignIntr = Intrinsic::getOrInsertDeclaration(
|
||||
F.getParent(), Intrinsic::ptrauth_sign, {});
|
||||
auto *ValInt = Builder.CreatePtrToInt(Val, Builder.getInt64Ty());
|
||||
Value *Sign = Builder.CreateCall(
|
||||
SignIntr,
|
||||
{ValInt, Builder.getInt32(/*AArch64PACKey::DA*/ 2),
|
||||
II->getOperand(1)},
|
||||
DSBundle);
|
||||
Sign = Builder.CreateIntToPtr(Sign, Builder.getPtrTy());
|
||||
|
||||
replaceOperand(SI, 0, Sign);
|
||||
replaceOperand(SI, 1, II->getOperand(0));
|
||||
return &SI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
@ -2969,12 +2969,6 @@ bool GVNPass::performScalarPRE(Instruction *CurInst) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Protected pointer field loads/stores should be paired with the intrinsic
|
||||
// to avoid unnecessary address escapes.
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(CurInst))
|
||||
if (II->getIntrinsicID() == Intrinsic::protected_field_ptr)
|
||||
return false;
|
||||
|
||||
uint32_t ValNo = VN.lookup(CurInst);
|
||||
|
||||
// Look for the predecessors for PRE opportunities. We're
|
||||
|
||||
@ -3908,12 +3908,6 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) {
|
||||
if (Op->isSwiftError())
|
||||
return false;
|
||||
|
||||
// Protected pointer field loads/stores should be paired with the intrinsic
|
||||
// to avoid unnecessary address escapes.
|
||||
if (auto *II = dyn_cast<IntrinsicInst>(Op))
|
||||
if (II->getIntrinsicID() == Intrinsic::protected_field_ptr)
|
||||
return false;
|
||||
|
||||
// Cannot replace alloca argument with phi/select.
|
||||
if (I->isLifetimeStartOrEnd())
|
||||
return false;
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
||||
; RUN: opt -passes=gvn -S < %s | FileCheck %s
|
||||
|
||||
; Check that PRE is inhibited for llvm.protected.field.ptr.
|
||||
declare void @use(ptr)
|
||||
|
||||
define void @test1(i1 %c, ptr %arg) {
|
||||
; CHECK-LABEL: @test1(
|
||||
; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[DOTBB2_CRIT_EDGE:%.*]]
|
||||
; CHECK: bb1:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call ptr @llvm.protected.field.ptr.p0(ptr [[ARG:%.*]], i64 1, i1 true)
|
||||
; CHECK-NEXT: br label [[BB3:%.*]]
|
||||
; CHECK: bb2:
|
||||
; CHECK-NEXT: [[CALL2:%.*]] = call ptr @llvm.protected.field.ptr.p0(ptr [[ARG]], i64 1, i1 true)
|
||||
; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[CALL2]], align 8
|
||||
; CHECK-NEXT: call void @use(ptr [[V]])
|
||||
; CHECK-NEXT: br label [[BB3]]
|
||||
; CHECK: bb3:
|
||||
; CHECK-NEXT: [[CALL3:%.*]] = call ptr @llvm.protected.field.ptr.p0(ptr [[ARG]], i64 1, i1 true)
|
||||
; CHECK-NEXT: [[V2:%.*]] = load ptr, ptr [[CALL3]], align 8
|
||||
; CHECK-NEXT: call void @use(ptr [[V2]])
|
||||
; CHECK-NEXT: br label [[DOTBB2_CRIT_EDGE]]
|
||||
;
|
||||
br i1 %c, label %bb1, label %bb2
|
||||
|
||||
bb1:
|
||||
%call = call ptr @llvm.protected.field.ptr.p0(ptr %arg, i64 1, i1 true)
|
||||
br label %bb3
|
||||
|
||||
bb2:
|
||||
%call2 = call ptr @llvm.protected.field.ptr.p0(ptr %arg, i64 1, i1 true)
|
||||
%v = load ptr, ptr %call2
|
||||
call void @use(ptr %v)
|
||||
br label %bb3
|
||||
|
||||
bb3:
|
||||
%call3 = call ptr @llvm.protected.field.ptr.p0(ptr %arg, i64 1, i1 true)
|
||||
%v2 = load ptr, ptr %call3
|
||||
call void @use(ptr %v2)
|
||||
br label %bb2
|
||||
}
|
||||
61
llvm/test/Transforms/InstCombine/protected-field-ptr.ll
Normal file
61
llvm/test/Transforms/InstCombine/protected-field-ptr.ll
Normal file
@ -0,0 +1,61 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
|
||||
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
|
||||
|
||||
@ds1 = external global i8
|
||||
@ds2 = external global i8
|
||||
|
||||
define ptr @load_hw(ptr addrspace(1) %ptrptr) {
|
||||
; CHECK-LABEL: define ptr @load_hw(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) {
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr addrspace(1) [[PTRPTR]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TMP2]], i32 2, i64 1)
|
||||
; CHECK-NEXT: [[PTR:%.*]] = inttoptr i64 [[TMP3]] to ptr
|
||||
; CHECK-NEXT: ret ptr [[PTR]]
|
||||
;
|
||||
%protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 1, i1 true)
|
||||
%ptr = load ptr, ptr addrspace(1) %protptrptr
|
||||
ret ptr %ptr
|
||||
}
|
||||
|
||||
define void @store_hw(ptr addrspace(1) %ptrptr, ptr %ptr) {
|
||||
; CHECK-LABEL: define void @store_hw(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]], ptr [[PTR:%.*]]) {
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[TMP1]], i32 2, i64 2)
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
|
||||
; CHECK-NEXT: store ptr [[TMP3]], ptr addrspace(1) [[PTRPTR]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 2, i1 true)
|
||||
store ptr %ptr, ptr addrspace(1) %protptrptr
|
||||
ret void
|
||||
}
|
||||
|
||||
define ptr @load_hw_ds(ptr addrspace(1) %ptrptr) {
|
||||
; CHECK-LABEL: define ptr @load_hw_ds(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) {
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr addrspace(1) [[PTRPTR]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[TMP2]], i32 2, i64 1) [ "deactivation-symbol"(ptr @ds1) ]
|
||||
; CHECK-NEXT: [[PTR:%.*]] = inttoptr i64 [[TMP3]] to ptr
|
||||
; CHECK-NEXT: ret ptr [[PTR]]
|
||||
;
|
||||
%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_ds(ptr addrspace(1) %ptrptr, ptr %ptr) {
|
||||
; CHECK-LABEL: define void @store_hw_ds(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]], ptr [[PTR:%.*]]) {
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR]] to i64
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[TMP1]], i32 2, i64 2) [ "deactivation-symbol"(ptr @ds2) ]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
|
||||
; CHECK-NEXT: store ptr [[TMP3]], ptr addrspace(1) [[PTRPTR]], align 8
|
||||
; CHECK-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
|
||||
}
|
||||
@ -161,6 +161,7 @@ define i64 @test_ptrauth_resign_ptrauth_constant(ptr %p) {
|
||||
}
|
||||
|
||||
@ds = external global i8
|
||||
@ds2 = external global i8
|
||||
|
||||
define i64 @test_ptrauth_nop_ds1(ptr %p) {
|
||||
; CHECK-LABEL: @test_ptrauth_nop_ds1(
|
||||
@ -188,6 +189,30 @@ define i64 @test_ptrauth_nop_ds2(ptr %p) {
|
||||
ret i64 %authed
|
||||
}
|
||||
|
||||
define i64 @test_ptrauth_nop_ds3(ptr %p) {
|
||||
; CHECK-LABEL: @test_ptrauth_nop_ds3(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
|
||||
; CHECK-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.sign(i64 [[TMP0]], i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; CHECK-NEXT: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED]], i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds2) ]
|
||||
; CHECK-NEXT: ret i64 [[AUTHED]]
|
||||
;
|
||||
%tmp0 = ptrtoint ptr %p to i64
|
||||
%signed = call i64 @llvm.ptrauth.sign(i64 %tmp0, i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds) ]
|
||||
%authed = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds2) ]
|
||||
ret i64 %authed
|
||||
}
|
||||
|
||||
define i64 @test_ptrauth_nop_ds4(ptr %p) {
|
||||
; CHECK-LABEL: @test_ptrauth_nop_ds4(
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
|
||||
; CHECK-NEXT: ret i64 [[TMP0]]
|
||||
;
|
||||
%tmp0 = ptrtoint ptr %p to i64
|
||||
%signed = call i64 @llvm.ptrauth.sign(i64 %tmp0, i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds) ]
|
||||
%authed = call i64 @llvm.ptrauth.auth(i64 %signed, i32 1, i64 1234) [ "deactivation-symbol"(ptr @ds) ]
|
||||
ret i64 %authed
|
||||
}
|
||||
|
||||
define i64 @test_ptrauth_nop_ds_constant() {
|
||||
; CHECK-LABEL: @test_ptrauth_nop_ds_constant(
|
||||
; CHECK-NEXT: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 ptrtoint (ptr ptrauth (ptr @foo, i32 1, i64 1234, ptr null, ptr @ds) to i64), i32 1, i64 1234)
|
||||
|
||||
@ -1,23 +1,27 @@
|
||||
; 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.
|
||||
; Test that no optimization run at -O2 before InstCombine moves the loads into
|
||||
; the exit block, as this causes unnecessary address escapes with pointer field
|
||||
; protection.
|
||||
|
||||
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-SAME: i1 [[SEL:%.*]], ptr readonly captures(none) [[P1:%.*]], ptr readonly captures(none) [[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.p0(ptr [[P1]], i64 1, i1 true)
|
||||
; CHECK-NEXT: [[LOAD1:%.*]] = load ptr, ptr [[PROTP1]], align 8
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[P1]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.ptrauth.auth(i64 [[TMP2]], i32 2, i64 1)
|
||||
; CHECK-NEXT: br label %[[EXIT:.*]]
|
||||
; CHECK: [[F]]:
|
||||
; CHECK-NEXT: [[PROTP2:%.*]] = tail call ptr @llvm.protected.field.ptr.p0(ptr [[P2]], i64 2, i1 true)
|
||||
; CHECK-NEXT: [[LOAD2:%.*]] = load ptr, ptr [[PROTP2]], align 8
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[P2]], align 8
|
||||
; CHECK-NEXT: [[TMP5:%.*]] = ptrtoint ptr [[TMP4]] to i64
|
||||
; CHECK-NEXT: [[TMP6:%.*]] = tail call i64 @llvm.ptrauth.auth(i64 [[TMP5]], i32 2, i64 2)
|
||||
; CHECK-NEXT: br label %[[EXIT]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = phi ptr [ [[LOAD1]], %[[T]] ], [ [[LOAD2]], %[[F]] ]
|
||||
; CHECK-NEXT: [[RETVAL_IN:%.*]] = phi i64 [ [[TMP3]], %[[T]] ], [ [[TMP6]], %[[F]] ]
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = inttoptr i64 [[RETVAL_IN]] to ptr
|
||||
; CHECK-NEXT: ret ptr [[RETVAL]]
|
||||
;
|
||||
br i1 %sel, label %t, label %f
|
||||
|
||||
64
llvm/test/Transforms/PreISelIntrinsicLowering/emupac.ll
Normal file
64
llvm/test/Transforms/PreISelIntrinsicLowering/emupac.ll
Normal file
@ -0,0 +1,64 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
|
||||
; RUN: opt -passes=pre-isel-intrinsic-lowering -mtriple aarch64-unknown-linux -S < %s | FileCheck --check-prefix=NOPAUTH %s
|
||||
; RUN: opt -passes=pre-isel-intrinsic-lowering -mtriple aarch64-unknown-linux -mattr=+pauth -S < %s | FileCheck --check-prefix=PAUTH1 %s
|
||||
; RUN: opt -passes=pre-isel-intrinsic-lowering -mtriple arm64e-apple-darwin -S < %s | FileCheck --check-prefix=PAUTH2 %s
|
||||
|
||||
@ds = external global i8
|
||||
|
||||
define i64 @sign1(i64 %p) {
|
||||
; NOPAUTH-LABEL: define i64 @sign1(
|
||||
; NOPAUTH-SAME: i64 [[P:%.*]]) {
|
||||
; NOPAUTH-NEXT: [[TMP1:%.*]] = call i64 @__emupac_autda(i64 [[P]], i64 1)
|
||||
; NOPAUTH-NEXT: ret i64 [[TMP1]]
|
||||
;
|
||||
; PAUTH1-LABEL: define i64 @sign1(
|
||||
; PAUTH1-SAME: i64 [[P:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; PAUTH1-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 2, i64 1)
|
||||
; PAUTH1-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
; PAUTH2-LABEL: define i64 @sign1(
|
||||
; PAUTH2-SAME: i64 [[P:%.*]]) {
|
||||
; PAUTH2-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 2, i64 1)
|
||||
; PAUTH2-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
%signed = call i64 @llvm.ptrauth.auth(i64 %p, i32 2, i64 1)
|
||||
ret i64 %signed
|
||||
}
|
||||
define i64 @sign2(i64 %p) {
|
||||
; NOPAUTH-LABEL: define i64 @sign2(
|
||||
; NOPAUTH-SAME: i64 [[P:%.*]]) {
|
||||
; NOPAUTH-NEXT: [[TMP1:%.*]] = call i64 @__emupac_autda(i64 [[P]], i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; NOPAUTH-NEXT: ret i64 [[TMP1]]
|
||||
;
|
||||
; PAUTH1-LABEL: define i64 @sign2(
|
||||
; PAUTH1-SAME: i64 [[P:%.*]]) #[[ATTR0]] {
|
||||
; PAUTH1-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 2, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; PAUTH1-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
; PAUTH2-LABEL: define i64 @sign2(
|
||||
; PAUTH2-SAME: i64 [[P:%.*]]) {
|
||||
; PAUTH2-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 2, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; PAUTH2-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
%signed = call i64 @llvm.ptrauth.auth(i64 %p, i32 2, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
ret i64 %signed
|
||||
}
|
||||
define i64 @sign3(i64 %p) {
|
||||
; NOPAUTH-LABEL: define i64 @sign3(
|
||||
; NOPAUTH-SAME: i64 [[P:%.*]]) {
|
||||
; NOPAUTH-NEXT: [[TMP1:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 0, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; NOPAUTH-NEXT: ret i64 [[TMP1]]
|
||||
;
|
||||
; PAUTH1-LABEL: define i64 @sign3(
|
||||
; PAUTH1-SAME: i64 [[P:%.*]]) #[[ATTR0]] {
|
||||
; PAUTH1-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 0, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; PAUTH1-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
; PAUTH2-LABEL: define i64 @sign3(
|
||||
; PAUTH2-SAME: i64 [[P:%.*]]) {
|
||||
; PAUTH2-NEXT: [[SIGNED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[P]], i32 0, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
; PAUTH2-NEXT: ret i64 [[SIGNED]]
|
||||
;
|
||||
%signed = call i64 @llvm.ptrauth.auth(i64 %p, i32 0, i64 1) [ "deactivation-symbol"(ptr @ds) ]
|
||||
ret i64 %signed
|
||||
}
|
||||
@ -1,85 +1,25 @@
|
||||
; 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
|
||||
; RUN: opt -passes=pre-isel-intrinsic-lowering -mattr=+pauth -S < %s | FileCheck %s
|
||||
|
||||
target triple = "aarch64-unknown-linux-gnu"
|
||||
|
||||
@ds1 = external global i8
|
||||
@ds2 = external global i8
|
||||
@ds3 = external global i8
|
||||
@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)
|
||||
; CHECK: @ds1 = external global i8
|
||||
; CHECK: @ds2 = 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]]
|
||||
; CHECK-LABEL: define i1 @compare(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr addrspace(1) [[PTRPTR]], null
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr addrspace(1) null, [[PTRPTR]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
|
||||
; CHECK-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) ]
|
||||
%protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds1) ]
|
||||
%cmp1 = icmp eq ptr addrspace(1) %protptrptr, null
|
||||
%cmp2 = icmp eq ptr addrspace(1) null, %protptrptr
|
||||
%cmp = or i1 %cmp1, %cmp2
|
||||
@ -87,25 +27,16 @@ define i1 @compare(ptr addrspace(1) %ptrptr) {
|
||||
}
|
||||
|
||||
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]]
|
||||
; CHECK-LABEL: define ptr addrspace(1) @escape(
|
||||
; CHECK-SAME: ptr addrspace(1) [[PTRPTR:%.*]]) #[[ATTR0]] {
|
||||
; CHECK-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) ]
|
||||
%protptrptr = call ptr addrspace(1) @llvm.protected.field.ptr.p1(ptr addrspace(1) %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds2) ]
|
||||
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) }
|
||||
; CHECK: attributes #[[ATTR0]] = { "target-features"="+pauth" }
|
||||
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) "target-features"="+pauth" }
|
||||
;.
|
||||
|
||||
@ -1,85 +1,25 @@
|
||||
; 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
|
||||
; RUN: opt -passes=pre-isel-intrinsic-lowering -mattr=+pauth -S < %s | FileCheck %s
|
||||
|
||||
target triple = "aarch64-unknown-linux-gnu"
|
||||
|
||||
@ds1 = external global i8
|
||||
@ds2 = external global i8
|
||||
@ds3 = external global i8
|
||||
@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)
|
||||
; CHECK: @ds1 = external global i8
|
||||
; CHECK: @ds2 = 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]]
|
||||
; CHECK-LABEL: define i1 @compare(
|
||||
; CHECK-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0:[0-9]+]] {
|
||||
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq ptr [[PTRPTR]], null
|
||||
; CHECK-NEXT: [[CMP2:%.*]] = icmp eq ptr null, [[PTRPTR]]
|
||||
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP1]], [[CMP2]]
|
||||
; CHECK-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) ]
|
||||
%protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds1) ]
|
||||
%cmp1 = icmp eq ptr %protptrptr, null
|
||||
%cmp2 = icmp eq ptr null, %protptrptr
|
||||
%cmp = or i1 %cmp1, %cmp2
|
||||
@ -87,25 +27,16 @@ define i1 @compare(ptr %ptrptr) {
|
||||
}
|
||||
|
||||
define ptr @escape(ptr %ptrptr) {
|
||||
; NOPAUTH-LABEL: define ptr @escape(
|
||||
; NOPAUTH-SAME: ptr [[PTRPTR:%.*]]) {
|
||||
; NOPAUTH-NEXT: ret ptr [[PTRPTR]]
|
||||
; CHECK-LABEL: define ptr @escape(
|
||||
; CHECK-SAME: ptr [[PTRPTR:%.*]]) #[[ATTR0]] {
|
||||
; CHECK-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) ]
|
||||
%protptrptr = call ptr @llvm.protected.field.ptr.p0(ptr %ptrptr, i64 3, i1 true) [ "deactivation-symbol"(ptr @ds2) ]
|
||||
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) }
|
||||
; CHECK: attributes #[[ATTR0]] = { "target-features"="+pauth" }
|
||||
; CHECK: attributes #[[ATTR1:[0-9]+]] = { nocallback nofree nosync nounwind willreturn memory(none) "target-features"="+pauth" }
|
||||
;.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user