Skip to content

Commit 1487747

Browse files
committed
[LTO] Prevent devirtualization for symbols dynamically exported
Identify dynamically exported symbols (--export-dynamic[-symbol=], --dynamic-list=, or definitions needed to preempt shared objects) and prevent their LTO visibility from being upgraded. This helps avoid use of whole program devirtualization when there may be overrides in dynamic libraries. Differential Revision: https://reviews.llvm.org/D91583
1 parent 6110e77 commit 1487747

File tree

14 files changed

+504
-36
lines changed

14 files changed

+504
-36
lines changed

lld/ELF/LTO.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,10 @@ void BitcodeCompiler::add(BitcodeFile &f) {
247247
r.VisibleToRegularObj = config->relocatable || sym->isUsedInRegularObj ||
248248
(r.Prevailing && sym->includeInDynsym()) ||
249249
usedStartStop.count(objSym.getSectionName());
250+
// Identify symbols exported dynamically, and that therefore could be
251+
// referenced by a shared library not visible to the linker.
252+
r.ExportDynamic = sym->isExportDynamic(sym->kind(), sym->visibility) ||
253+
sym->exportDynamic || sym->inDynamicList;
250254
const auto *dr = dyn_cast<Defined>(sym);
251255
r.FinalDefinitionInLinkageUnit =
252256
(isExec || sym->visibility != STV_DEFAULT) && dr &&

lld/ELF/Symbols.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,13 @@ class Symbol {
223223
// non-lazy object causes a runtime error.
224224
void fetch() const;
225225

226-
private:
227226
static bool isExportDynamic(Kind k, uint8_t visibility) {
228227
if (k == SharedKind)
229228
return visibility == llvm::ELF::STV_DEFAULT;
230229
return config->shared || config->exportDynamic;
231230
}
232231

232+
private:
233233
void resolveUndefined(const Undefined &other);
234234
void resolveCommon(const CommonSymbol &other);
235235
void resolveDefined(const Defined &other);
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
; REQUIRES: x86
2+
;; Test that dynamically exported symbols prevent devirtualization.
3+
4+
;; First check that we get devirtualization without any export dynamic options.
5+
6+
;; Index based WPD
7+
;; Generate unsplit module with summary for ThinLTO index-based WPD.
8+
; RUN: opt --thinlto-bc -o %t2.o %s
9+
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
10+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
11+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
12+
13+
;; Hybrid WPD
14+
;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
15+
; RUN: opt --thinlto-bc --thinlto-split-lto-unit -o %t.o %s
16+
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
17+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
18+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
19+
20+
;; Regular LTO WPD
21+
; RUN: opt -o %t4.o %s
22+
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
23+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
24+
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
25+
26+
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
27+
; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
28+
29+
;; Check that all WPD fails with --export-dynamic.
30+
31+
;; Index based WPD
32+
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
33+
; RUN: -mllvm -pass-remarks=. \
34+
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
35+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
36+
37+
;; Hybrid WPD
38+
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
39+
; RUN: -mllvm -pass-remarks=. \
40+
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
41+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
42+
43+
;; Regular LTO WPD
44+
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
45+
; RUN: -mllvm -pass-remarks=. \
46+
; RUN: --export-dynamic 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
47+
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
48+
49+
;; Check that WPD fails for target _ZN1D1mEi with --export-dynamic-symbol=_ZTV1D.
50+
51+
;; Index based WPD
52+
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
53+
; RUN: -mllvm -pass-remarks=. \
54+
; RUN: --export-dynamic-symbol=_ZTV1D 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
55+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
56+
57+
;; Hybrid WPD
58+
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
59+
; RUN: -mllvm -pass-remarks=. \
60+
; RUN: --export-dynamic-symbol=_ZTV1D 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
61+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
62+
63+
;; Regular LTO WPD
64+
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
65+
; RUN: -mllvm -pass-remarks=. \
66+
; RUN: --export-dynamic-symbol=_ZTV1D 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
67+
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
68+
69+
; REMARK-AONLY-NOT: single-impl:
70+
; REMARK-AONLY: single-impl: devirtualized a call to _ZN1A1nEi
71+
; REMARK-AONLY-NOT: single-impl:
72+
73+
;; Check that WPD fails for target _ZN1D1mEi with _ZTV1D in --dynamic-list.
74+
; RUN: echo "{ _ZTV1D; };" > %t.list
75+
76+
;; Index based WPD
77+
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
78+
; RUN: -mllvm -pass-remarks=. \
79+
; RUN: --dynamic-list=%t.list 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
80+
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
81+
82+
;; Hybrid WPD
83+
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
84+
; RUN: -mllvm -pass-remarks=. \
85+
; RUN: --dynamic-list=%t.list 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
86+
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
87+
88+
;; Regular LTO WPD
89+
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
90+
; RUN: -mllvm -pass-remarks=. \
91+
; RUN: --dynamic-list=%t.list 2>&1 | FileCheck %s --check-prefix=REMARK-AONLY
92+
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-AONLY-IR
93+
94+
95+
;; Check that all WPD fails with when linking against a shared library containing
96+
;; preemptible versions of the vtables. In this case the symbols in the object being
97+
;; linked against the shared library must be exported to .dynsym to allow the runtime
98+
;; preemption, even without any options.
99+
100+
;; Index based WPD
101+
; RUN: opt -relocation-model=pic -o %t5.o %s
102+
; RUN: ld.lld %t5.o -o %t5.so -shared
103+
; RUN: ld.lld %t5.o %t5.so -o %t5 -save-temps --lto-whole-program-visibility \
104+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
105+
106+
;; Hybrid WPD
107+
; RUN: opt -relocation-model=pic --thinlto-bc -o %t5.o %s
108+
; RUN: ld.lld %t5.o -o %t5.so -shared
109+
; RUN: ld.lld %t5.o %t5.so -o %t5 -save-temps --lto-whole-program-visibility \
110+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
111+
112+
;; Regular LTO WPD
113+
; RUN: opt -relocation-model=pic --thinlto-bc --thinlto-split-lto-unit -o %t5.o %s
114+
; RUN: ld.lld %t5.o -o %t5.so -shared
115+
; RUN: ld.lld %t5.o %t5.so -o %t5 -save-temps --lto-whole-program-visibility \
116+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
117+
118+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
119+
target triple = "x86_64-grtev4-linux-gnu"
120+
121+
%struct.A = type { i32 (...)** }
122+
%struct.B = type { %struct.A }
123+
%struct.C = type { %struct.A }
124+
%struct.D = type { i32 (...)** }
125+
126+
@_ZTV1B = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.B*, i32)* @_ZN1B1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !1, !vcall_visibility !5
127+
@_ZTV1C = linkonce_odr unnamed_addr constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2, !vcall_visibility !5
128+
@_ZTV1D = linkonce_odr unnamed_addr constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3, !vcall_visibility !5
129+
130+
;; Prevent the vtables from being dead code eliminated.
131+
@llvm.used = appending global [3 x i8*] [ i8* bitcast ( { [4 x i8*] }* @_ZTV1B to i8*), i8* bitcast ( { [4 x i8*] }* @_ZTV1C to i8*), i8* bitcast ( { [3 x i8*] }* @_ZTV1D to i8*)]
132+
133+
; CHECK-IR-LABEL: define dso_local i32 @_start
134+
define i32 @_start(%struct.A* %obj, %struct.D* %obj2, i32 %a) {
135+
entry:
136+
%0 = bitcast %struct.A* %obj to i8***
137+
%vtable = load i8**, i8*** %0
138+
%1 = bitcast i8** %vtable to i8*
139+
%p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
140+
call void @llvm.assume(i1 %p)
141+
%fptrptr = getelementptr i8*, i8** %vtable, i32 1
142+
%2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
143+
%fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8
144+
145+
;; Check that the call was devirtualized.
146+
; CHECK-IR: %call = tail call i32 @_ZN1A1nEi
147+
; CHECK-AONLY-IR: %call = tail call i32 @_ZN1A1nEi
148+
; CHECK-NODEVIRT-IR: %call = tail call i32 %fptr1
149+
%call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
150+
151+
%3 = bitcast i8** %vtable to i32 (%struct.A*, i32)**
152+
%fptr22 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %3, align 8
153+
154+
;; We still have to call it as virtual.
155+
; CHECK-IR: %call3 = tail call i32 %fptr22
156+
; CHECK-AONLY-IR: %call3 = tail call i32 %fptr22
157+
; CHECK-NODEVIRT-IR: %call3 = tail call i32 %fptr22
158+
%call3 = tail call i32 %fptr22(%struct.A* nonnull %obj, i32 %call)
159+
160+
%4 = bitcast %struct.D* %obj2 to i8***
161+
%vtable2 = load i8**, i8*** %4
162+
%5 = bitcast i8** %vtable2 to i8*
163+
%p2 = call i1 @llvm.type.test(i8* %5, metadata !4)
164+
call void @llvm.assume(i1 %p2)
165+
166+
%6 = bitcast i8** %vtable2 to i32 (%struct.D*, i32)**
167+
%fptr33 = load i32 (%struct.D*, i32)*, i32 (%struct.D*, i32)** %6, align 8
168+
169+
;; Check that the call was devirtualized.
170+
; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
171+
; CHECK-AONLY-IR: %call4 = tail call i32 %fptr33
172+
; CHECK-NODEVIRT-IR: %call4 = tail call i32 %fptr33
173+
%call4 = tail call i32 %fptr33(%struct.D* nonnull %obj2, i32 %call3)
174+
ret i32 %call4
175+
}
176+
; CHECK-IR-LABEL: ret i32
177+
; CHECK-IR-LABEL: }
178+
179+
declare i1 @llvm.type.test(i8*, metadata)
180+
declare void @llvm.assume(i1)
181+
182+
define i32 @_ZN1B1fEi(%struct.B* %this, i32 %a) #0 {
183+
ret i32 0;
184+
}
185+
186+
define i32 @_ZN1A1nEi(%struct.A* %this, i32 %a) #0 {
187+
ret i32 0;
188+
}
189+
190+
define i32 @_ZN1C1fEi(%struct.C* %this, i32 %a) #0 {
191+
ret i32 0;
192+
}
193+
194+
define i32 @_ZN1D1mEi(%struct.D* %this, i32 %a) #0 {
195+
ret i32 0;
196+
}
197+
198+
;; Make sure we don't inline or otherwise optimize out the direct calls.
199+
attributes #0 = { noinline optnone }
200+
201+
!0 = !{i64 16, !"_ZTS1A"}
202+
!1 = !{i64 16, !"_ZTS1B"}
203+
!2 = !{i64 16, !"_ZTS1C"}
204+
!3 = !{i64 16, !4}
205+
!4 = distinct !{}
206+
!5 = !{i64 0}

