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