31#define DEBUG_TYPE "globaldce"
35 cl::desc(
"Enable virtual function elimination"));
37STATISTIC(NumAliases ,
"Number of global aliases removed");
38STATISTIC(NumFunctions,
"Number of functions removed");
39STATISTIC(NumIFuncs,
"Number of indirect functions removed");
40STATISTIC(NumVariables,
"Number of global variables removed");
41STATISTIC(NumVFuncs,
"Number of virtual functions removed");
46 if (
F->isDeclaration())
49 for (
auto &
I : Entry) {
50 if (
I.isDebugOrPseudoInst())
52 if (
auto *RI = dyn_cast<ReturnInst>(&
I))
53 return !RI->getReturnValue();
61void GlobalDCEPass::ComputeDependencies(
Value *V,
63 if (
auto *
I = dyn_cast<Instruction>(V)) {
64 Function *Parent =
I->getParent()->getParent();
66 }
else if (
auto *GV = dyn_cast<GlobalValue>(V)) {
68 }
else if (
auto *CE = dyn_cast<Constant>(V)) {
70 auto Where = ConstantDependenciesCache.find(CE);
71 if (Where != ConstantDependenciesCache.end()) {
72 auto const &
K = Where->second;
76 for (
User *CEUser :
CE->users())
77 ComputeDependencies(CEUser, LocalDeps);
83void GlobalDCEPass::UpdateGVDependencies(
GlobalValue &GV) {
86 ComputeDependencies(
User, Deps);
93 if (VFESafeVTables.count(GVU) && isa<Function>(&GV)) {
98 GVDependencies[GVU].insert(&GV);
105 auto const Ret = AliveGlobals.insert(&GV);
112 for (
auto &&CM :
make_range(ComdatMembers.equal_range(
C))) {
113 MarkLive(*CM.second, Updates);
119void GlobalDCEPass::ScanVTables(
Module &M) {
123 auto *LTOPostLinkMD =
124 cast_or_null<ConstantAsMetadata>(
M.getModuleFlag(
"LTOPostLink"));
126 LTOPostLinkMD && !cast<ConstantInt>(LTOPostLinkMD->getValue())->isZero();
142 cast<ConstantAsMetadata>(
Type->getOperand(0))->getValue())
151 if (
auto GO = dyn_cast<GlobalObject>(&GV)) {
157 VFESafeVTables.insert(&GV);
165 for (
const auto &VTableInfo : TypeIdMap[TypeId]) {
167 uint64_t VTableOffset = VTableInfo.second;
171 *
Caller->getParent(), VTable);
174 VFESafeVTables.erase(VTable);
178 auto Callee = dyn_cast<Function>(
Ptr->stripPointerCasts());
181 VFESafeVTables.erase(VTable);
186 <<
Callee->getName() <<
"\n");
191void GlobalDCEPass::ScanTypeCheckedLoadIntrinsics(
Module &M) {
196 if (!TypeCheckedLoadFunc)
199 for (
auto *U : TypeCheckedLoadFunc->
users()) {
200 auto CI = dyn_cast<CallInst>(U);
204 auto *
Offset = dyn_cast<ConstantInt>(CI->getArgOperand(1));
205 Value *TypeIdValue = CI->getArgOperand(2);
206 auto *TypeId = cast<MetadataAsValue>(TypeIdValue)->
getMetadata();
209 ScanVTableLoad(CI->getFunction(), TypeId,
Offset->getZExtValue());
213 for (
const auto &VTableInfo : TypeIdMap[TypeId]) {
214 VFESafeVTables.erase(VTableInfo.first);
220void GlobalDCEPass::AddVirtualFunctionDependencies(
Module &M) {
228 auto *Val = mdconst::dyn_extract_or_null<ConstantInt>(
229 M.getModuleFlag(
"Virtual Function Elim"));
230 if (!Val || Val->isZero())
235 if (VFESafeVTables.empty())
238 ScanTypeCheckedLoadIntrinsics(M);
241 dbgs() <<
"VFE safe vtables:\n";
242 for (
auto *VTable : VFESafeVTables)
248 bool Changed =
false;
265 ComdatMembers.insert(std::make_pair(
C, &
F));
268 ComdatMembers.insert(std::make_pair(
C, &GV));
270 if (
Comdat *
C = GA.getComdat())
271 ComdatMembers.insert(std::make_pair(
C, &GA));
275 AddVirtualFunctionDependencies(M);
279 GO.removeDeadConstantUsers();
283 if (!GO.isDeclaration())
284 if (!GO.isDiscardableIfUnused())
287 UpdateGVDependencies(GO);
292 GA.removeDeadConstantUsers();
294 if (!GA.isDiscardableIfUnused())
297 UpdateGVDependencies(GA);
302 GIF.removeDeadConstantUsers();
304 if (!GIF.isDiscardableIfUnused())
307 UpdateGVDependencies(GIF);
314 while (!NewLiveGVs.empty()) {
316 for (
auto *GVD : GVDependencies[LGV])
317 MarkLive(*GVD, &NewLiveGVs);
325 std::vector<GlobalVariable *> DeadGlobalVars;
327 if (!AliveGlobals.count(&GV)) {
328 DeadGlobalVars.push_back(&GV);
329 if (GV.hasInitializer()) {
331 GV.setInitializer(
nullptr);
333 Init->destroyConstant();
338 std::vector<Function *> DeadFunctions;
340 if (!AliveGlobals.count(&
F)) {
341 DeadFunctions.push_back(&
F);
342 if (!
F.isDeclaration())
347 std::vector<GlobalAlias*> DeadAliases;
349 if (!AliveGlobals.count(&GA)) {
350 DeadAliases.push_back(&GA);
351 GA.setAliasee(
nullptr);
355 std::vector<GlobalIFunc*> DeadIFuncs;
357 if (!AliveGlobals.count(&GIF)) {
358 DeadIFuncs.push_back(&GIF);
359 GIF.setResolver(
nullptr);
364 auto EraseUnusedGlobalValue = [&](
GlobalValue *GV) {
370 NumFunctions += DeadFunctions.size();
372 if (!
F->use_empty()) {
390 EraseUnusedGlobalValue(
F);
393 NumVariables += DeadGlobalVars.size();
395 EraseUnusedGlobalValue(GV);
397 NumAliases += DeadAliases.size();
399 EraseUnusedGlobalValue(GA);
401 NumIFuncs += DeadIFuncs.size();
403 EraseUnusedGlobalValue(GIF);
406 AliveGlobals.clear();
407 ConstantDependenciesCache.clear();
408 GVDependencies.clear();
409 ComdatMembers.clear();
411 VFESafeVTables.clear();
amdgpu Simplify well known AMD library false FunctionCallee Callee
static bool isEmptyFunction(Function *F)
Returns true if F is effectively empty.
static cl::opt< bool > ClEnableVFE("enable-vfe", cl::Hidden, cl::init(true), cl::desc("Enable virtual function elimination"))
Module.h This file contains the declarations for the Module class.
ModuleAnalysisManager MAM
This file defines the SmallPtrSet class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
A container for analyses that lazily runs them and caches their results.
LLVM Basic Block Representation.
static ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
This is an important base class in LLVM.
void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
@ VCallVisibilityLinkageUnit
@ VCallVisibilityTranslationUnit
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
const Comdat * getComdat() const
void eraseFromParent()
This method unlinks 'this' from the containing module and deletes it.
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
bool erase(PtrType Ptr)
erase - If the set contains the specified pointer, remove it and return true, otherwise return false.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
TypeID
Definitions of all of the base types for the Type system.
LLVM Value Representation.
iterator_range< user_iterator > users()
MDNode * getMetadata(unsigned KindID) const
Get the current metadata attachments for the given kind, if any.
StringRef getName() const
Return a constant reference to the value's name.
@ C
The default llvm calling convention, compatible with C.
StringRef getName(ID id)
Return the LLVM name for an intrinsic, such as "llvm.ppc.altivec.lvx".
@ CE
Windows NT (Windows on ARM)
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void replaceRelativePointerUsersWithZero(Function *F)
Finds the same "relative pointer" pattern as described above, where the target is F,...
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
bool isSafeToDestroyConstant(const Constant *C)
It is safe to destroy a constant iff it is only used by constants itself.
bool optimizeGlobalCtorsList(Module &M, function_ref< bool(uint32_t, Function *)> ShouldRemove)
Call "ShouldRemove" for every entry in M's global_ctor list and remove the entries for which it retur...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Constant * getPointerAtOffset(Constant *I, uint64_t Offset, Module &M, Constant *TopLevelGlobal=nullptr)
Processes a Constant recursively looking into elements of arrays, structs and expressions to find a t...