1 //===- CtorUtils.cpp - Helpers for working with global_ctors ----*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file defines functions that are used to process llvm.global_ctors. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Transforms/Utils/CtorUtils.h" 15 #include "llvm/ADT/BitVector.h" 16 #include "llvm/IR/Constants.h" 17 #include "llvm/IR/Function.h" 18 #include "llvm/IR/GlobalVariable.h" 19 #include "llvm/IR/Module.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 #define DEBUG_TYPE "ctor_utils" 24 25 using namespace llvm; 26 27 /// Given a specified llvm.global_ctors list, remove the listed elements. 28 static void removeGlobalCtors(GlobalVariable *GCL, const BitVector &CtorsToRemove) { 29 // Filter out the initializer elements to remove. 30 ConstantArray *OldCA = cast<ConstantArray>(GCL->getInitializer()); 31 SmallVector<Constant *, 10> CAList; 32 for (unsigned I = 0, E = OldCA->getNumOperands(); I < E; ++I) 33 if (!CtorsToRemove.test(I)) 34 CAList.push_back(OldCA->getOperand(I)); 35 36 // Create the new array initializer. 37 ArrayType *ATy = 38 ArrayType::get(OldCA->getType()->getElementType(), CAList.size()); 39 Constant *CA = ConstantArray::get(ATy, CAList); 40 41 // If we didn't change the number of elements, don't create a new GV. 42 if (CA->getType() == OldCA->getType()) { 43 GCL->setInitializer(CA); 44 return; 45 } 46 47 // Create the new global and insert it next to the existing list. 48 GlobalVariable *NGV = 49 new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), 50 CA, "", GCL->getThreadLocalMode()); 51 GCL->getParent()->getGlobalList().insert(GCL->getIterator(), NGV); 52 NGV->takeName(GCL); 53 54 // Nuke the old list, replacing any uses with the new one. 55 if (!GCL->use_empty()) { 56 Constant *V = NGV; 57 if (V->getType() != GCL->getType()) 58 V = ConstantExpr::getBitCast(V, GCL->getType()); 59 GCL->replaceAllUsesWith(V); 60 } 61 GCL->eraseFromParent(); 62 } 63 64 /// Given a llvm.global_ctors list that we can understand, 65 /// return a list of the functions and null terminator as a vector. 66 static std::vector<Function *> parseGlobalCtors(GlobalVariable *GV) { 67 if (GV->getInitializer()->isNullValue()) 68 return std::vector<Function *>(); 69 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 70 std::vector<Function *> Result; 71 Result.reserve(CA->getNumOperands()); 72 for (auto &V : CA->operands()) { 73 ConstantStruct *CS = cast<ConstantStruct>(V); 74 Result.push_back(dyn_cast<Function>(CS->getOperand(1))); 75 } 76 return Result; 77 } 78 79 /// Find the llvm.global_ctors list, verifying that all initializers have an 80 /// init priority of 65535. 81 static GlobalVariable *findGlobalCtors(Module &M) { 82 GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); 83 if (!GV) 84 return nullptr; 85 86 // Verify that the initializer is simple enough for us to handle. We are 87 // only allowed to optimize the initializer if it is unique. 88 if (!GV->hasUniqueInitializer()) 89 return nullptr; 90 91 if (isa<ConstantAggregateZero>(GV->getInitializer())) 92 return GV; 93 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 94 95 for (auto &V : CA->operands()) { 96 if (isa<ConstantAggregateZero>(V)) 97 continue; 98 ConstantStruct *CS = cast<ConstantStruct>(V); 99 if (isa<ConstantPointerNull>(CS->getOperand(1))) 100 continue; 101 102 // Must have a function or null ptr. 103 if (!isa<Function>(CS->getOperand(1))) 104 return nullptr; 105 106 // Init priority must be standard. 107 ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0)); 108 if (CI->getZExtValue() != 65535) 109 return nullptr; 110 } 111 112 return GV; 113 } 114 115 /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the 116 /// entries for which it returns true. Return true if anything changed. 117 bool llvm::optimizeGlobalCtorsList( 118 Module &M, function_ref<bool(Function *)> ShouldRemove) { 119 GlobalVariable *GlobalCtors = findGlobalCtors(M); 120 if (!GlobalCtors) 121 return false; 122 123 std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors); 124 if (Ctors.empty()) 125 return false; 126 127 bool MadeChange = false; 128 129 // Loop over global ctors, optimizing them when we can. 130 unsigned NumCtors = Ctors.size(); 131 BitVector CtorsToRemove(NumCtors); 132 for (unsigned i = 0; i != Ctors.size() && NumCtors > 0; ++i) { 133 Function *F = Ctors[i]; 134 // Found a null terminator in the middle of the list, prune off the rest of 135 // the list. 136 if (!F) 137 continue; 138 139 LLVM_DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n"); 140 141 // We cannot simplify external ctor functions. 142 if (F->empty()) 143 continue; 144 145 // If we can evaluate the ctor at compile time, do. 146 if (ShouldRemove(F)) { 147 Ctors[i] = nullptr; 148 CtorsToRemove.set(i); 149 NumCtors--; 150 MadeChange = true; 151 continue; 152 } 153 } 154 155 if (!MadeChange) 156 return false; 157 158 removeGlobalCtors(GlobalCtors, CtorsToRemove); 159 return true; 160 } 161