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