[llvm] [WPD] Dereference `GlobalAlias` targets (PR #215880)

Mircea Trofin via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 12 13:17:45 PDT 2026


https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/215880

>From a51959d49c33247e41b68baef92b01cf3b9a4794 Mon Sep 17 00:00:00 2001
From: Mircea Trofin <mtrofin at google.com>
Date: Wed, 12 Aug 2026 13:02:03 -0700
Subject: [PATCH] [WPD] Dereference `GlobalAlias` targets

---
 .../lib/Transforms/IPO/WholeProgramDevirt.cpp | 13 ++--
 .../ThinLTO/X86/devirt-alias-attributes.ll    | 53 +++++++++++++++
 .../ThinLTO/X86/devirt-alias-cross-module.ll  | 65 +++++++++++++++++++
 .../ThinLTO/X86/devirt_function_alias2.ll     |  8 ++-
 4 files changed, 132 insertions(+), 7 deletions(-)
 create mode 100644 llvm/test/ThinLTO/X86/devirt-alias-attributes.ll
 create mode 100644 llvm/test/ThinLTO/X86/devirt-alias-cross-module.ll

diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
index 0c8b2aa7078c2..6d37730f2d594 100644
--- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
+++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp
@@ -1147,6 +1147,8 @@ bool DevirtModule::tryFindVirtualCallTargets(
     // target.
     auto *GV = dyn_cast<GlobalValue>(C);
     assert(GV);
+    if (auto *GA = dyn_cast<GlobalAlias>(GV))
+      GV = GA->getAliaseeObject();
     TargetsForSlot.push_back({GV, &TM});
   }
 
@@ -2261,10 +2263,13 @@ void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) {
     assert(!Res.SingleImplName.empty());
     // The type of the function in the declaration is irrelevant because every
     // call site will cast it to the correct type.
-    Constant *SingleImpl =
-        cast<Constant>(M.getOrInsertFunction(Res.SingleImplName,
-                                             Type::getVoidTy(M.getContext()))
-                           .getCallee());
+    Value *SingleImplVal =
+        M.getOrInsertFunction(Res.SingleImplName,
+                              Type::getVoidTy(M.getContext()))
+            .getCallee();
+    if (auto *A = dyn_cast<GlobalAlias>(SingleImplVal->stripPointerCasts()))
+      SingleImplVal = A->getAliaseeObject();
+    Constant *SingleImpl = cast<Constant>(SingleImplVal);
 
     // This is the import phase so we should not be exporting anything.
     bool IsExported = false;
diff --git a/llvm/test/ThinLTO/X86/devirt-alias-attributes.ll b/llvm/test/ThinLTO/X86/devirt-alias-attributes.ll
new file mode 100644
index 0000000000000..3bac59ada2638
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/devirt-alias-attributes.ll
@@ -0,0 +1,53 @@
+; REQUIRES: x86-registered-target
+
+;; Check that successful devirtualization to an alias allows constant propagation
+;; and attribute deduction for the caller.
+
+;; Generate split module with summary for hybrid Thin/Regular LTO WPD.
+; RUN: opt -passes=assign-guid -thinlto-bc -thinlto-split-lto-unit -o %t.o %s
+
+; RUN: llvm-lto2 run %t.o -save-temps \
+; RUN:   -whole-program-visibility \
+; RUN:   -o %t2 \
+; RUN:   -r=%t.o,test,px \
+; RUN:   -r=%t.o,_ZTV1D, \
+; RUN:   -r=%t.o,_ZTV1D,px \
+; RUN:   -r=%t.o,_ZN1D1mEi,px \
+; RUN:   -r=%t.o,_ZN1D1mEiAlias,px \
+; RUN:   -r=%t.o,_ZN1D1mEiAlias,
+; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
+
+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"
+
+%struct.D = type { ptr }
+
+ at _ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr poison, ptr @_ZN1D1mEiAlias] }, !type !3
+
+;; The aliasee has NO optnone or noinline, permitting IPSCCP to fold ret i32 0.
+define i32 @_ZN1D1mEi(ptr %this, i32 %a) {
+   ret i32 0
+}
+
+ at _ZN1D1mEiAlias = hidden unnamed_addr alias i32 (ptr, i32), ptr @_ZN1D1mEi
+
+; CHECK-IR-LABEL: define noundef i32 @test
+define i32 @test(ptr %obj2, i32 %a) {
+entry:
+  %vtable2 = load ptr, ptr %obj2
+  %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !"_ZTS1D")
+  call void @llvm.assume(i1 %p2)
+
+  %fptr33 = load ptr, ptr %vtable2, align 8
+
+  ;; Check that the call was devirtualized and folded to 0, granting @test noundef.
+  ;; CHECK-IR-NOT: tail call
+  ;; CHECK-IR: ret i32 0
+  %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %a)
+  ret i32 %call4
+}
+
+declare i1 @llvm.type.test(ptr, metadata)
+declare void @llvm.assume(i1)
+
+!3 = !{i64 16, !"_ZTS1D"}
diff --git a/llvm/test/ThinLTO/X86/devirt-alias-cross-module.ll b/llvm/test/ThinLTO/X86/devirt-alias-cross-module.ll
new file mode 100644
index 0000000000000..7bc0da0e6c48b
--- /dev/null
+++ b/llvm/test/ThinLTO/X86/devirt-alias-cross-module.ll
@@ -0,0 +1,65 @@
+; RUN: rm -rf %t && split-file %s %t
+; REQUIRES: x86-registered-target
+
+;; Check for successful devirtualization across ThinLTO modules when vtable 
+;; contains an alias. Ensures the ThinLTO index step properly connects the alias 
+;; to the aliasee, allowing importing and devirtualization in the caller's backend.
+
+; RUN: opt -passes=assign-guid -thinlto-bc -o %t_caller.o %t/caller.ll
+; RUN: opt -passes=assign-guid -thinlto-bc -o %t_callee.o %t/callee.ll
+
+; RUN: llvm-lto2 run %t_caller.o %t_callee.o -save-temps -pass-remarks=. \
+; RUN:   -whole-program-visibility \
+; RUN:   -wholeprogramdevirt-print-index-based \
+; RUN:   -o %t_out \
+; RUN:   -r=%t_caller.o,test,px \
+; RUN:   -r=%t_callee.o,_ZTV1D,px \
+; RUN:   -r=%t_callee.o,_ZN1D1mEi,px \
+; RUN:   -r=%t_callee.o,_ZN1D1mEiAlias,px \
+; RUN:   2>&1 | FileCheck %s --check-prefix=REMARK --check-prefix=PRINT
+; RUN: llvm-dis %t_out.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR
+
+; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1D1mEiAlias)
+; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
+
+;--- caller.ll
+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"
+
+%struct.D = type { ptr }
+
+; CHECK-IR-LABEL: define i32 @test
+define i32 @test(ptr %obj2, i32 %a) {
+entry:
+  %vtable2 = load ptr, ptr %obj2
+  %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !"_ZTS1D")
+  call void @llvm.assume(i1 %p2)
+
+  %fptr33 = load ptr, ptr %vtable2, align 8
+
+  ;; Check that the cross-module call was successfully devirtualized to the aliasee.
+  ;; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi
+  %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %a)
+  ret i32 %call4
+}
+
+declare i1 @llvm.type.test(ptr, metadata)
+declare void @llvm.assume(i1)
+
+;--- callee.ll
+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"
+
+%struct.D = type { ptr }
+
+ at _ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr poison, ptr @_ZN1D1mEiAlias] }, !type !3
+
+define i32 @_ZN1D1mEi(ptr %this, i32 %a) #0 {
+   ret i32 0;
+}
+
+ at _ZN1D1mEiAlias = hidden unnamed_addr alias i32 (ptr, i32), ptr @_ZN1D1mEi
+
+attributes #0 = { noinline optnone }
+
+!3 = !{i64 16, !"_ZTS1D"}
diff --git a/llvm/test/ThinLTO/X86/devirt_function_alias2.ll b/llvm/test/ThinLTO/X86/devirt_function_alias2.ll
index 3b3208e300aa8..d460aeda80df4 100644
--- a/llvm/test/ThinLTO/X86/devirt_function_alias2.ll
+++ b/llvm/test/ThinLTO/X86/devirt_function_alias2.ll
@@ -25,7 +25,7 @@
 ; RUN: llvm-dis %t2.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR1
 
 ; PRINT-DAG: Devirtualized call to {{.*}} (_ZN1D1mEiAlias)
-; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEiAlias
+; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi
 
 ;; Test hybrid Thin/Regular LTO
 
@@ -63,13 +63,15 @@ target triple = "x86_64-grtev4-linux-gnu"
 
 @_ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr undef, ptr @_ZN1D1mEiAlias] }, !type !3
 
-define i32 @_ZN1D1mEi(ptr %this, i32 %a) {
+define i32 @_ZN1D1mEi(ptr %this, i32 %a) #0 {
    ret i32 0;
 }
 
 @_ZN1D1mEiAlias = unnamed_addr alias i32 (ptr, i32), ptr @_ZN1D1mEi
 
-; CHECK-IR1-LABEL: define i32 @test
+attributes #0 = { noinline optnone }
+
+; CHECK-IR1-LABEL: define {{.*}}i32 @test
 define i32 @test(ptr %obj2, i32 %a) {
 entry:
   %vtable2 = load ptr, ptr %obj2



More information about the llvm-commits mailing list