Skip to content

Commit 791c98e

Browse files
committedFeb 6, 2018
[ThinLTO] Remove dead and dropped symbol declarations when possible
Summary: Removing the dropped symbols will prevent indirect call promotion in the ThinLTO Backend from adding a new reference to a symbol, which can result in linker unsats. This can happen when we compile with a sample profile collected from one binary by used for another, which may have profiled targets that aren't used in the new binary. Note that until dropDeadSymbols handles variables and aliases (in progress), we may not be able to remove the declaration and can still have an issue. Reviewers: grimar, davidxl Subscribers: mehdi_amini, inglorion, llvm-commits, eraman Differential Revision: https://reviews.llvm.org/D42816 llvm-svn: 324299
1 parent 7b98be2 commit 791c98e

File tree

4 files changed

+90
-10
lines changed

4 files changed

+90
-10
lines changed
 

‎llvm/lib/LTO/LTOBackend.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -401,14 +401,23 @@ Error lto::backend(Config &C, AddStreamFn AddStream,
401401

402402
static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals,
403403
const ModuleSummaryIndex &Index) {
404-
std::vector<GlobalValue *> ReplacedGlobals;
404+
std::vector<GlobalValue*> DeadGVs;
405405
for (auto &GV : Mod.global_values())
406406
if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID()))
407-
if (!Index.isGlobalValueLive(GVS) && !convertToDeclaration(GV))
408-
ReplacedGlobals.push_back(&GV);
409-
410-
for (GlobalValue *GV : ReplacedGlobals)
411-
GV->eraseFromParent();
407+
if (!Index.isGlobalValueLive(GVS)) {
408+
DeadGVs.push_back(&GV);
409+
convertToDeclaration(GV);
410+
}
411+
412+
// Now that all dead bodies have been dropped, delete the actual objects
413+
// themselves when possible.
414+
for (GlobalValue *GV : DeadGVs) {
415+
GV->removeDeadConstantUsers();
416+
// Might reference something defined in native object (i.e. dropped a
417+
// non-prevailing IR def, but we need to keep the declaration).
418+
if (GV->use_empty())
419+
GV->eraseFromParent();
420+
}
412421
}
413422

414423
Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,

