Skip to content

Commit c9cf318

Browse files
committed
[PtrAuth] Add ConstantPtrAuth comparator to FunctionComparator.cpp
When building rustc std for arm64e, the optimizations result in devirtualization of indirect calls. This can happen during function merging so I modified FunctionComparator.cpp as the ConstantPtrAuth value would go unchecked in the switch statement.
1 parent d2f67c3 commit c9cf318

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

llvm/lib/Transforms/Utils/FunctionComparator.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,23 @@ int FunctionComparator::cmpConstants(const Constant *L,
354354
if (!L->isNullValue() && R->isNullValue())
355355
return -1;
356356

357+
// Handle authenticated pointer constants produced by ConstantPtrAuth::get.
358+
if (auto *PA1 = dyn_cast<ConstantPtrAuth>(L)) {
359+
auto *PA2 = dyn_cast<ConstantPtrAuth>(R);
360+
if (!PA2)
361+
return cmpNumbers(L->getValueID(), R->getValueID());
362+
363+
if (int Res = cmpConstants(PA1->getPointer(), PA2->getPointer()))
364+
return Res;
365+
if (int Res = cmpConstants(PA1->getKey(), PA2->getKey()))
366+
return Res;
367+
if (int Res =
368+
cmpConstants(PA1->getDiscriminator(), PA2->getDiscriminator()))
369+
return Res;
370+
return cmpConstants(PA1->getAddrDiscriminator(),
371+
PA2->getAddrDiscriminator());
372+
}
373+
357374
auto GlobalValueL = const_cast<GlobalValue *>(dyn_cast<GlobalValue>(L));
358375
auto GlobalValueR = const_cast<GlobalValue *>(dyn_cast<GlobalValue>(R));
359376
if (GlobalValueL && GlobalValueR) {
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
; RUN: opt -passes=mergefunc -S %s | FileCheck %s
2+
; Ensure MergeFunc handles ConstantPtrAuth correctly and does not
3+
; merge when any ptrauth operand differs (ptr, key, int disc, addr disc).
4+
5+
target triple = "arm64e-apple-ios14.0.0"
6+
7+
declare void @baz()
8+
@ADDR = external global i8
9+
10+
declare void @sink0()
11+
declare void @sink1()
12+
declare void @sink2()
13+
declare void @sink3()
14+
15+
; different base pointer (null vs @baz)
16+
17+
define void @f_ptr_null() {
18+
; CHECK-LABEL: define void @f_ptr_null()
19+
; CHECK: call void @sink0()
20+
; CHECK: call void ptrauth (ptr null, i32 0)(
21+
entry:
22+
call void @sink0()
23+
call void ptrauth (ptr null, i32 0)(ptr null)
24+
ret void
25+
}
26+
27+
define void @g_ptr_baz() {
28+
; CHECK-LABEL: define void @g_ptr_baz()
29+
; CHECK: call void @sink0()
30+
; CHECK: call void ptrauth (ptr @baz, i32 0)(
31+
entry:
32+
call void @sink0()
33+
call void ptrauth (ptr @baz, i32 0)(ptr null)
34+
ret void
35+
}
36+
37+
; different key (i32 0 vs i32 1)
38+
39+
define void @f_key0() {
40+
; CHECK-LABEL: define void @f_key0()
41+
; CHECK: call void @sink1()
42+
; CHECK: call void ptrauth (ptr @baz, i32 0)(
43+
entry:
44+
call void @sink1()
45+
call void ptrauth (ptr @baz, i32 0)(ptr null)
46+
ret void
47+
}
48+
49+
define void @g_key1() {
50+
; CHECK-LABEL: define void @g_key1()
51+
; CHECK: call void @sink1()
52+
; CHECK: call void ptrauth (ptr @baz, i32 1)(
53+
entry:
54+
call void @sink1()
55+
call void ptrauth (ptr @baz, i32 1)(ptr null)
56+
ret void
57+
}
58+
59+
; different integer disc (i64 0 vs i64 7)
60+
61+
define void @f_disc0() {
62+
; CHECK-LABEL: define void @f_disc0()
63+
; CHECK: call void @sink2()
64+
; CHECK: call void ptrauth (ptr @baz, i32 0)(
65+
entry:
66+
call void @sink2()
67+
call void ptrauth (ptr @baz, i32 0)(ptr null)
68+
ret void
69+
}
70+
71+
define void @g_disc7() {
72+
; CHECK-LABEL: define void @g_disc7()
73+
; CHECK: call void @sink2()
74+
; CHECK: call void ptrauth (ptr @baz, i32 0, i64 7)(
75+
entry:
76+
call void @sink2()
77+
call void ptrauth (ptr @baz, i32 0, i64 7)(ptr null)
78+
ret void
79+
}
80+
81+
; different addr disc (ptr null vs @ADDR)
82+
83+
define void @f_addr_null() {
84+
; CHECK-LABEL: define void @f_addr_null()
85+
; CHECK: call void @sink3()
86+
; CHECK: call void ptrauth (ptr @baz, i32 0)(
87+
entry:
88+
call void @sink3()
89+
call void ptrauth (ptr @baz, i32 0)(ptr null)
90+
ret void
91+
}
92+
93+
define void @g_addr_ADDR() {
94+
; CHECK-LABEL: define void @g_addr_ADDR()
95+
; CHECK: call void @sink3()
96+
; CHECK: call void ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)(
97+
entry:
98+
call void @sink3()
99+
call void ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)(ptr null)
100+
ret void
101+
}
102+
103+
; positive test: identical ptrauth operands, should be merged
104+
105+
define void @merge_ptrauth_a() {
106+
; CHECK-LABEL: define void @merge_ptrauth_a()
107+
; CHECK: call void @sink1()
108+
; CHECK: call void ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)(ptr null)
109+
entry:
110+
call void @sink1()
111+
call void ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)(ptr null)
112+
ret void
113+
}
114+
115+
define void @merge_ptrauth_b() {
116+
; CHECK-LABEL: define void @merge_ptrauth_b()
117+
; CHECK: tail call void @merge_ptrauth_a()
118+
entry:
119+
call void @sink1()
120+
call void ptrauth (ptr @baz, i32 0, i64 0, ptr @ADDR)(ptr null)
121+
ret void
122+
}

0 commit comments

Comments
 (0)