From d94e8479fcd7cd57fa9c6f3f3aa24d2ad3e11d89 Mon Sep 17 00:00:00 2001 From: Florian Hahn Date: Thu, 2 Mar 2023 10:12:23 +0100 Subject: [PATCH] [GlobalOpt] Extend CleanupPointerRootUsers to handle CE users. Extend CleanupPointerRootUsers to iterate over a worklist, add users of constant expressions to the worklist to enable additional cleanups. Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D144468 --- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 7 +++-- llvm/test/ThinLTO/X86/import-constant.ll | 4 +-- .../cleanup-pointer-root-users-gep-constexpr.ll | 10 ------- ...up-pointer-root-users-ptrtoint-add-constexpr.ll | 34 ++++++++++++++++++++++ 4 files changed, 41 insertions(+), 14 deletions(-) create mode 100644 llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-ptrtoint-add-constexpr.ll diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index bbe9f87..25dc748 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -206,8 +206,10 @@ CleanupPointerRootUsers(GlobalVariable *GV, // chain of computation and the store to the global in Dead[n].second. SmallVector, 32> Dead; + SmallVector Worklist(GV->users()); // Constants can't be pointers to dynamically allocated memory. - for (User *U : llvm::make_early_inc_range(GV->users())) { + while (!Worklist.empty()) { + User *U = Worklist.pop_back_val(); if (StoreInst *SI = dyn_cast(U)) { Value *V = SI->getValueOperand(); if (isa(V)) { @@ -238,7 +240,8 @@ CleanupPointerRootUsers(GlobalVariable *GV, if (CE->use_empty()) { CE->destroyConstant(); Changed = true; - } + } else if (isa(CE)) + append_range(Worklist, CE->users()); } else if (Constant *C = dyn_cast(U)) { if (isSafeToDestroyConstant(C)) { C->destroyConstant(); diff --git a/llvm/test/ThinLTO/X86/import-constant.ll b/llvm/test/ThinLTO/X86/import-constant.ll index ae77192..79d0ef5 100644 --- a/llvm/test/ThinLTO/X86/import-constant.ll +++ b/llvm/test/ThinLTO/X86/import-constant.ll @@ -32,11 +32,11 @@ ; IMPORT-NEXT: @_ZL3Obj.llvm.{{.*}} = available_externally hidden constant %struct.S { i32 4, i32 8, ptr @val } ; IMPORT-NEXT: @outer = internal local_unnamed_addr global %struct.Q zeroinitializer -; OPT: @outer = internal unnamed_addr global %struct.Q zeroinitializer +; @outer is a write-only variable that's stored to once, so the store and the global can be removed. +; OPT-NOT: @outer ; OPT: define dso_local i32 @main() ; OPT-NEXT: entry: -; OPT-NEXT: store ptr null, ptr getelementptr inbounds (%struct.Q, ptr @outer, i64 1, i32 0) ; OPT-NEXT: ret i32 12 ; NOREFS: @_ZL3Obj.llvm.{{.*}} = external hidden constant %struct.S diff --git a/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-gep-constexpr.ll b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-gep-constexpr.ll index fdcadc9..f9d988f9 100644 --- a/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-gep-constexpr.ll +++ b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-gep-constexpr.ll @@ -16,14 +16,6 @@ declare i32 @fn3() define void @stores_single_use_gep_constexpr() { ; CHECK-LABEL: @stores_single_use_gep_constexpr( ; CHECK-NEXT: entry: -; CHECK-NEXT: store ptr @fn1, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR:%.*]], ptr @global.20ptr, i64 0, i32 1), align 8 -; CHECK-NEXT: store ptr @fn2, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 2), align 8 -; CHECK-NEXT: store ptr @fn3, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 3), align 8 -; CHECK-NEXT: store ptr @fn0, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 4), align 8 -; CHECK-NEXT: store ptr @fn1, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 5), align 8 -; CHECK-NEXT: store ptr @fn2, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 6), align 8 -; CHECK-NEXT: store ptr @fn3, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 7), align 8 -; CHECK-NEXT: store ptr @fn0, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 8), align 8 ; CHECK-NEXT: ret void ; entry: @@ -42,8 +34,6 @@ entry: define void @stores_multi_use_gep_constexpr() { ; CHECK-LABEL: @stores_multi_use_gep_constexpr( ; CHECK-NEXT: entry: -; CHECK-NEXT: store i32 0, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR:%.*]], ptr @global.20ptr, i64 0, i32 16), align 8 -; CHECK-NEXT: store i32 0, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR]], ptr @global.20ptr, i64 0, i32 16), align 8 ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-ptrtoint-add-constexpr.ll b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-ptrtoint-add-constexpr.ll new file mode 100644 index 0000000..477b617 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/cleanup-pointer-root-users-ptrtoint-add-constexpr.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -passes=globalopt -S %s | FileCheck %s + +%struct.global.20ptr = type { ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr, ptr } + +@global.20ptr = internal unnamed_addr global %struct.global.20ptr zeroinitializer + +declare i32 @fn0() + +declare i32 @fn1() + +define void @stores_single_use_gep_constexpr() { +; CHECK-LABEL: @stores_single_use_gep_constexpr( +; CHECK-NEXT: entry: +; CHECK-NEXT: store ptr @fn0, ptr @global.20ptr, align 8 +; CHECK-NEXT: store ptr @fn1, ptr getelementptr inbounds ([[STRUCT_GLOBAL_20PTR:%.*]], ptr @global.20ptr, i64 0, i32 1), align 8 +; CHECK-NEXT: ret void +; +entry: + store ptr @fn0, ptr getelementptr inbounds (%struct.global.20ptr, ptr @global.20ptr, i64 0, i32 0), align 8 + store ptr @fn1, ptr getelementptr inbounds (%struct.global.20ptr, ptr @global.20ptr, i64 0, i32 1), align 8 + ret void +} + +define void @stores_ptrtoint_constexpr() { +; CHECK-LABEL: @stores_ptrtoint_constexpr( +; CHECK-NEXT: entry: +; CHECK-NEXT: store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @global.20ptr to i64), i64 200) to ptr), align 8 +; CHECK-NEXT: ret void +; +entry: + store i32 0, ptr inttoptr (i64 add (i64 ptrtoint (ptr @global.20ptr to i64), i64 200) to ptr), align 8 + ret void +} -- 2.7.4