LLVM API Documentation
00001 //===- CtorUtils.cpp - Helpers for working with global_ctors ----*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines functions that are used to process llvm.global_ctors. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "llvm/Transforms/Utils/CtorUtils.h" 00015 #include "llvm/IR/Constants.h" 00016 #include "llvm/IR/Function.h" 00017 #include "llvm/IR/GlobalVariable.h" 00018 #include "llvm/IR/Instructions.h" 00019 #include "llvm/IR/Module.h" 00020 #include "llvm/Support/Debug.h" 00021 00022 #define DEBUG_TYPE "ctor_utils" 00023 00024 namespace llvm { 00025 00026 namespace { 00027 /// Given a specified llvm.global_ctors list, install the 00028 /// specified array. 00029 void installGlobalCtors(GlobalVariable *GCL, 00030 const std::vector<Function *> &Ctors) { 00031 // If we made a change, reassemble the initializer list. 00032 Constant *CSVals[3]; 00033 00034 StructType *StructTy = 00035 cast<StructType>(GCL->getType()->getElementType()->getArrayElementType()); 00036 00037 // Create the new init list. 00038 std::vector<Constant *> CAList; 00039 for (Function *F : Ctors) { 00040 Type *Int32Ty = Type::getInt32Ty(GCL->getContext()); 00041 if (F) { 00042 CSVals[0] = ConstantInt::get(Int32Ty, 65535); 00043 CSVals[1] = F; 00044 } else { 00045 CSVals[0] = ConstantInt::get(Int32Ty, 0x7fffffff); 00046 CSVals[1] = Constant::getNullValue(StructTy->getElementType(1)); 00047 } 00048 // FIXME: Only allow the 3-field form in LLVM 4.0. 00049 size_t NumElts = StructTy->getNumElements(); 00050 if (NumElts > 2) 00051 CSVals[2] = Constant::getNullValue(StructTy->getElementType(2)); 00052 CAList.push_back( 00053 ConstantStruct::get(StructTy, makeArrayRef(CSVals, NumElts))); 00054 } 00055 00056 // Create the array initializer. 00057 Constant *CA = 00058 ConstantArray::get(ArrayType::get(StructTy, CAList.size()), CAList); 00059 00060 // If we didn't change the number of elements, don't create a new GV. 00061 if (CA->getType() == GCL->getInitializer()->getType()) { 00062 GCL->setInitializer(CA); 00063 return; 00064 } 00065 00066 // Create the new global and insert it next to the existing list. 00067 GlobalVariable *NGV = 00068 new GlobalVariable(CA->getType(), GCL->isConstant(), GCL->getLinkage(), 00069 CA, "", GCL->getThreadLocalMode()); 00070 GCL->getParent()->getGlobalList().insert(GCL, NGV); 00071 NGV->takeName(GCL); 00072 00073 // Nuke the old list, replacing any uses with the new one. 00074 if (!GCL->use_empty()) { 00075 Constant *V = NGV; 00076 if (V->getType() != GCL->getType()) 00077 V = ConstantExpr::getBitCast(V, GCL->getType()); 00078 GCL->replaceAllUsesWith(V); 00079 } 00080 GCL->eraseFromParent(); 00081 } 00082 00083 /// Given a llvm.global_ctors list that we can understand, 00084 /// return a list of the functions and null terminator as a vector. 00085 std::vector<Function*> parseGlobalCtors(GlobalVariable *GV) { 00086 if (GV->getInitializer()->isNullValue()) 00087 return std::vector<Function *>(); 00088 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 00089 std::vector<Function *> Result; 00090 Result.reserve(CA->getNumOperands()); 00091 for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { 00092 ConstantStruct *CS = cast<ConstantStruct>(*i); 00093 Result.push_back(dyn_cast<Function>(CS->getOperand(1))); 00094 } 00095 return Result; 00096 } 00097 00098 /// Find the llvm.global_ctors list, verifying that all initializers have an 00099 /// init priority of 65535. 00100 GlobalVariable *findGlobalCtors(Module &M) { 00101 GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); 00102 if (!GV) 00103 return nullptr; 00104 00105 // Verify that the initializer is simple enough for us to handle. We are 00106 // only allowed to optimize the initializer if it is unique. 00107 if (!GV->hasUniqueInitializer()) 00108 return nullptr; 00109 00110 if (isa<ConstantAggregateZero>(GV->getInitializer())) 00111 return GV; 00112 ConstantArray *CA = cast<ConstantArray>(GV->getInitializer()); 00113 00114 for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) { 00115 if (isa<ConstantAggregateZero>(*i)) 00116 continue; 00117 ConstantStruct *CS = cast<ConstantStruct>(*i); 00118 if (isa<ConstantPointerNull>(CS->getOperand(1))) 00119 continue; 00120 00121 // Must have a function or null ptr. 00122 if (!isa<Function>(CS->getOperand(1))) 00123 return nullptr; 00124 00125 // Init priority must be standard. 00126 ConstantInt *CI = cast<ConstantInt>(CS->getOperand(0)); 00127 if (CI->getZExtValue() != 65535) 00128 return nullptr; 00129 } 00130 00131 return GV; 00132 } 00133 } // namespace 00134 00135 /// Call "ShouldRemove" for every entry in M's global_ctor list and remove the 00136 /// entries for which it returns true. Return true if anything changed. 00137 bool optimizeGlobalCtorsList(Module &M, 00138 function_ref<bool(Function *)> ShouldRemove) { 00139 GlobalVariable *GlobalCtors = findGlobalCtors(M); 00140 if (!GlobalCtors) 00141 return false; 00142 00143 std::vector<Function *> Ctors = parseGlobalCtors(GlobalCtors); 00144 if (Ctors.empty()) 00145 return false; 00146 00147 bool MadeChange = false; 00148 00149 // Loop over global ctors, optimizing them when we can. 00150 for (unsigned i = 0; i != Ctors.size(); ++i) { 00151 Function *F = Ctors[i]; 00152 // Found a null terminator in the middle of the list, prune off the rest of 00153 // the list. 00154 if (!F) { 00155 if (i != Ctors.size() - 1) { 00156 Ctors.resize(i + 1); 00157 MadeChange = true; 00158 } 00159 break; 00160 } 00161 DEBUG(dbgs() << "Optimizing Global Constructor: " << *F << "\n"); 00162 00163 // We cannot simplify external ctor functions. 00164 if (F->empty()) 00165 continue; 00166 00167 // If we can evaluate the ctor at compile time, do. 00168 if (ShouldRemove(F)) { 00169 Ctors.erase(Ctors.begin() + i); 00170 MadeChange = true; 00171 --i; 00172 continue; 00173 } 00174 } 00175 00176 if (!MadeChange) 00177 return false; 00178 00179 installGlobalCtors(GlobalCtors, Ctors); 00180 return true; 00181 } 00182 00183 } // End llvm namespace