‎llvm/test/ThinLTO/X86/deadstrip.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
; LTO2: define internal void @_GLOBAL__I_a()
5151
; LTO2: define internal void @bar() {
5252
; LTO2: define internal void @bar_internal()
53-
; LTO2: declare dso_local void @dead_func()
53+
; LTO2-NOT: @dead_func()
5454
; LTO2-NOT: available_externally {{.*}} @baz()
5555

5656
; Make sure we didn't internalize @boo, which is reachable via
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
; REQUIRES: x86-registered-target
2+
3+
; RUN: opt -module-summary %s -o %t.bc
4+
5+
; Tests that with dead stripping in the thin link enabled (default), we do not
6+
; promote to target of the dropped dead symbol _ZL3foov. This can happen with a
7+
; sample profile collected for one binary used to optimize for another binary.
8+
; RUN: llvm-lto2 run -save-temps -o %t2 %t.bc -r %t.bc,fptr,plx \
9+
; RUN: -r %t.bc,main,plx -r %t.bc,_ZL3foov,l
10+
; RUN: llvm-dis < %t2.1.4.opt.bc | FileCheck %s --check-prefix=OPT
11+
; RUN: llvm-lto2 run -save-temps -o %t2 %t.bc -r %t.bc,fptr,plx \
12+
; RUN: -r %t.bc,main,plx -r %t.bc,_ZL3foov,l -compute-dead=false
13+
; RUN: llvm-dis < %t2.1.4.opt.bc | FileCheck %s --check-prefix=OPT-NODEAD
14+
15+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
16+
target triple = "x86_64-unknown-linux-gnu"
17+
18+
@fptr = local_unnamed_addr global void ()* null, align 8
19+
20+
define void @_ZL3foov() #1 {
21+
entry:
22+
ret void
23+
}
24+
25+
define i32 @main() local_unnamed_addr #0 !prof !34 {
26+
entry:
27+
%0 = load void ()*, void ()** @fptr, align 8
28+
; OPT-NOT: label %if.false.orig_indirect
29+
; OPT-NODEAD: br i1 %{{[0-9]+}}, label %if.end.icp, label %if.false.orig_indirect
30+
tail call void %0(), !prof !40
31+
ret i32 0
32+
}
33+
34+
!llvm.dbg.cu = !{!0}
35+
!llvm.module.flags = !{!3,!4}
36+
!llvm.ident = !{!31}
37+
38+
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 5.0.0 (trunk 297016)", isOptimized: true, runtimeVersion: 0, emissionKind: NoDebug, enums: !2)
39+
!1 = !DIFile(filename: "main.cc", directory: ".")
40+
!2 = !{}
41+
!3 = !{i32 2, !"Debug Info Version", i32 3}
42+
!4 = !{i32 1, !"ProfileSummary", !5}
43+
!5 = !{!6, !7, !8, !9, !10, !11, !12, !13}
44+
!6 = !{!"ProfileFormat", !"SampleProfile"}
45+
!7 = !{!"TotalCount", i64 3003}
46+
!8 = !{!"MaxCount", i64 3000}
47+
!9 = !{!"MaxInternalCount", i64 0}
48+
!10 = !{!"MaxFunctionCount", i64 0}
49+
!11 = !{!"NumCounts", i64 3}
50+
!12 = !{!"NumFunctions", i64 1}
51+
!13 = !{!"DetailedSummary", !14}
52+
!14 = !{!15, !16, !17, !18, !19, !20, !20, !21, !21, !22, !23, !24, !25, !26, !27, !28, !29, !30}
53+
!15 = !{i32 10000, i64 3000, i32 1}
54+
!16 = !{i32 100000, i64 3000, i32 1}
55+
!17 = !{i32 200000, i64 3000, i32 1}
56+
!18 = !{i32 300000, i64 3000, i32 1}
57+
!19 = !{i32 400000, i64 3000, i32 1}
58+
!20 = !{i32 500000, i64 3000, i32 1}
59+
!21 = !{i32 600000, i64 3000, i32 1}
60+
!22 = !{i32 700000, i64 3000, i32 1}
61+
!23 = !{i32 800000, i64 3000, i32 1}
62+
!24 = !{i32 900000, i64 3000, i32 1}
63+
!25 = !{i32 950000, i64 3000, i32 1}
64+
!26 = !{i32 990000, i64 3000, i32 1}
65+
!27 = !{i32 999000, i64 3000, i32 1}
66+
!28 = !{i32 999900, i64 2, i32 2}
67+
!29 = !{i32 999990, i64 2, i32 2}
68+
!30 = !{i32 999999, i64 2, i32 2}
69+
!31 = !{!"clang version 5.0.0 (trunk 297016)"}
70+
!34 = !{!"function_entry_count", i64 1}
71+
!40 = !{!"VP", i32 0, i64 3000, i64 -8789629626369651636, i64 3000}

‎llvm/test/tools/gold/X86/global_with_section.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ target triple = "x86_64-unknown-linux-gnu"
4747
; the expected internalization.
4848
; CHECK-REGULARLTO-DAG: @var_with_nonC_section = internal global i32 0, section ".nonCsection"
4949
; Check we dropped definition of dead variable.
50-
; CHECK-THINLTO-DAG: @var_with_nonC_section = external dso_local global i32, section ".nonCsection"
50+
; CHECK-THINLTO-NOT: @var_with_nonC_section
5151
@var_with_nonC_section = global i32 0, section ".nonCsection"
5252

5353
; We should not internalize @deadfunc_with_section due to section
@@ -61,7 +61,7 @@ define void @deadfunc_with_section() section "some_other_section" {
6161
; the expected internalization.
6262
; CHECK2-REGULARLTO-DAG: define internal void @deadfunc_with_nonC_section() section ".nonCsection"
6363
; Check dead function converted to declaration.
64-
; CHECK-THINLTO-DAG: declare dso_local void @deadfunc_with_nonC_section() section ".nonCsection"
64+
; CHECK-THINLTO-NOT: @deadfunc_with_nonC_section()
6565
define void @deadfunc_with_nonC_section() section ".nonCsection" {
6666
call void @deadfunc2_called_from_nonC_section()
6767
ret void
@@ -80,5 +80,5 @@ declare void @deadfunc2_called_from_section()
8080
; are getting the expected internalization.
8181
; CHECK2-REGULARLTO: define internal void @deadfunc2_called_from_nonC_section
8282
; Check dead function converted to declaration.
83-
; CHECK2-THINLTO: declare dso_local void @deadfunc2_called_from_nonC_section
83+
; CHECK2-THINLTO-NOT: @deadfunc2_called_from_nonC_section
8484
declare void @deadfunc2_called_from_nonC_section()

0 commit comments

Comments
 (0)
Please sign in to comment.