[llvm] 7329abf - [GlobalDCE] In VFE, replace the whole 'sub' expression of unused relative-pointer-based vtable slots

Kuba Mracek via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 6 15:56:08 PDT 2021


Author: Kuba Mracek
Date: 2021-10-06T15:55:55-07:00
New Revision: 7329abf2f81a0432bd0a9e7dec0c55b692fc72e5

URL: https://github.com/llvm/llvm-project/commit/7329abf2f81a0432bd0a9e7dec0c55b692fc72e5
DIFF: https://github.com/llvm/llvm-project/commit/7329abf2f81a0432bd0a9e7dec0c55b692fc72e5.diff

LOG: [GlobalDCE] In VFE, replace the whole 'sub' expression of unused relative-pointer-based vtable slots

Differential Revision: https://reviews.llvm.org/D109114

Added: 
    llvm/test/Transforms/GlobalDCE/call-with-ptrtoint.ll

Modified: 
    llvm/include/llvm/Analysis/TypeMetadataUtils.h
    llvm/lib/Analysis/TypeMetadataUtils.cpp
    llvm/lib/Transforms/IPO/GlobalDCE.cpp
    llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll
    llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll
    llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Analysis/TypeMetadataUtils.h b/llvm/include/llvm/Analysis/TypeMetadataUtils.h
index 6ca112457b6f..074c40942b06 100644
--- a/llvm/include/llvm/Analysis/TypeMetadataUtils.h
+++ b/llvm/include/llvm/Analysis/TypeMetadataUtils.h
@@ -22,6 +22,7 @@ namespace llvm {
 class CallBase;
 class CallInst;
 class Constant;
+class Function;
 class DominatorTree;
 class Instruction;
 class Module;
@@ -56,25 +57,30 @@ void findDevirtualizableCallsForTypeCheckedLoad(
     SmallVectorImpl<Instruction *> &Preds, bool &HasNonCallUses,
     const CallInst *CI, DominatorTree &DT);
 
-// Processes a Constant recursively looking into elements of arrays, structs and
-// expressions to find a trivial pointer element that is located at the given
-// offset (relative to the beginning of the whole outer Constant).
-//
-// Used for example from GlobalDCE to find an entry in a C++ vtable that matches
-// a vcall offset.
-//
-// To support Swift vtables, getPointerAtOffset can see through "relative
-// pointers", i.e. (sub-)expressions of the form of:
-//
-//   @symbol = ... {
-//     i32 trunc (i64 sub (
-//       i64 ptrtoint (<type> @target to i64), i64 ptrtoint (... @symbol to i64)
-//     ) to i32)
-//   }
-//
-// For such (sub-)expressions, getPointerAtOffset returns the @target pointer.
+/// Processes a Constant recursively looking into elements of arrays, structs
+/// and expressions to find a trivial pointer element that is located at the
+/// given offset (relative to the beginning of the whole outer Constant).
+///
+/// Used for example from GlobalDCE to find an entry in a C++ vtable that
+/// matches a vcall offset.
+///
+/// To support Swift vtables, getPointerAtOffset can see through "relative
+/// pointers", i.e. (sub-)expressions of the form of:
+///
+/// @symbol = ... {
+///   i32 trunc (i64 sub (
+///     i64 ptrtoint (<type> @target to i64), i64 ptrtoint (... @symbol to i64)
+///   ) to i32)
+/// }
+///
+/// For such (sub-)expressions, getPointerAtOffset returns the @target pointer.
 Constant *getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
                              Constant *TopLevelGlobal = nullptr);
-}
+
+/// Finds the same "relative pointer" pattern as described above, where the
+/// target is `F`, and replaces the entire pattern with a constant zero.
+void replaceRelativePointerUsersWithZero(Function *F);
+
+} // namespace llvm
 
 #endif

diff  --git a/llvm/lib/Analysis/TypeMetadataUtils.cpp b/llvm/lib/Analysis/TypeMetadataUtils.cpp
index 65fa2bbcffd3..80051fd5f7c1 100644
--- a/llvm/lib/Analysis/TypeMetadataUtils.cpp
+++ b/llvm/lib/Analysis/TypeMetadataUtils.cpp
@@ -197,3 +197,20 @@ Constant *llvm::getPointerAtOffset(Constant *I, uint64_t Offset, Module &M,
   }
   return nullptr;
 }
+
+void llvm::replaceRelativePointerUsersWithZero(Function *F) {
+  for (auto *U : F->users()) {
+    auto *PtrExpr = dyn_cast<ConstantExpr>(U);
+    if (!PtrExpr || PtrExpr->getOpcode() != Instruction::PtrToInt)
+      continue;
+
+    for (auto *PtrToIntUser : PtrExpr->users()) {
+      auto *SubExpr = dyn_cast<ConstantExpr>(PtrToIntUser);
+      if (!SubExpr || SubExpr->getOpcode() != Instruction::Sub)
+        continue;
+
+      SubExpr->replaceNonMetadataUsesWith(
+          ConstantInt::get(SubExpr->getType(), 0));
+    }
+  }
+}

