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