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