lld/test/ELF/lto/devirt_vcall_vis_public.ll

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
; REQUIRES: x86
22
;; Test that --lto-whole-program-visibility enables devirtualization.
33

4-
;; Note that the --export-dynamic used below is simply to ensure symbols are
5-
;; retained during linking.
6-
74
;; Index based WPD
85
;; Generate unsplit module with summary for ThinLTO index-based WPD.
96
; RUN: opt --thinlto-bc -o %t2.o %s
107
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility \
11-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --check-prefix=REMARK
8+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
129
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
1310

1411
;; Hybrid WPD
1512
;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
1613
; RUN: opt --thinlto-bc --thinlto-split-lto-unit -o %t.o %s
1714
; RUN: ld.lld %t.o -o %t3 -save-temps --lto-whole-program-visibility \
18-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --check-prefix=REMARK
15+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
1916
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
2017

2118
;; Regular LTO WPD
2219
; RUN: opt -o %t4.o %s
2320
; RUN: ld.lld %t4.o -o %t3 -save-temps --lto-whole-program-visibility \
24-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --check-prefix=REMARK
21+
; RUN: -mllvm -pass-remarks=. 2>&1 | FileCheck %s --check-prefix=REMARK
2522
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
2623

2724
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
@@ -32,21 +29,25 @@
3229

