Skip to content

Commit 7bbbe5b

Browse files
teresajohnsonaokblast
authored andcommitted
[WPD] Reduce ThinLTO link time by avoiding unnecessary summary analysis (llvm#164046)
We are scanning through every single definition of a vtable across all translation units which is unnecessary in most cases. If this is a local, we want to make sure there isn't another local with the same GUID due to it having the same relative path. However, we were always scanning through every single summary in all cases. We can now check the new HasLocal flag added in PR164647 ahead of the loop, instead of checking on every iteration. This cut down a large thin link by around 6%, which was over half the time it spent in WPD. Note that we previously took the last conforming vtable summary, and now we use the first. This caused a test difference in one somewhat contrived test for vtables in comdats.
1 parent dfce7d9 commit 7bbbe5b

File tree

3 files changed

+17
-11
lines changed

3 files changed

+17
-11
lines changed

llvm/include/llvm/IR/ModuleSummaryIndex.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,8 @@ struct alignas(8) GlobalValueSummaryInfo {
178178
/// only be called prior to index-based internalization and promotion.
179179
inline void verifyLocal() const;
180180

181+
bool hasLocal() const { return HasLocal; }
182+
181183
private:
182184
/// List of global value summary structures for a particular value held
183185
/// in the GlobalValueMap. Requires a vector in the case of multiple
@@ -239,6 +241,8 @@ struct ValueInfo {
239241

240242
void verifyLocal() const { getRef()->second.verifyLocal(); }
241243

244+
bool hasLocal() const { return getRef()->second.hasLocal(); }
245+
242246
// Even if the index is built with GVs available, we may not have one for
243247
// summary entries synthesized for profiled indirect call targets.
244248
bool hasName() const { return !haveGVs() || getValue(); }

llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1161,14 +1161,10 @@ bool DevirtIndex::tryFindVirtualCallTargets(
11611161
// and therefore the same GUID. This can happen if there isn't enough
11621162
// distinguishing path when compiling the source file. In that case we
11631163
// conservatively return false early.
1164+
if (P.VTableVI.hasLocal() && P.VTableVI.getSummaryList().size() > 1)
1165+
return false;
11641166
const GlobalVarSummary *VS = nullptr;
1165-
bool LocalFound = false;
11661167
for (const auto &S : P.VTableVI.getSummaryList()) {
1167-
if (GlobalValue::isLocalLinkage(S->linkage())) {
1168-
if (LocalFound)
1169-
return false;
1170-
LocalFound = true;
1171-
}
11721168
auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
11731169
if (!CurVS->vTableFuncs().empty() ||
11741170
// Previously clang did not attach the necessary type metadata to
@@ -1184,6 +1180,7 @@ bool DevirtIndex::tryFindVirtualCallTargets(
11841180
// with public LTO visibility.
11851181
if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic)
11861182
return false;
1183+
break;
11871184
}
11881185
}
11891186
// There will be no VS if all copies are available_externally having no
@@ -2591,6 +2588,11 @@ void DevirtIndex::run() {
25912588
if (ExportSummary.typeIdCompatibleVtableMap().empty())
25922589
return;
25932590

2591+
// Assert that we haven't made any changes that would affect the hasLocal()
2592+
// flag on the GUID summary info.
2593+
assert(!ExportSummary.withInternalizeAndPromote() &&
2594+
"Expect index-based WPD to run before internalization and promotion");
2595+
25942596
DenseMap<GlobalValue::GUID, std::vector<StringRef>> NameByGUID;
25952597
for (const auto &P : ExportSummary.typeIdCompatibleVtableMap()) {
25962598
NameByGUID[GlobalValue::getGUIDAssumingExternalLinkage(P.first)].push_back(

llvm/test/ThinLTO/X86/devirt_external_comdat_same_guid.ll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
; RUN: llvm-dis %t5.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR1
2525
; RUN: llvm-dis %t5.2.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR2
2626

27-
; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1A1nEi)
27+
; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1B1nEi)
2828

29-
; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
29+
; REMARK-DAG: single-impl: devirtualized a call to _ZN1B1nEi
3030

3131
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
3232
target triple = "x86_64-grtev4-linux-gnu"
@@ -55,7 +55,7 @@ entry:
5555
ret i32 0
5656
}
5757

58-
; CHECK-IR1: define i32 @test(
58+
; CHECK-IR1: define noundef i32 @test(
5959
define i32 @test(ptr %obj, i32 %a) {
6060
entry:
6161
%vtable = load ptr, ptr %obj
@@ -65,15 +65,15 @@ entry:
6565
%fptr1 = load ptr, ptr %fptrptr, align 8
6666

6767
; Check that the call was devirtualized.
68-
; CHECK-IR1: tail call i32 {{.*}}@_ZN1A1nEi
68+
; CHECK-IR1: tail call i32 {{.*}}@_ZN1B1nEi
6969
%call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a)
7070

7171
ret i32 %call
7272
}
7373

7474
; CHECK-IR2: define i32 @test2
7575
; Check that the call was devirtualized.
76-
; CHECK-IR2: tail call i32 @_ZN1A1nEi
76+
; CHECK-IR2: tail call i32 @_ZN1B1nEi
7777

7878
declare i1 @llvm.type.test(ptr, metadata)
7979
declare void @llvm.assume(i1)

0 commit comments

Comments
 (0)