[PATCH] D108741: [GlobalDCE] Handle non-vfunc entries in vtables during VFE (for Swift vtables)

Kuba (Brecka) Mracek via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 25 16:16:29 PDT 2021


kubamracek created this revision.
kubamracek added reviewers: yln, manmanren, pcc, tejohnson, mehdi_amini, ab, jckarter, fhahn.
kubamracek added a project: LLVM.
kubamracek requested review of this revision.

As part of codesize optimization work for Swift, we'd like to add Virtual Function Elimination to Swift, very similarly to how GlobalDCE supports C++ VFE. This PR adds support to GlobalDCE for vtables containing references that are not virtual functions and should not participate in VFE. The PR extends GlobalDCE's logic that ignores vtable->vfunc dependencies to only apply when the vtable slot offset is present in one of the !type metadata attributes on the vtable.

See added test for an example of this.


https://reviews.llvm.org/D108741

Files:
  llvm/lib/Transforms/IPO/GlobalDCE.cpp
  llvm/test/Transforms/GlobalDCE/virtual-functions-non-vfunc-entries.ll


Index: llvm/test/Transforms/GlobalDCE/virtual-functions-non-vfunc-entries.ll
===================================================================
--- /dev/null
+++ llvm/test/Transforms/GlobalDCE/virtual-functions-non-vfunc-entries.ll
@@ -0,0 +1,47 @@
+; RUN: opt < %s -globaldce -S | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
+
+; A vtable that contains a non-nfunc entry, @regular_non_virtual_func, which should not participate in VFE.
+ at vtable = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [
+  i8* bitcast (void ()* @vfunc1_live to i8*),
+  i8* bitcast (void ()* @vfunc2_dead to i8*),
+  i8* bitcast (void ()* @regular_non_virtual_func to i8*)
+]}, align 8, !type !0, !type !1, !vcall_visibility !{i64 2}
+!0 = !{i64 0, !"vfunc1.type"}
+!1 = !{i64 8, !"vfunc2.type"}
+
+; CHECK:      @vtable = internal unnamed_addr constant { [3 x i8*] } { [3 x i8*] [
+; CHECK-SAME:   i8* bitcast (void ()* @vfunc1_live to i8*),
+; CHECK-SAME:   i8* null,
+; CHECK-SAME:   i8* bitcast (void ()* @regular_non_virtual_func to i8*)
+; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
+
+; (1) vfunc1_live is referenced from @main, stays alive
+define internal void @vfunc1_live() {
+  ; CHECK: define internal void @vfunc1_live(
+  ret void
+}
+
+; (2) vfunc2_dead is never referenced, gets removed and vtable slot is null'd
+define internal void @vfunc2_dead() {
+  ; CHECK-NOT: define internal void @vfunc2_dead(
+  ret void
+}
+
+; (3) regular, non-virtual function that just happens to be referenced from the vtable data structure, should stay alive
+define internal void @regular_non_virtual_func() {
+  ; CHECK: define internal void @regular_non_virtual_func(
+  ret void
+}
+
+define void @main() {
+  %1 = ptrtoint { [3 x i8*] }* @vtable to i64 ; to keep @vtable alive
+  %2 = tail call { i8*, i1 } @llvm.type.checked.load(i8* null, i32 0, metadata !"vfunc1.type")
+  ret void
+}
+
+!999 = !{i32 1, !"Virtual Function Elim", i32 1}
+!llvm.module.flags = !{!999}
Index: llvm/lib/Transforms/IPO/GlobalDCE.cpp
===================================================================
--- llvm/lib/Transforms/IPO/GlobalDCE.cpp
+++ llvm/lib/Transforms/IPO/GlobalDCE.cpp
@@ -131,11 +131,39 @@
     // complete information about all virtual call sites which could call
     // though this vtable, then skip it, because the call site information will
     // be more precise.
+    bool IgnoreDependency = false;
+
     if (VFESafeVTables.count(GVU) && isa<Function>(&GV)) {
+      // Scan the !type metadata on the vtable and only ignore those deps that
+      // have an offset in one of the !type entries.
+      if (auto *VTable = dyn_cast<GlobalVariable>(GVU)) {
+        SmallVector<MDNode *, 2> Types;
+        VTable->getMetadata(LLVMContext::MD_type, Types);
+        if (!VTable->isDeclaration() && !Types.empty()) {
+          for (MDNode *Type : Types) {
+            uint64_t OffsetInType =
+                cast<ConstantInt>(
+                    cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
+                    ->getZExtValue();
+            Constant *Ptr =
+                getPointerAtOffset(VTable->getInitializer(), OffsetInType,
+                                   *VTable->getParent());
+            Ptr = Ptr ? Ptr->stripPointerCasts() : nullptr;
+            if (Ptr == &GV) {
+              IgnoreDependency = true;
+              break;
+            }
+          }
+        }
+      }
+    }
+
+    if (IgnoreDependency) {
       LLVM_DEBUG(dbgs() << "Ignoring dep " << GVU->getName() << " -> "
                         << GV.getName() << "\n");
       continue;
     }
+
     GVDependencies[GVU].insert(&GV);
   }
 }


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D108741.368772.patch
Type: text/x-patch
Size: 3767 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210825/4a8734cb/attachment.bin>


More information about the llvm-commits mailing list