[llvm] [WPD] Reduce ThinLTO link time by avoiding unnecessary summary analysis (PR #164046)
Mingming Liu via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 17 23:26:14 PDT 2025
https://github.com/mingmingl-llvm updated https://github.com/llvm/llvm-project/pull/164046
>From 26f6ae2b676b3aa2854f711f30695fc7d018a8a9 Mon Sep 17 00:00:00 2001
From: Teresa Johnson <tejohnson at google.com>
Date: Fri, 17 Oct 2025 19:58:54 -0700
Subject: [PATCH 1/2] [WPD] Reduce ThinLTO link time by avoiding unnecessary
summary analysis
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 shouldn't have locals and non-locals with the same GUID since local
GUIDs are computed from "path:name" and non-locals from just "name". So
once we find a non-local vtable summary meeting the other constraints we
can just use it.
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.
---
llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 10 +++++++++-
.../ThinLTO/X86/devirt_external_comdat_same_guid.ll | 10 +++++-----
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index 2d5cb8268ffdd..e37e0d3142224 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1142,7 +1142,11 @@ bool DevirtIndex::tryFindVirtualCallTargets(
if (LocalFound)
return false;
LocalFound = true;
- }
+ } else
+ // Don't expect to find a mix of locals and non-locals (due to path
+ // prefix for locals one should never have the same GUID as a
+ // non-local).
+ assert(!LocalFound);
auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
if (!CurVS->vTableFuncs().empty() ||
// Previously clang did not attach the necessary type metadata to
@@ -1158,6 +1162,10 @@ bool DevirtIndex::tryFindVirtualCallTargets(
// with public LTO visibility.
if (VS->getVCallVisibility() == GlobalObject::VCallVisibilityPublic)
return false;
+ // Unless VS is a local, we don't need to keep looking through the rest
+ // of the summaries.
+ if (!LocalFound)
+ break;
}
}
// There will be no VS if all copies are available_externally having no
diff --git a/llvm/test/ThinLTO/X86/devirt_external_comdat_same_guid.ll b/llvm/test/ThinLTO/X86/devirt_external_comdat_same_guid.ll
index 1f0737b719254..d0b8d14777f52 100644
--- a/llvm/test/ThinLTO/X86/devirt_external_comdat_same_guid.ll
+++ b/llvm/test/ThinLTO/X86/devirt_external_comdat_same_guid.ll
@@ -24,9 +24,9 @@
; RUN: llvm-dis %t5.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR1
; RUN: llvm-dis %t5.2.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR2
-; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1A1nEi)
+; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1B1nEi)
-; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi
+; REMARK-DAG: single-impl: devirtualized a call to _ZN1B1nEi
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-grtev4-linux-gnu"
@@ -55,7 +55,7 @@ entry:
ret i32 0
}
-; CHECK-IR1: define i32 @test(
+; CHECK-IR1: define noundef i32 @test(
define i32 @test(ptr %obj, i32 %a) {
entry:
%vtable = load ptr, ptr %obj
@@ -65,7 +65,7 @@ entry:
%fptr1 = load ptr, ptr %fptrptr, align 8
; Check that the call was devirtualized.
- ; CHECK-IR1: tail call i32 {{.*}}@_ZN1A1nEi
+ ; CHECK-IR1: tail call i32 {{.*}}@_ZN1B1nEi
%call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a)
ret i32 %call
@@ -73,7 +73,7 @@ entry:
; CHECK-IR2: define i32 @test2
; Check that the call was devirtualized.
-; CHECK-IR2: tail call i32 @_ZN1A1nEi
+; CHECK-IR2: tail call i32 @_ZN1B1nEi
declare i1 @llvm.type.test(ptr, metadata)
declare void @llvm.assume(i1)
>From ef97725a4fcdc2559a4c6451d71898f40b7437fe Mon Sep 17 00:00:00 2001
From: Mingming Liu <minglotus6 at gmail.com>
Date: Fri, 17 Oct 2025 23:26:06 -0700
Subject: [PATCH 2/2] Use braces around else given the multi-line comment
before assert
---
llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index e37e0d3142224..c2fd24dd4cdb9 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1142,11 +1142,12 @@ bool DevirtIndex::tryFindVirtualCallTargets(
if (LocalFound)
return false;
LocalFound = true;
- } else
+ } else {
// Don't expect to find a mix of locals and non-locals (due to path
// prefix for locals one should never have the same GUID as a
// non-local).
assert(!LocalFound);
+ }
auto *CurVS = cast<GlobalVarSummary>(S->getBaseObject());
if (!CurVS->vTableFuncs().empty() ||
// Previously clang did not attach the necessary type metadata to
More information about the llvm-commits
mailing list