[llvm] badd088 - [GlobalOpt] Enable optimization of constructors with different priorities
Alexander Shaposhnikov via llvm-commits
llvm-commits at lists.llvm.org
Fri May 13 15:19:51 PDT 2022
Author: Alexander Shaposhnikov
Date: 2022-05-13T22:19:29Z
New Revision: badd088c57d7d18acd337b7868fe8c7974c88c5b
URL: https://github.com/llvm/llvm-project/commit/badd088c57d7d18acd337b7868fe8c7974c88c5b
DIFF: https://github.com/llvm/llvm-project/commit/badd088c57d7d18acd337b7868fe8c7974c88c5b.diff
LOG: [GlobalOpt] Enable optimization of constructors with different priorities
Adjust `optimizeGlobalCtorsList` to handle the case of different priorities.
This addresses the issue https://github.com/llvm/llvm-project/issues/55083.
Test plan: ninja check-all
Differential revision: https://reviews.llvm.org/D125278
Added:
Modified:
llvm/include/llvm/Transforms/Utils/CtorUtils.h
llvm/lib/Transforms/IPO/GlobalDCE.cpp
llvm/lib/Transforms/IPO/GlobalOpt.cpp
llvm/lib/Transforms/Utils/CtorUtils.cpp
llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/CtorUtils.h b/llvm/include/llvm/Transforms/Utils/CtorUtils.h
index 20587f194249c..40b290a5a6f4e 100644
--- a/llvm/include/llvm/Transforms/Utils/CtorUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/CtorUtils.h
@@ -22,9 +22,9 @@ class Module;
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
/// entries for which it returns true. Return true if anything changed.
-bool optimizeGlobalCtorsList(Module &M,
- function_ref<bool(Function *)> ShouldRemove);
+bool optimizeGlobalCtorsList(
+ Module &M, function_ref<bool(uint32_t, Function *)> ShouldRemove);
-} // End llvm namespace
+} // namespace llvm
#endif
diff --git a/llvm/lib/Transforms/IPO/GlobalDCE.cpp b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
index e7ecd5ce68b6e..44a157f7ec96f 100644
--- a/llvm/lib/Transforms/IPO/GlobalDCE.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalDCE.cpp
@@ -85,6 +85,9 @@ ModulePass *llvm::createGlobalDCEPass() {
/// Returns true if F is effectively empty.
static bool isEmptyFunction(Function *F) {
+ // Skip external functions.
+ if (F->isDeclaration())
+ return false;
BasicBlock &Entry = F->getEntryBlock();
for (auto &I : Entry) {
if (I.isDebugOrPseudoInst())
@@ -297,7 +300,8 @@ PreservedAnalyses GlobalDCEPass::run(Module &M, ModuleAnalysisManager &MAM) {
// marked as alive are discarded.
// Remove empty functions from the global ctors list.
- Changed |= optimizeGlobalCtorsList(M, isEmptyFunction);
+ Changed |= optimizeGlobalCtorsList(
+ M, [](uint32_t, Function *F) { return isEmptyFunction(F); });
// Collect the set of members for each comdat.
for (Function &F : M)
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index 157cb27ec96f5..04aff8be0a9ab 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -2058,6 +2058,9 @@ OptimizeGlobalVars(Module &M,
/// can, false otherwise.
static bool EvaluateStaticConstructor(Function *F, const DataLayout &DL,
TargetLibraryInfo *TLI) {
+ // Skip external functions.
+ if (F->isDeclaration())
+ return false;
// Call the function.
Evaluator Eval(DL, TLI);
Constant *RetValDummy;
@@ -2419,6 +2422,8 @@ static bool optimizeGlobalsInModule(
SmallPtrSet<const Comdat *, 8> NotDiscardableComdats;
bool Changed = false;
bool LocalChange = true;
+ Optional<uint32_t> FirstNotFullyEvaluatedPriority;
+
while (LocalChange) {
LocalChange = false;
@@ -2441,9 +2446,16 @@ static bool optimizeGlobalsInModule(
NotDiscardableComdats);
// Optimize global_ctors list.
- LocalChange |= optimizeGlobalCtorsList(M, [&](Function *F) {
- return EvaluateStaticConstructor(F, DL, &GetTLI(*F));
- });
+ LocalChange |=
+ optimizeGlobalCtorsList(M, [&](uint32_t Priority, Function *F) {
+ if (FirstNotFullyEvaluatedPriority &&
+ *FirstNotFullyEvaluatedPriority != Priority)
+ return false;
+ bool Evaluated = EvaluateStaticConstructor(F, DL, &GetTLI(*F));
+ if (!Evaluated)
+ FirstNotFullyEvaluatedPriority = Priority;
+ return Evaluated;
+ });
// Optimize non-address-taken globals.
LocalChange |= OptimizeGlobalVars(M, GetTTI, GetTLI, LookupDomTree,
diff --git a/llvm/lib/Transforms/Utils/CtorUtils.cpp b/llvm/lib/Transforms/Utils/CtorUtils.cpp
index 5f709f3911a14..c997f39508e35 100644
--- a/llvm/lib/Transforms/Utils/CtorUtils.cpp
+++ b/llvm/lib/Transforms/Utils/CtorUtils.cpp
@@ -18,6 +18,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
+#include <numeric>
#define DEBUG_TYPE "ctor_utils"
@@ -62,19 +63,20 @@ static void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemov
/// Given a llvm.global_ctors list that we can understand,
/// return a list of the functions and null terminator as a vector.
-static std::vector<Function *> parseGlobalCtors(GlobalVariable *GV) {
+static std::vector<std::pair<uint32_t, Function *>>
+parseGlobalCtors(GlobalVariable *GV) {
ConstantArray *CA = cast<ConstantArray>(GV->getInitializer());
- std::vector<Function *> Result;
+ std::vector<std::pair<uint32_t, Function *>> Result;
Result.reserve(CA->getNumOperands());
for (auto &V : CA->operands()) {
ConstantStruct *CS = cast<ConstantStruct>(V);
- Result.push_back(dyn_cast<Function>(CS->getOperand(1)));
+ Result.emplace_back(cast<ConstantInt>(CS->getOperand(0))->getZExtValue(),
+ dyn_cast<Function>(CS->getOperand(1)));
}
return Result;
}
-/// Find the llvm.global_ctors list, verifying that all initializers have an
-/// init priority of 65535.
+/// Find the llvm.global_ctors list.
static GlobalVariable *findGlobalCtors(Module &M) {
GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors");
if (!GV)
@@ -102,49 +104,43 @@ static GlobalVariable *findGlobalCtors(Module &M) {
Function *F = dyn_cast<Function>(CS->getOperand(1));
if (!F || F->arg_size() != 0)
return nullptr;
-
- // Init priority must be standard.
- ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0));
- if (CI->getZExtValue() != 65535)
- return nullptr;
}
-
return GV;
}
/// Call "ShouldRemove" for every entry in M's global_ctor list and remove the
/// entries for which it returns true. Return true if anything changed.
bool llvm::optimizeGlobalCtorsList(
- Module &M, function_ref<bool(Function *)> ShouldRemove) {
+ Module &M, function_ref<bool(uint32_t, Function *)> ShouldRemove) {
GlobalVariable *GlobalCtors = findGlobalCtors(M);
if (!GlobalCtors)
return false;
- std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors);
+ std::vector<std::pair<uint32_t, Function *>> Ctors =
+ parseGlobalCtors(GlobalCtors);
if (Ctors.empty())
return false;
bool MadeChange = false;
-
// Loop over global ctors, optimizing them when we can.
BitVector CtorsToRemove(Ctors.size());
- for (unsigned i = 0, e = Ctors.size(); i != e; ++i) {
- Function *F = Ctors[i];
- // Found a null terminator in the middle of the list, prune off the rest of
- // the list.
+ std::vector<size_t> CtorsByPriority(Ctors.size());
+ std::iota(CtorsByPriority.begin(), CtorsByPriority.end(), 0);
+ stable_sort(CtorsByPriority, [&](size_t LHS, size_t RHS) {
+ return Ctors[LHS].first < Ctors[RHS].first;
+ });
+ for (unsigned CtorIndex : CtorsByPriority) {
+ const uint32_t Priority = Ctors[CtorIndex].first;
+ Function *F = Ctors[CtorIndex].second;
if (!F)
continue;
LLVM_DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n");
- // We cannot simplify external ctor functions.
- if (F->empty())
- continue;
-
// If we can evaluate the ctor at compile time, do.
- if (ShouldRemove(F)) {
- Ctors[i] = nullptr;
- CtorsToRemove.set(i);
+ if (ShouldRemove(Priority, F)) {
+ Ctors[CtorIndex].second = nullptr;
+ CtorsToRemove.set(CtorIndex);
MadeChange = true;
continue;
}
diff --git a/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll b/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll
index 0e932cc1acb7a..d0399416c434f 100644
--- a/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll
+++ b/llvm/test/Transforms/GlobalOpt/ctor-list-opt.ll
@@ -1,7 +1,8 @@
; RUN: opt < %s -passes=globalopt -S | FileCheck %s
; CHECK-NOT: CTOR
%ini = type { i32, void()*, i8* }
- at llvm.global_ctors = appending global [11 x %ini] [
+ at llvm.global_ctors = appending global [15 x %ini] [
+ %ini { i32 65534, void ()* @CTOR1, i8* null },
%ini { i32 65535, void ()* @CTOR1, i8* null },
%ini { i32 65535, void ()* @CTOR1, i8* null },
%ini { i32 65535, void ()* @CTOR2, i8* null },
@@ -12,6 +13,9 @@
%ini { i32 65535, void ()* @CTOR7, i8* null },
%ini { i32 65535, void ()* @CTOR8, i8* null },
%ini { i32 65535, void ()* @CTOR9, i8* null },
+ %ini { i32 65536, void ()* @CTOR10_EXTERNAL, i8* null },
+ %ini { i32 65536, void ()* @CTOR11, i8* null },
+ %ini { i32 65537, void ()* @CTOR12, i8* null },
%ini { i32 2147483647, void ()* null, i8* null }
]
@@ -113,3 +117,16 @@ entry:
store i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @GV2, i64 1, i64 0), i8*** %3
ret void
}
+
+; CHECK: CTOR10_EXTERNAL
+declare external void @CTOR10_EXTERNAL();
+
+; CHECK-NOT: CTOR11
+define internal void @CTOR11() {
+ ret void
+}
+
+; CHECK: CTOR12
+define internal void @CTOR12() {
+ ret void
+}
More information about the llvm-commits
mailing list