xref: /llvm-project/lld/test/ELF/lto/devirt_vcall_vis_public.ll (revision 1228becf7df28c68579f2b9b390b74aa41149a0a)
1; REQUIRES: x86
2;; Test that --lto-whole-program-visibility enables devirtualization.
3
4;; Index based WPD
5;; Generate unsplit module with summary for ThinLTO index-based WPD.
6; RUN: opt --thinlto-bc -o %t2.o %s
7; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
8; RUN:   -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
9; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
10
11;; Hybrid WPD
12;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
13; RUN: opt --thinlto-bc --thinlto-split-lto-unit -o %t.o %s
14; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
15; RUN:   -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
16; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
17
18;; Regular LTO WPD
19; RUN: opt -o %t4.o %s
20; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
21; RUN:   -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
22; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
23
24; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
25; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
26
27;; Try everything again but without -whole-program-visibility to confirm
28;; WPD fails
29
30;; Index based WPD
31; RUN: ld.lld %t2.o -o %t3 -save-temps \
32; RUN:   -mllvm -pass-remarks=. \
33; RUN:   2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
34; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
35;; Ensure --no-lto-whole-program-visibility overrides explicit --lto-whole-program-visibility.
36; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility --no-lto-whole-program-visibility \
37; RUN:   -mllvm -pass-remarks=. \
38; RUN:   2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
39; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
40
41;; Hybrid WPD
42; RUN: ld.lld %t.o -o %t3 -save-temps \
43; RUN:   -mllvm -pass-remarks=. \
44; RUN:   2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
45; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
46
47;; Regular LTO WPD
48; RUN: ld.lld %t4.o -o %t3 -save-temps \
49; RUN:   -mllvm -pass-remarks=. \
50; RUN:   2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
51; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
52
53target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
54target triple = "x86_64-grtev4-linux-gnu"
55
56%struct.A = type { ptr }
57%struct.B = type { %struct.A }
58%struct.C = type { %struct.A }
59%struct.D = type { ptr }
60
61@_ZTV1B = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1B1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !1, !vcall_visibility !5
62@_ZTV1C = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1C1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !2, !vcall_visibility !5
63@_ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr undef, ptr @_ZN1D1mEi] }, !type !3, !vcall_visibility !5
64
65; Prevent the vtables from being dead code eliminated.
66@llvm.used = appending global [3 x ptr] [ ptr @_ZTV1B, ptr @_ZTV1C, ptr @_ZTV1D]
67
68; CHECK-IR-LABEL: define dso_local {{(noundef )?}}i32 @_start
69define i32 @_start(ptr %obj, ptr %obj2, i32 %a) {
70entry:
71  %vtable = load ptr, ptr %obj
72  %p = call i1 @llvm.type.test(ptr %vtable, metadata !"_ZTS1A")
73  call void @llvm.assume(i1 %p)
74  %fptrptr = getelementptr ptr, ptr %vtable, i32 1
75  %fptr1 = load ptr, ptr %fptrptr, align 8
76
77  ;; Check that the call was devirtualized.
78  ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
79  ; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
80  %call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a)
81
82  %fptr22 = load ptr, ptr %vtable, align 8
83
84  ;; We still have to call it as virtual.
85  ; CHECK-IR: %call3 = tail call i32 %fptr22
86  ; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
87  %call3 = tail call i32 %fptr22(ptr nonnull %obj, i32 %call)
88
89  %vtable2 = load ptr, ptr %obj2
90  %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !4)
91  call void @llvm.assume(i1 %p2)
92
93  %fptr33 = load ptr, ptr %vtable2, align 8
94
95  ;; Check that the call was devirtualized.
96  ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
97  ; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
98  %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %call3)
99  ret i32 %call4
100}
101; CHECK-IR-LABEL: ret i32
102; CHECK-IR-LABEL: }
103
104declare i1 @llvm.type.test(ptr, metadata)
105declare void @llvm.assume(i1)
106
107define i32 @_ZN1B1fEi(ptr %this, i32 %a) #0 {
108   ret i32 0;
109}
110
111define i32 @_ZN1A1nEi(ptr %this, i32 %a) #0 {
112   ret i32 0;
113}
114
115define i32 @_ZN1C1fEi(ptr %this, i32 %a) #0 {
116   ret i32 0;
117}
118
119define i32 @_ZN1D1mEi(ptr %this, i32 %a) #0 {
120   ret i32 0;
121}
122
123;; Make sure we don't inline or otherwise optimize out the direct calls.
124attributes #0 = { noinline optnone }
125
126!0 = !{i64 16, !"_ZTS1A"}
127!1 = !{i64 16, !"_ZTS1B"}
128!2 = !{i64 16, !"_ZTS1C"}
129!3 = !{i64 16, !4}
130!4 = distinct !{}
131!5 = !{i64 0}
132