diff  --git a/llvm/lib/Transforms/IPO/GlobalDCE.cpp b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
index 018a594127f0..9977fa7904a0 100644
--- a/llvm/lib/Transforms/IPO/GlobalDCE.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
@@ -416,6 +416,16 @@ PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) {
       // virtual function pointers with null, allowing us to remove the
       // function itself.
       ++NumVFuncs;
+
+      // Detect vfuncs that are referenced as "relative pointers" which are used
+      // in Swift vtables, i.e. entries in the form of:
+      //
+      //   i32 trunc (i64 sub (i64 ptrtoint @f, i64 ptrtoint ...)) to i32)
+      //
+      // In this case, replace the whole "sub" expression with constant 0 to
+      // avoid leaving a weird sub(0, symbol) expression behind.
+      replaceRelativePointerUsersWithZero(F);
+
       F->replaceNonMetadataUsesWith(ConstantPointerNull::get(F->getType()));
     }
     EraseUnusedGlobalValue(F);

diff  --git a/llvm/test/Transforms/GlobalDCE/call-with-ptrtoint.ll b/llvm/test/Transforms/GlobalDCE/call-with-ptrtoint.ll
new file mode 100644
index 000000000000..bff769b34f7c
--- /dev/null
+++ b/llvm/test/Transforms/GlobalDCE/call-with-ptrtoint.ll
@@ -0,0 +1,21 @@
+; RUN: opt < %s -globaldce -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)
+
+define internal void @foo() {
+  call void @bar_with_fptr_argument(i64 ptrtoint (void ()* @baz to i64))
+  ret void
+}
+
+define internal void @bar_with_fptr_argument(i64 %0) {
+  ret void
+}
+
+define internal void @baz() {
+  ret void
+}
+
+!999 = !{i32 1, !"Virtual Function Elim", i32 1}
+!llvm.module.flags = !{!999}

diff  --git a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll
index 9562d3db82e2..c386e6c71df6 100644
--- a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll
+++ b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-bad.ll
@@ -14,11 +14,7 @@ declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
 !0 = !{i64 0, !"vfunc1.type"}
 !1 = !{i64 4, !"vfunc2.type"}
 
-; CHECK:      @vtable = internal unnamed_addr constant { [3 x i32] } { [3 x i32] [
-; CHECK-SAME:   i32 trunc (i64 sub (i64 0, i64 ptrtoint ({ [3 x i32] }* @vtable to i64)) to i32),
-; CHECK-SAME:   i32 trunc (i64 sub (i64 0, i64 ptrtoint ({ [3 x i32] }* @vtable to i64)) to i32),
-; CHECK-SAME:   i32 trunc (i64 sub (i64 0, i64 ptrtoint (void ()* @weird_ref_2 to i64)) to i32)
-; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
+; CHECK:      @vtable = internal unnamed_addr constant { [3 x i32] } zeroinitializer, align 8, !type !0, !type !1, !vcall_visibility !2
 
 define internal void @vfunc1() { ret void }
 define internal void @vfunc2() { ret void }

diff  --git a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll
index e49dc784af61..7ec29cc26f13 100644
--- a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll
+++ b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers-gep.ll
@@ -16,7 +16,7 @@ declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
 
 ; CHECK:      @vtable = internal unnamed_addr constant { [4 x i32] } { [4 x i32] [
 ; CHECK-SAME:   i32 trunc (i64 sub (i64 ptrtoint (void ()* @vfunc1_live              to i64), i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32] }, { [4 x i32] }* @vtable, i32 0, i32 0, i32 2) to i64)) to i32),
-; CHECK-SAME:   i32 trunc (i64 sub (i64 0,                                                    i64 ptrtoint (i32* getelementptr inbounds ({ [4 x i32] }, { [4 x i32] }* @vtable, i32 0, i32 0, i32 2) to i64)) to i32)
+; CHECK-SAME:   i32 0
 ; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
 
 ; (1) vfunc1_live is referenced from @main, stays alive

diff  --git a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll
index c2bbf00ba56d..685f3754d2da 100644
--- a/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll
+++ b/llvm/test/Transforms/GlobalDCE/virtual-functions-relative-pointers.ll
@@ -14,7 +14,7 @@ declare { i8*, i1 } @llvm.type.checked.load(i8*, i32, metadata)
 
 ; CHECK:      @vtable = internal unnamed_addr constant { [2 x i32] } { [2 x i32] [
 ; CHECK-SAME:   i32 trunc (i64 sub (i64 ptrtoint (void ()* @vfunc1_live              to i64), i64 ptrtoint ({ [2 x i32] }* @vtable to i64)) to i32),
-; CHECK-SAME:   i32 trunc (i64 sub (i64 0,                                                    i64 ptrtoint ({ [2 x i32] }* @vtable to i64)) to i32)
+; CHECK-SAME:   i32 0
 ; CHECK-SAME: ] }, align 8, !type !0, !type !1, !vcall_visibility !2
 
 ; (1) vfunc1_live is referenced from @main, stays alive


        


More information about the llvm-commits mailing list