|  | //===- CtorUtils.cpp - Helpers for working with global_ctors ----*- C++ -*-===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines functions that are used to process llvm.global_ctors. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Transforms/Utils/CtorUtils.h" | 
|  | #include "llvm/ADT/BitVector.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/GlobalVariable.h" | 
|  | #include "llvm/IR/Module.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | #define DEBUG_TYPE "ctor_utils" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | /// Given a specified llvm.global_ctors list, remove the listed elements. | 
|  | static void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemove) { | 
|  | // Filter out the initializer elements to remove. | 
|  | ConstantArray *OldCA = cast<ConstantArray>(GCL->getInitializer()); | 
|  | SmallVector<Constant *, 10> CAList; | 
|  | for (unsigned I = 0, E = OldCA->getNumOperands(); I < E; ++I) | 
|  | if (!CtorsToRemove.test(I)) | 
|  | CAList.push_back(OldCA->getOperand(I)); | 
|  |  | 
|  | // Create the new array initializer. | 
|  | ArrayType *ATy = | 
|  | ArrayType::get(OldCA->getType()->getElementType(), CAList.size()); | 
|  | Constant *CA = ConstantArray::get(ATy, CAList); | 
|  |  | 
|  | // If we didn't change the number of elements, don't create a new GV. | 
|  | if (CA->getType() == OldCA->getType()) { | 
|  | GCL->setInitializer(CA); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Create the new global and insert it next to the existing list. | 
|  | GlobalVariable *NGV = | 
|  | new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), | 
|  | CA, "", GCL->getThreadLocalMode()); | 
|  | GCL->getParent()->getGlobalList().insert(GCL->getIterator(), NGV); | 
|  | NGV->takeName(GCL); | 
|  |  | 
|  | // Nuke the old list, replacing any uses with the new one. | 
|  | if (!GCL->use_empty()) { | 
|  | Constant *V = NGV; | 
|  | if (V->getType() != GCL->getType()) | 
|  | V = ConstantExpr::getBitCast(V, GCL->getType()); | 
|  | GCL->replaceAllUsesWith(V); | 
|  | } | 
|  | GCL->eraseFromParent(); | 
|  | } | 
|  |  | 
|  | /// 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) { | 
|  | if (GV->getInitializer()->isNullValue()) | 
|  | return std::vector<Function *>(); | 
|  | ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); | 
|  | std::vector<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))); | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | /// Find the llvm.global_ctors list, verifying that all initializers have an | 
|  | /// init priority of 65535. | 
|  | static GlobalVariable *findGlobalCtors(Module &M) { | 
|  | GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); | 
|  | if (!GV) | 
|  | return nullptr; | 
|  |  | 
|  | // Verify that the initializer is simple enough for us to handle. We are | 
|  | // only allowed to optimize the initializer if it is unique. | 
|  | if (!GV->hasUniqueInitializer()) | 
|  | return nullptr; | 
|  |  | 
|  | if (isa<ConstantAggregateZero>(GV->getInitializer())) | 
|  | return GV; | 
|  | ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); | 
|  |  | 
|  | for (auto &V : CA->operands()) { | 
|  | if (isa<ConstantAggregateZero>(V)) | 
|  | continue; | 
|  | ConstantStruct *CS = cast<ConstantStruct>(V); | 
|  | if (isa<ConstantPointerNull>(CS->getOperand(1))) | 
|  | continue; | 
|  |  | 
|  | // Must have a function or null ptr. | 
|  | if (!isa<Function>(CS->getOperand(1))) | 
|  | 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) { | 
|  | GlobalVariable *GlobalCtors = findGlobalCtors(M); | 
|  | if (!GlobalCtors) | 
|  | return false; | 
|  |  | 
|  | std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors); | 
|  | if (Ctors.empty()) | 
|  | return false; | 
|  |  | 
|  | bool MadeChange = false; | 
|  |  | 
|  | // Loop over global ctors, optimizing them when we can. | 
|  | unsigned NumCtors = Ctors.size(); | 
|  | BitVector CtorsToRemove(NumCtors); | 
|  | for (unsigned i = 0; i != Ctors.size() && NumCtors > 0; ++i) { | 
|  | Function *F = Ctors[i]; | 
|  | // Found a null terminator in the middle of the list, prune off the rest of | 
|  | // the list. | 
|  | 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); | 
|  | NumCtors--; | 
|  | MadeChange = true; | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!MadeChange) | 
|  | return false; | 
|  |  | 
|  | removeGlobalCtors(GlobalCtors, CtorsToRemove); | 
|  | return true; | 
|  | } |