3330
;; Index based WPD
3431
; RUN: ld.lld %t2.o -o %t3 -save-temps \
35-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
32+
; RUN: -mllvm -pass-remarks=. \
33+
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
3634
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
3735
;; Ensure --no-lto-whole-program-visibility overrides explicit --lto-whole-program-visibility.
3836
; RUN: ld.lld %t2.o -o %t3 -save-temps --lto-whole-program-visibility --no-lto-whole-program-visibility \
39-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
37+
; RUN: -mllvm -pass-remarks=. \
38+
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
4039
; RUN: llvm-dis %t2.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
4140

4241
;; Hybrid WPD
4342
; RUN: ld.lld %t.o -o %t3 -save-temps \
44-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
43+
; RUN: -mllvm -pass-remarks=. \
44+
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
4545
; RUN: llvm-dis %t.o.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
4646

4747
;; Regular LTO WPD
4848
; RUN: ld.lld %t4.o -o %t3 -save-temps \
49-
; RUN: -mllvm -pass-remarks=. --export-dynamic 2>&1 | FileCheck %s --implicit-check-not single-impl --allow-empty
49+
; RUN: -mllvm -pass-remarks=. \
50+
; RUN: 2>&1 | FileCheck /dev/null --implicit-check-not single-impl --allow-empty
5051
; RUN: llvm-dis %t3.0.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-NODEVIRT-IR
5152

