llvm.org GIT mirror llvm / 27deee6
[ThinLTO/WPD] Ensure devirtualized targets use promoted symbol when necessary Summary: This fixes a hole in the handling of devirtualized targets that were local but need promoting due to devirtualization in another module. We were not correctly referencing the promoted symbol in some cases. Make sure the code that updates the name also looks at the ExportedGUIDs set by utilizing a callback that checks all conditions (the callback utilized by the internalization/promotion code). Reviewers: pcc, davidxl, hiraditya Subscribers: mehdi_amini, Prazek, inglorion, steven_wu, dexonsmith, dang, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D68159 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@373485 91177308-0d34-0410-b5e6-96231b3b80d8 Teresa Johnson 1 year, 2 months ago
5 changed file(s) with 120 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
250250 /// devirt target names for any locals that were exported.
251251 void updateIndexWPDForExports(
252252 ModuleSummaryIndex &Summary,
253 StringMap &ExportLists,
253 function_ref isExported,
254254 std::map> &LocalWPDTargetsMap);
255255
256256 } // end namespace llvm
13031303 ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
13041304 ImportLists, ExportLists);
13051305
1306 // Update local devirtualized targets that were exported by cross-module
1307 // importing
1308 updateIndexWPDForExports(ThinLTO.CombinedIndex, ExportLists,
1309 LocalWPDTargetsMap);
1310
13111306 // Figure out which symbols need to be internalized. This also needs to happen
13121307 // at -O0 because summary-based DCE is implemented using internalization, and
13131308 // we must apply DCE consistently with the full LTO module in order to avoid
13371332 ExportList->second.count(GUID)) ||
13381333 ExportedGUIDs.count(GUID);
13391334 };
1335
1336 // Update local devirtualized targets that were exported by cross-module
1337 // importing or by other devirtualizations marked in the ExportedGUIDs set.
1338 updateIndexWPDForExports(ThinLTO.CombinedIndex, isExported,
1339 LocalWPDTargetsMap);
1340
13401341 auto isPrevailing = [&](GlobalValue::GUID GUID,
13411342 const GlobalValueSummary *S) {
13421343 return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();
712712
713713 void updateIndexWPDForExports(
714714 ModuleSummaryIndex &Summary,
715 StringMap &ExportLists,
715 function_ref isExported,
716716 std::map> &LocalWPDTargetsMap) {
717717 for (auto &T : LocalWPDTargetsMap) {
718718 auto &VI = T.first;
720720 assert(VI.getSummaryList().size() == 1 &&
721721 "Devirt of local target has more than one copy");
722722 auto &S = VI.getSummaryList()[0];
723 const auto &ExportList = ExportLists.find(S->modulePath());
724 if (ExportList == ExportLists.end() ||
725 !ExportList->second.count(VI.getGUID()))
723 if (!isExported(S->modulePath(), VI.getGUID()))
726724 continue;
727725
728726 // It's been exported by a cross module import.
0 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
1 target triple = "x86_64-grtev4-linux-gnu"
2
3 %struct.A = type { i32 (...)** }
4 %struct.B = type { %struct.A }
5
6 @_ZTV1B = 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
7
8 define i32 @_ZN1B1fEi(%struct.B* %this, i32 %a) #0 {
9 ret i32 0;
10 }
11
12 define internal i32 @_ZN1A1nEi(%struct.A* %this, i32 %a) #0 {
13 ret i32 0;
14 }
15
16 define i32 @test2(%struct.B* %obj, i32 %a) {
17 entry:
18 %0 = bitcast %struct.B* %obj to i8***
19 %vtable2 = load i8**, i8*** %0
20 %1 = bitcast i8** %vtable2 to i8*
21 %p2 = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1B")
22 call void @llvm.assume(i1 %p2)
23
24 %fptrptr = getelementptr i8*, i8** %vtable2, i32 1
25 %2 = bitcast i8** %fptrptr to i32 (%struct.B*, i32)**
26 %fptr33 = load i32 (%struct.B*, i32)*, i32 (%struct.B*, i32)** %2, align 8
27
28 %call4 = tail call i32 %fptr33(%struct.B* nonnull %obj, i32 %a)
29 ret i32 %call4
30 }
31
32 attributes #0 = { noinline optnone }
33
34 declare i1 @llvm.type.test(i8*, metadata)
35 declare void @llvm.assume(i1)
36
37 !0 = !{i64 16, !"_ZTS1A"}
38 !1 = !{i64 16, !"_ZTS1B"}
0 ; REQUIRES: x86-registered-target
1
2 ; Test devirtualization requiring promotion of local targets, where the
3 ; promotion is required by one devirtualization and needs to be updated
4 ; for a second devirtualization in the defining module as a post-pass
5 ; update.
6
7 ; Generate unsplit module with summary for ThinLTO index-based WPD.
8 ; RUN: opt -thinlto-bc -o %t3.o %s
9 ; RUN: opt -thinlto-bc -o %t4.o %p/Inputs/devirt_promote.ll
10
11 ; RUN: llvm-lto2 run %t3.o %t4.o -save-temps -use-new-pm -pass-remarks=. \
12 ; RUN: -wholeprogramdevirt-print-index-based \
13 ; RUN: -o %t5 \
14 ; RUN: -r=%t3.o,test,px \
15 ; RUN: -r=%t4.o,_ZN1B1fEi,p \
16 ; RUN: -r=%t4.o,test2,px \
17 ; RUN: -r=%t4.o,_ZTV1B,px \
18 ; RUN: 2>&1 | FileCheck %s --check-prefix=REMARK --check-prefix=PRINT
19 ; RUN: llvm-dis %t5.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR1
20 ; RUN: llvm-dis %t5.2.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR2
21 ; RUN: llvm-nm %t5.1 | FileCheck %s --check-prefix=NM-INDEX1
22 ; RUN: llvm-nm %t5.2 | FileCheck %s --check-prefix=NM-INDEX2
23
24 ; NM-INDEX1: U _ZN1A1nEi.llvm.
25
26 ; Make sure that not only did _ZN1A1nEi get promoted (due to the
27 ; devirtualization in the other module) but the reference due to the
28 ; devirtualization in its defining module should be to the promoted
29 ; symbol.
30 ; NM-INDEX2-NOT: U _ZN1A1nEi
31 ; NM-INDEX2: T _ZN1A1nEi.llvm.
32 ; NM-INDEX2-NOT: U _ZN1A1nEi
33
34 ; We should devirt call to _ZN1A1nEi once in importing module and once
35 ; in original (exporting) module.
36 ; REMARK-COUNT-2: single-impl: devirtualized a call to _ZN1A1nEi.llvm.
37
38 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
39 target triple = "x86_64-grtev4-linux-gnu"
40
41 %struct.A = type { i32 (...)** }
42
43 ; CHECK-IR1-LABEL: define i32 @test
44 define i32 @test(%struct.A* %obj, i32 %a) {
45 entry:
46 %0 = bitcast %struct.A* %obj to i8***
47 %vtable = load i8**, i8*** %0
48 %1 = bitcast i8** %vtable to i8*
49 %p = call i1 @llvm.type.test(i8* %1, metadata !"_ZTS1A")
50 call void @llvm.assume(i1 %p)
51 %fptrptr = getelementptr i8*, i8** %vtable, i32 1
52 %2 = bitcast i8** %fptrptr to i32 (%struct.A*, i32)**
53 %fptr1 = load i32 (%struct.A*, i32)*, i32 (%struct.A*, i32)** %2, align 8
54
55 ; Check that the call was devirtualized.
56 ; CHECK-IR1: %call = tail call i32 bitcast (void ()* @_ZN1A1nEi
57 %call = tail call i32 %fptr1(%struct.A* nonnull %obj, i32 %a)
58
59 ret i32 %call
60 }
61 ; CHECK-IR1-LABEL: ret i32
62 ; CHECK-IR1-LABEL: }
63
64 ; CHECK-IR2: define i32 @test2
65 ; Check that the call was devirtualized.
66 ; CHECK-IR2: %call4 = tail call i32 @_ZN1A1nEi
67
68 declare i1 @llvm.type.test(i8*, metadata)
69 declare void @llvm.assume(i1)
70
71 attributes #0 = { noinline optnone }