Skip to content

Commit b8b2f99

Browse files
committed
Reapply "[llvm] Teach GlobalDCE about dso_local_equivalent"
This reverts commit 1c604a9.
1 parent 09c3bfe commit b8b2f99

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

llvm/include/llvm/Analysis/TypeMetadataUtils.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ std::pair<Function *, Constant *>
8787
getFunctionAtVTableOffset(GlobalVariable *GV, uint64_t Offset, Module &M);
8888

8989
/// Finds the same "relative pointer" pattern as described above, where the
90-
/// target is `F`, and replaces the entire pattern with a constant zero.
91-
void replaceRelativePointerUsersWithZero(Function *F);
90+
/// target is `C`, and replaces the entire pattern with a constant zero.
91+
void replaceRelativePointerUsersWithZero(Constant *C);
9292

9393
} // namespace llvm
9494

llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,32 @@ declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
1616

1717
; CHECK: @vtable = internal unnamed_addr constant { [3 x i32] } zeroinitializer, align 8, !type !0, !type !1, !vcall_visibility !2
1818

19+
@vtable2 = internal unnamed_addr constant { [3 x i32] } { [3 x i32] [
20+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3 to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
21+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc4 to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
22+
23+
; a "bad" relative pointer because it's base is not the @vtable symbol
24+
i32 trunc (i64 sub (i64 ptrtoint (ptr @weird_ref_3 to i64), i64 ptrtoint (ptr @weird_ref_4 to i64)) to i32)
25+
]}, align 4, !type !3, !type !4, !vcall_visibility !{i64 2}
26+
!3 = !{i64 0, !"vfunc3.type"}
27+
!4 = !{i64 4, !"vfunc4.type"}
28+
29+
; CHECK: @vtable2 = internal unnamed_addr constant { [3 x i32] } zeroinitializer, align 4, !type !3, !type !4, !vcall_visibility !2
30+
1931
define internal void @vfunc1() { ret void }
2032
define internal void @vfunc2() { ret void }
2133
define internal void @weird_ref_1() { ret void }
2234
define internal void @weird_ref_2() { ret void }
35+
declare void @vfunc3()
36+
declare void @vfunc4()
37+
declare void @weird_ref_3()
38+
declare void @weird_ref_4()
2339

2440
define void @main() {
2541
%1 = ptrtoint ptr @vtable to i64 ; to keep @vtable alive
2642
call void @weird_ref_2()
43+
%2 = ptrtoint ptr @vtable2 to i64 ; to keep @vtable2 alive
44+
call void @weird_ref_4()
2745
ret void
2846
}
2947

llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,20 @@ declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
1919
; CHECK-SAME: i32 0
2020
; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
2121

22+
@vtable2 = internal unnamed_addr constant { [4 x i32] } { [4 x i32] [
23+
i32 42,
24+
i32 1337,
25+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32),
26+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc4_dead_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32)
27+
]}, align 4, !type !3, !type !4, !vcall_visibility !{i64 2}
28+
!3 = !{i64 8, !"vfunc3.type"}
29+
!4 = !{i64 12, !"vfunc4.type"}
30+
31+
; CHECK: @vtable2 = internal unnamed_addr constant { [4 x i32] } { [4 x i32] [
32+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @vtable2, i32 0, i32 0, i32 2) to i64)) to i32),
33+
; CHECK-SAME: i32 0
34+
; CHECK-SAME: ] }, align 4, !type !3, !type !4, !vcall_visibility !2
35+
2236
; (1) vfunc1_live is referenced from @main, stays alive
2337
define internal void @vfunc1_live() {
2438
; CHECK: define internal void @vfunc1_live(
@@ -31,9 +45,19 @@ define internal void @vfunc2_dead() {
3145
ret void
3246
}
3347

48+
; (3) vfunc3_live_extern is referenced from @main, stays alive
49+
; CHECK: declare void @vfunc3_live_extern
50+
declare void @vfunc3_live_extern()
51+
52+
; (4) vfunc4_dead_extern is never referenced, gets removed and vtable slot is null'd
53+
; CHECK-NOT: declare void @vfunc4_dead_extern
54+
declare void @vfunc4_dead_extern()
55+
3456
define void @main() {
3557
%1 = ptrtoint ptr @vtable to i64 ; to keep @vtable alive
3658
%2 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc1.type")
59+
%3 = ptrtoint ptr @vtable2 to i64 ; to keep @vtable2 alive
60+
%4 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc3.type")
3761
ret void
3862
}
3963

llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,20 @@ declare { ptr, i1 } @llvm.type.checked.load(ptr, i32, metadata)
1717
; CHECK-SAME: i32 0
1818
; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
1919

20+
; Similar to above, but the vtable is more aligned to how C++ relative vtables look.
21+
; That is, the functions may not be dso-local.
22+
@vtable2 = internal unnamed_addr constant { [2 x i32] } { [2 x i32] [
23+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
24+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc4_dead_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32)
25+
]}, align 4, !type !3, !type !4, !vcall_visibility !{i64 2}
26+
!3 = !{i64 0, !"vfunc3.type"}
27+
!4 = !{i64 4, !"vfunc4.type"}
28+
29+
; CHECK: @vtable2 = internal unnamed_addr constant { [2 x i32] } { [2 x i32] [
30+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vfunc3_live_extern to i64), i64 ptrtoint (ptr @vtable2 to i64)) to i32),
31+
; CHECK-SAME: i32 0
32+
; CHECK-SAME: ] }, align 4, !type !3, !type !4, !vcall_visibility !2
33+
2034
; (1) vfunc1_live is referenced from @main, stays alive
2135
define internal void @vfunc1_live() {
2236
; CHECK: define internal void @vfunc1_live(
@@ -29,9 +43,19 @@ define internal void @vfunc2_dead() {
2943
ret void
3044
}
3145

46+
; (3) vfunc3_live_extern is referenced from @main, stays alive
47+
; CHECK: declare void @vfunc3_live_extern
48+
declare void @vfunc3_live_extern()
49+
50+
; (4) vfunc4_dead_extern is never referenced, gets removed and vtable slot is null'd
51+
; CHECK-NOT: declare void @vfunc4_dead_extern
52+
declare void @vfunc4_dead_extern()
53+
3254
define void @main() {
3355
%1 = ptrtoint ptr @vtable to i64 ; to keep @vtable alive
3456
%2 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc1.type")
57+
%3 = ptrtoint ptr @vtable2 to i64 ; to keep @vtable2 alive
58+
%4 = tail call { ptr, i1 } @llvm.type.checked.load(ptr null, i32 0, metadata !"vfunc3.type")
3559
ret void
3660
}
3761

0 commit comments

Comments
 (0)