5253
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
@@ -61,6 +62,8 @@ target triple = "x86_64-grtev4-linux-gnu"
6162
@_ZTV1C = constant { [4 x i8*] } { [4 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.C*, i32)* @_ZN1C1fEi to i8*), i8* bitcast (i32 (%struct.A*, i32)* @_ZN1A1nEi to i8*)] }, !type !0, !type !2, !vcall_visibility !5
6263
@_ZTV1D = constant { [3 x i8*] } { [3 x i8*] [i8* null, i8* undef, i8* bitcast (i32 (%struct.D*, i32)* @_ZN1D1mEi to i8*)] }, !type !3, !vcall_visibility !5
6364

65+
; Prevent the vtables from being dead code eliminated.
66+
@llvm.used = appending global [3 x i8*] [ i8* bitcast ( { [4 x i8*] }* @_ZTV1B to i8*), i8* bitcast ( { [4 x i8*] }* @_ZTV1C to i8*), i8* bitcast ( { [3 x i8*] }* @_ZTV1D to i8*)]
6467

6568
; CHECK-IR-LABEL: define dso_local i32 @_start
6669
define i32 @_start(%struct.A* %obj, %struct.D* %obj2, i32 %a) {

llvm/include/llvm/LTO/LTO.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ class LTO {
364364
/// summary).
365365
bool VisibleOutsideSummary = false;
366366

367+
/// The symbol was exported dynamically, and therefore could be referenced
368+
/// by a shared library not visible to the linker.
369+
bool ExportDynamic = false;
370+
367371
bool UnnamedAddr = true;
368372

369373
/// True if module contains the prevailing definition.
@@ -434,14 +438,18 @@ class LTO {
434438

435439
// Use Optional to distinguish false from not yet initialized.
436440
Optional<bool> EnableSplitLTOUnit;
441+
442+
// Identify symbols exported dynamically, and that therefore could be
443+
// referenced by a shared library not visible to the linker.
444+
DenseSet<GlobalValue::GUID> DynamicExportSymbols;
437445
};
438446

439447
/// The resolution for a symbol. The linker must provide a SymbolResolution for
440448
/// each global symbol based on its internal resolution of that symbol.
441449
struct SymbolResolution {
442450
SymbolResolution()
443451
: Prevailing(0), FinalDefinitionInLinkageUnit(0), VisibleToRegularObj(0),
444-
LinkerRedefined(0) {}
452+
ExportDynamic(0), LinkerRedefined(0) {}
445453

446454
/// The linker has chosen this definition of the symbol.
447455
unsigned Prevailing : 1;
@@ -453,6 +461,10 @@ struct SymbolResolution {
453461
/// The definition of this symbol is visible outside of the LTO unit.
454462
unsigned VisibleToRegularObj : 1;
455463

464+
/// The symbol was exported dynamically, and therefore could be referenced
465+
/// by a shared library not visible to the linker.
466+
unsigned ExportDynamic : 1;
467+
456468
/// Linker redefined version of the symbol which appeared in -wrap or -defsym
457469
/// linker option.
458470
unsigned LinkerRedefined : 1;

llvm/include/llvm/Transforms/IPO/WholeProgramDevirt.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,12 @@ struct VTableSlotSummary {
239239
uint64_t ByteOffset;
240240
};
241241

242-
void updateVCallVisibilityInModule(Module &M,
243-
bool WholeProgramVisibilityEnabledInLTO);
244-
void updateVCallVisibilityInIndex(ModuleSummaryIndex &Index,
245-
bool WholeProgramVisibilityEnabledInLTO);
242+
void updateVCallVisibilityInModule(
243+
Module &M, bool WholeProgramVisibilityEnabledInLTO,
244+
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols);
245+
void updateVCallVisibilityInIndex(
246+
ModuleSummaryIndex &Index, bool WholeProgramVisibilityEnabledInLTO,
247+
const DenseSet<GlobalValue::GUID> &DynamicExportSymbols);
246248

247249
/// Perform index-based whole program devirtualization on the \p Summary
248250
/// index. Any devirtualized targets used by a type test in another module

0 commit comments

Comments
 (0)