Skip to content

Commit f4b659c

Browse files
committed
Merge commit '77bcab835aca' from llvm.org/main into next
Conflicts: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp llvm/test/Transforms/InstCombine/ptrauth-intrinsics-call.ll rdar://156051408
2 parents 3a9e45f + 77bcab8 commit f4b659c

File tree

3 files changed

+171
-73
lines changed

3 files changed

+171
-73
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4050,34 +4050,45 @@ static IntrinsicInst *findInitTrampoline(Value *Callee) {
40504050
return nullptr;
40514051
}
40524052

4053-
Instruction *InstCombinerImpl::tryCombinePtrAuthCall(CallBase &Call) {
4054-
Value *Callee = Call.getCalledOperand();
4055-
auto *IPC = dyn_cast<IntToPtrInst>(Callee);
4053+
Instruction *InstCombinerImpl::foldPtrAuthIntrinsicCallee(CallBase &Call) {
4054+
const Value *Callee = Call.getCalledOperand();
4055+
const auto *IPC = dyn_cast<IntToPtrInst>(Callee);
40564056
if (!IPC || !IPC->isNoopCast(DL))
40574057
return nullptr;
40584058

4059-
IntrinsicInst *II = dyn_cast<IntrinsicInst>(IPC->getOperand(0));
4059+
const auto *II = dyn_cast<IntrinsicInst>(IPC->getOperand(0));
40604060
if (!II)
40614061
return nullptr;
40624062

4063-
auto PtrAuthBundleOrNone = Call.getOperandBundle(LLVMContext::OB_ptrauth);
4064-
assert(Call.getNumOperandBundles() <= 1 &&
4065-
"unimplemented support for ptrauth and other bundle");
4066-
4067-
Value *NewCallee = nullptr;
4068-
SmallVector<OperandBundleDef, 1> NewBundles;
4069-
switch (II->getIntrinsicID()) {
4070-
default:
4063+
Intrinsic::ID IIID = II->getIntrinsicID();
4064+
if (IIID != Intrinsic::ptrauth_resign && IIID != Intrinsic::ptrauth_sign &&
4065+
IIID != Intrinsic::ptrauth_auth)
40714066
return nullptr;
40724067

4073-
// call(ptrauth_resign(p)), ["ptrauth"()] -> call p, ["ptrauth"()]
4068+
// Isolate the ptrauth bundle from the others.
4069+
std::optional<OperandBundleUse> PtrAuthBundleOrNone;
4070+
SmallVector<OperandBundleDef, 2> NewBundles;
4071+
for (unsigned BI = 0, BE = Call.getNumOperandBundles(); BI != BE; ++BI) {
4072+
OperandBundleUse Bundle = Call.getOperandBundleAt(BI);
4073+
if (Bundle.getTagID() == LLVMContext::OB_ptrauth)
4074+
PtrAuthBundleOrNone = Bundle;
4075+
else
4076+
NewBundles.emplace_back(Bundle);
4077+
}
4078+
4079+
Value *NewCallee = nullptr;
4080+
switch (IIID) {
4081+
// call(ptrauth.resign(p)), ["ptrauth"()] -> call p, ["ptrauth"()]
40744082
// assuming the call bundle and the sign operands match.
40754083
case Intrinsic::ptrauth_resign: {
40764084
if (!PtrAuthBundleOrNone)
40774085
return nullptr;
4078-
auto PtrAuthBundle = *PtrAuthBundleOrNone;
4079-
if (II->getOperand(3) != PtrAuthBundle.Inputs[0] ||
4080-
II->getOperand(4) != PtrAuthBundle.Inputs[1])
4086+
4087+
// Resign result key should match bundle.
4088+
if (II->getOperand(3) != PtrAuthBundleOrNone->Inputs[0])
4089+
return nullptr;
4090+
// Resign result discriminator should match bundle.
4091+
if (II->getOperand(4) != PtrAuthBundleOrNone->Inputs[1])
40814092
return nullptr;
40824093

40834094
Value *NewBundleOps[] = {II->getOperand(1), II->getOperand(2)};
@@ -4086,14 +4097,18 @@ Instruction *InstCombinerImpl::tryCombinePtrAuthCall(CallBase &Call) {
40864097
break;
40874098
}
40884099

4089-
// call(ptrauth_sign(p)), ["ptrauth"()] -> call p
4100+
// call(ptrauth.sign(p)), ["ptrauth"()] -> call p
40904101
// assuming the call bundle and the sign operands match.
4102+
// Non-ptrauth indirect calls are undesirable, but so is ptrauth.sign.
40914103
case Intrinsic::ptrauth_sign: {
40924104
if (!PtrAuthBundleOrNone)
40934105
return nullptr;
4094-
auto PtrAuthBundle = *PtrAuthBundleOrNone;
4095-
if (II->getOperand(1) != PtrAuthBundle.Inputs[0] ||
4096-
II->getOperand(2) != PtrAuthBundle.Inputs[1])
4106+
4107+
// Sign key should match bundle.
4108+
if (II->getOperand(1) != PtrAuthBundleOrNone->Inputs[0])
4109+
return nullptr;
4110+
// Sign discriminator should match bundle.
4111+
if (II->getOperand(2) != PtrAuthBundleOrNone->Inputs[1])
40974112
return nullptr;
40984113
NewCallee = II->getOperand(0);
40994114
break;
@@ -4103,24 +4118,21 @@ Instruction *InstCombinerImpl::tryCombinePtrAuthCall(CallBase &Call) {
41034118
case Intrinsic::ptrauth_auth: {
41044119
if (PtrAuthBundleOrNone)
41054120
return nullptr;
4121+
41064122
Value *NewBundleOps[] = {II->getOperand(1), II->getOperand(2)};
41074123
NewBundles.emplace_back("ptrauth", NewBundleOps);
41084124
NewCallee = II->getOperand(0);
41094125
break;
41104126
}
4127+
default:
4128+
llvm_unreachable("unexpected intrinsic ID");
41114129
}
41124130

41134131
if (!NewCallee)
41144132
return nullptr;
41154133

41164134
NewCallee = Builder.CreateBitOrPointerCast(NewCallee, Callee->getType());
4117-
CallBase *NewCall = nullptr;
4118-
if (auto *CI = dyn_cast<CallInst>(&Call)) {
4119-
NewCall = CallInst::Create(CI, NewBundles);
4120-
} else {
4121-
auto *IKI = cast<InvokeInst>(&Call);
4122-
NewCall = InvokeInst::Create(IKI, NewBundles);
4123-
}
4135+
CallBase *NewCall = CallBase::Create(&Call, NewBundles);
41244136
NewCall->setCalledOperand(NewCallee);
41254137
return NewCall;
41264138
}
@@ -4313,8 +4325,8 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
43134325
if (IntrinsicInst *II = findInitTrampoline(Callee))
43144326
return transformCallThroughTrampoline(Call, *II);
43154327

4316-
// Combine calls involving pointer authentication
4317-
if (Instruction *NewCall = tryCombinePtrAuthCall(Call))
4328+
// Combine calls involving pointer authentication intrinsics.
4329+
if (Instruction *NewCall = foldPtrAuthIntrinsicCallee(Call))
43184330
return NewCall;
43194331

43204332
// Combine calls to ptrauth constants.

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,14 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
284284
IntrinsicInst &Tramp);
285285
Instruction *tryCombinePtrAuthCall(CallBase &Call);
286286

287+
/// Try to optimize a call to the result of a ptrauth intrinsic, potentially
288+
/// into the ptrauth call bundle:
289+
/// - call(ptrauth.resign(p)), ["ptrauth"()] -> call p, ["ptrauth"()]
290+
/// - call(ptrauth.sign(p)), ["ptrauth"()] -> call p
291+
/// as long as the key/discriminator are the same in sign and auth-bundle,
292+
/// and we don't change the key in the bundle (to a potentially-invalid key.)
293+
Instruction *foldPtrAuthIntrinsicCallee(CallBase &Call);
294+
287295
/// Try to optimize a call to a ptrauth constant, into its ptrauth bundle:
288296
/// call(ptrauth(f)), ["ptrauth"()] -> call f
289297
/// as long as the key/discriminator are the same in constant and bundle.
Lines changed: 122 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,143 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
22
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
33

4+
define i32 @test_ptrauth_call_sign(ptr %p) {
5+
; CHECK-LABEL: @test_ptrauth_call_sign(
6+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]()
7+
; CHECK-NEXT: ret i32 [[V3]]
8+
;
9+
%v0 = ptrtoint ptr %p to i64
10+
%v1 = call i64 @llvm.ptrauth.sign(i64 %v0, i32 2, i64 5678)
11+
%v2 = inttoptr i64 %v1 to ptr
12+
%v3 = call i32 %v2() [ "ptrauth"(i32 2, i64 5678) ]
13+
ret i32 %v3
14+
}
15+
16+
define i32 @test_ptrauth_call_sign_otherbundle(ptr %p) {
17+
; CHECK-LABEL: @test_ptrauth_call_sign_otherbundle(
18+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]() [ "somebundle"(ptr null), "otherbundle"(i64 0) ]
19+
; CHECK-NEXT: ret i32 [[V3]]
20+
;
21+
%v0 = ptrtoint ptr %p to i64
22+
%v1 = call i64 @llvm.ptrauth.sign(i64 %v0, i32 2, i64 5678)
23+
%v2 = inttoptr i64 %v1 to ptr
24+
%v3 = call i32 %v2() [ "somebundle"(ptr null), "ptrauth"(i32 2, i64 5678), "otherbundle"(i64 0) ]
25+
ret i32 %v3
26+
}
27+
428
define i32 @test_ptrauth_call_resign(ptr %p) {
529
; CHECK-LABEL: @test_ptrauth_call_resign(
6-
; CHECK-NEXT: [[TMP3:%.*]] = call i32 [[P:%.*]]() [ "ptrauth"(i32 0, i64 1234) ]
7-
; CHECK-NEXT: ret i32 [[TMP3]]
30+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]() [ "ptrauth"(i32 1, i64 1234) ]
31+
; CHECK-NEXT: ret i32 [[V3]]
832
;
9-
%tmp0 = ptrtoint ptr %p to i64
10-
%tmp1 = call i64 @llvm.ptrauth.resign(i64 %tmp0, i32 0, i64 1234, i32 2, i64 5678)
11-
%tmp2 = inttoptr i64 %tmp1 to ptr
12-
%tmp3 = call i32 %tmp2() [ "ptrauth"(i32 2, i64 5678) ]
13-
ret i32 %tmp3
33+
%v0 = ptrtoint ptr %p to i64
34+
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 1, i64 5678)
35+
%v2 = inttoptr i64 %v1 to ptr
36+
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
37+
ret i32 %v3
1438
}
1539

1640
define i32 @test_ptrauth_call_resign_blend(ptr %pp) {
1741
; CHECK-LABEL: @test_ptrauth_call_resign_blend(
18-
; CHECK-NEXT: [[TMP01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
19-
; CHECK-NEXT: [[TMP6:%.*]] = call i32 [[TMP01]]() [ "ptrauth"(i32 0, i64 1234) ]
20-
; CHECK-NEXT: ret i32 [[TMP6]]
42+
; CHECK-NEXT: [[V01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
43+
; CHECK-NEXT: [[V6:%.*]] = call i32 [[V01]]() [ "ptrauth"(i32 1, i64 1234) ]
44+
; CHECK-NEXT: ret i32 [[V6]]
2145
;
22-
%tmp0 = load ptr, ptr %pp, align 8
23-
%tmp1 = ptrtoint ptr %pp to i64
24-
%tmp2 = ptrtoint ptr %tmp0 to i64
25-
%tmp3 = call i64 @llvm.ptrauth.blend(i64 %tmp1, i64 5678)
26-
%tmp4 = call i64 @llvm.ptrauth.resign(i64 %tmp2, i32 0, i64 1234, i32 1, i64 %tmp3)
27-
%tmp5 = inttoptr i64 %tmp4 to ptr
28-
%tmp6 = call i32 %tmp5() [ "ptrauth"(i32 1, i64 %tmp3) ]
29-
ret i32 %tmp6
46+
%v0 = load ptr, ptr %pp, align 8
47+
%v1 = ptrtoint ptr %pp to i64
48+
%v2 = ptrtoint ptr %v0 to i64
49+
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
50+
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 1, i64 1234, i32 1, i64 %v3)
51+
%v5 = inttoptr i64 %v4 to ptr
52+
%v6 = call i32 %v5() [ "ptrauth"(i32 1, i64 %v3) ]
53+
ret i32 %v6
3054
}
3155

3256
define i32 @test_ptrauth_call_resign_blend_2(ptr %pp) {
3357
; CHECK-LABEL: @test_ptrauth_call_resign_blend_2(
34-
; CHECK-NEXT: [[TMP01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
35-
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PP]] to i64
36-
; CHECK-NEXT: [[TMP3:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[TMP1]], i64 5678)
37-
; CHECK-NEXT: [[TMP6:%.*]] = call i32 [[TMP01]]() [ "ptrauth"(i32 1, i64 [[TMP3]]) ]
38-
; CHECK-NEXT: ret i32 [[TMP6]]
58+
; CHECK-NEXT: [[V01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
59+
; CHECK-NEXT: [[V1:%.*]] = ptrtoint ptr [[PP]] to i64
60+
; CHECK-NEXT: [[V3:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[V1]], i64 5678)
61+
; CHECK-NEXT: [[V6:%.*]] = call i32 [[V01]]() [ "ptrauth"(i32 0, i64 [[V3]]) ]
62+
; CHECK-NEXT: ret i32 [[V6]]
63+
;
64+
%v0 = load ptr, ptr %pp, align 8
65+
%v1 = ptrtoint ptr %pp to i64
66+
%v2 = ptrtoint ptr %v0 to i64
67+
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
68+
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 0, i64 %v3, i32 0, i64 1234)
69+
%v5 = inttoptr i64 %v4 to ptr
70+
%v6 = call i32 %v5() [ "ptrauth"(i32 0, i64 1234) ]
71+
ret i32 %v6
72+
}
73+
74+
define i32 @test_ptrauth_call_resign_mismatch_key(ptr %p) {
75+
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_key(
76+
; CHECK-NEXT: [[V0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
77+
; CHECK-NEXT: [[V1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V0]], i32 1, i64 1234, i32 0, i64 5678)
78+
; CHECK-NEXT: [[V2:%.*]] = inttoptr i64 [[V1]] to ptr
79+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V2]]() [ "ptrauth"(i32 1, i64 5678) ]
80+
; CHECK-NEXT: ret i32 [[V3]]
81+
;
82+
%v0 = ptrtoint ptr %p to i64
83+
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 0, i64 5678)
84+
%v2 = inttoptr i64 %v1 to ptr
85+
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
86+
ret i32 %v3
87+
}
88+
89+
define i32 @test_ptrauth_call_resign_mismatch_disc(ptr %p) {
90+
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_disc(
91+
; CHECK-NEXT: [[V0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
92+
; CHECK-NEXT: [[V1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V0]], i32 1, i64 1234, i32 0, i64 9900)
93+
; CHECK-NEXT: [[V2:%.*]] = inttoptr i64 [[V1]] to ptr
94+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V2]]() [ "ptrauth"(i32 1, i64 5678) ]
95+
; CHECK-NEXT: ret i32 [[V3]]
3996
;
40-
%tmp0 = load ptr, ptr %pp, align 8
41-
%tmp1 = ptrtoint ptr %pp to i64
42-
%tmp2 = ptrtoint ptr %tmp0 to i64
43-
%tmp3 = call i64 @llvm.ptrauth.blend(i64 %tmp1, i64 5678)
44-
%tmp4 = call i64 @llvm.ptrauth.resign(i64 %tmp2, i32 1, i64 %tmp3, i32 0, i64 1234)
45-
%tmp5 = inttoptr i64 %tmp4 to ptr
46-
%tmp6 = call i32 %tmp5() [ "ptrauth"(i32 0, i64 1234) ]
47-
ret i32 %tmp6
97+
%v0 = ptrtoint ptr %p to i64
98+
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 0, i64 9900)
99+
%v2 = inttoptr i64 %v1 to ptr
100+
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
101+
ret i32 %v3
48102
}
49103

104+
define i32 @test_ptrauth_call_resign_mismatch_blend(ptr %pp) {
105+
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_blend(
106+
; CHECK-NEXT: [[V0:%.*]] = load ptr, ptr [[PP:%.*]], align 8
107+
; CHECK-NEXT: [[V1:%.*]] = ptrtoint ptr [[PP]] to i64
108+
; CHECK-NEXT: [[V2:%.*]] = ptrtoint ptr [[V0]] to i64
109+
; CHECK-NEXT: [[V6:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[V1]], i64 5678)
110+
; CHECK-NEXT: [[V4:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V2]], i32 1, i64 1234, i32 1, i64 [[V6]])
111+
; CHECK-NEXT: [[V5:%.*]] = inttoptr i64 [[V4]] to ptr
112+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V5]]() [ "ptrauth"(i32 1, i64 [[V1]]) ]
113+
; CHECK-NEXT: ret i32 [[V3]]
114+
;
115+
%v0 = load ptr, ptr %pp, align 8
116+
%v1 = ptrtoint ptr %pp to i64
117+
%v2 = ptrtoint ptr %v0 to i64
118+
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
119+
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 1, i64 1234, i32 1, i64 %v3)
120+
%v5 = inttoptr i64 %v4 to ptr
121+
%v6 = call i32 %v5() [ "ptrauth"(i32 1, i64 %v1) ]
122+
ret i32 %v6
123+
}
124+
125+
; Downstream, we allow changing keys
126+
127+
define i32 @test_ptrauth_call_resign_changing_call_key(ptr %p) {
128+
; CHECK-LABEL: @test_ptrauth_call_resign_changing_call_key(
129+
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]() [ "ptrauth"(i32 0, i64 1234) ]
130+
; CHECK-NEXT: ret i32 [[V3]]
131+
;
132+
%v0 = ptrtoint ptr %p to i64
133+
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 0, i64 1234, i32 1, i64 5678)
134+
%v2 = inttoptr i64 %v1 to ptr
135+
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
136+
ret i32 %v3
137+
}
138+
139+
; Downstream, we fold auth into the call
140+
50141
define i32 @test_ptrauth_call_auth(ptr %p) {
51142
; CHECK-LABEL: @test_ptrauth_call_auth(
52143
; CHECK-NEXT: [[TMP3:%.*]] = call i32 [[P:%.*]]() [ "ptrauth"(i32 2, i64 5678) ]
@@ -59,19 +150,6 @@ define i32 @test_ptrauth_call_auth(ptr %p) {
59150
ret i32 %tmp3
60151
}
61152

62-
define i32 @test_ptrauth_call_sign(ptr %p) {
63-
; CHECK-LABEL: @test_ptrauth_call_sign(
64-
; CHECK-NEXT: [[TMP3:%.*]] = call i32 [[P:%.*]]()
65-
; CHECK-NEXT: ret i32 [[TMP3]]
66-
;
67-
%tmp0 = ptrtoint ptr %p to i64
68-
%tmp1 = call i64 @llvm.ptrauth.sign(i64 %tmp0, i32 2, i64 5678)
69-
%tmp2 = inttoptr i64 %tmp1 to ptr
70-
%tmp3 = call i32 %tmp2() [ "ptrauth"(i32 2, i64 5678) ]
71-
ret i32 %tmp3
72-
}
73-
74-
declare i64 @llvm.ptrauth.auth(i64, i32, i64)
75153
declare i64 @llvm.ptrauth.sign(i64, i32, i64)
76154
declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)
77155
declare i64 @llvm.ptrauth.blend(i64, i64)

0 commit comments

Comments
 (0)