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