e61591870bc57d01e19da15c810ac773bc43aa69
[oota-llvm.git] / lib / Transforms / IPO / Internalize.cpp
1 //===-- Internalize.cpp - Mark functions internal -------------------------===//
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 pass loops over all of the functions and variables in the input module.
11 // If the function or variable is not in the list of external names given to
12 // the pass it is marked as internal.
13 //
14 // This transformation would not be legal or profitable in a regular
15 // compilation, but it gets extra information from the linker about what is safe
16 // or profitable.
17 //
18 // As an example of a normally illegal transformation: Internalizing a function
19 // with external linkage. Only if we are told it is only used from within this
20 // module, it is safe to do it.
21 //
22 // On the profitability side: It is always legal to internalize a linkonce_odr
23 // whose address is not used. Doing so normally would introduce code bloat, but
24 // if we are told by the linker that the only use of this would be for a
25 // DSO symbol table, it is profitable to hide it.
26 //
27 //===----------------------------------------------------------------------===//
28
29 #define DEBUG_TYPE "internalize"
30 #include "llvm/Transforms/IPO.h"
31 #include "llvm/ADT/SmallPtrSet.h"
32 #include "llvm/ADT/Statistic.h"
33 #include "llvm/Analysis/CallGraph.h"
34 #include "llvm/IR/Module.h"
35 #include "llvm/Pass.h"
36 #include "llvm/Support/CommandLine.h"
37 #include "llvm/Support/Debug.h"
38 #include "llvm/Support/raw_ostream.h"
39 #include "llvm/Transforms/Utils/GlobalStatus.h"
40 #include "llvm/Transforms/Utils/ModuleUtils.h"
41 #include <fstream>
42 #include <set>
43 using namespace llvm;
44
45 STATISTIC(NumAliases  , "Number of aliases internalized");
46 STATISTIC(NumFunctions, "Number of functions internalized");
47 STATISTIC(NumGlobals  , "Number of global vars internalized");
48
49 // APIFile - A file which contains a list of symbols that should not be marked
50 // external.
51 static cl::opt<std::string>
52 APIFile("internalize-public-api-file", cl::value_desc("filename"),
53         cl::desc("A file containing list of symbol names to preserve"));
54
55 // APIList - A list of symbols that should not be marked internal.
56 static cl::list<std::string>
57 APIList("internalize-public-api-list", cl::value_desc("list"),
58         cl::desc("A list of symbol names to preserve"),
59         cl::CommaSeparated);
60
61 static cl::list<std::string>
62 DSOList("internalize-dso-list", cl::value_desc("list"),
63         cl::desc("A list of symbol names need for a dso symbol table"),
64         cl::CommaSeparated);
65
66 namespace {
67   class InternalizePass : public ModulePass {
68     std::set<std::string> ExternalNames;
69     std::set<std::string> DSONames;
70   public:
71     static char ID; // Pass identification, replacement for typeid
72     explicit InternalizePass();
73     explicit InternalizePass(ArrayRef<const char *> ExportList,
74                              ArrayRef<const char *> DSOList);
75     void LoadFile(const char *Filename);
76     virtual bool runOnModule(Module &M);
77
78     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
79       AU.setPreservesCFG();
80       AU.addPreserved<CallGraph>();
81     }
82   };
83 } // end anonymous namespace
84
85 char InternalizePass::ID = 0;
86 INITIALIZE_PASS(InternalizePass, "internalize",
87                 "Internalize Global Symbols", false, false)
88
89 InternalizePass::InternalizePass()
90   : ModulePass(ID) {
91   initializeInternalizePassPass(*PassRegistry::getPassRegistry());
92   if (!APIFile.empty())           // If a filename is specified, use it.
93     LoadFile(APIFile.c_str());
94   ExternalNames.insert(APIList.begin(), APIList.end());
95   DSONames.insert(DSOList.begin(), DSOList.end());
96 }
97
98 InternalizePass::InternalizePass(ArrayRef<const char *> ExportList,
99                                  ArrayRef<const char *> DSOList)
100   : ModulePass(ID){
101   initializeInternalizePassPass(*PassRegistry::getPassRegistry());
102   for(ArrayRef<const char *>::const_iterator itr = ExportList.begin();
103         itr != ExportList.end(); itr++) {
104     ExternalNames.insert(*itr);
105   }
106   for(ArrayRef<const char *>::const_iterator itr = DSOList.begin();
107         itr != DSOList.end(); itr++) {
108     DSONames.insert(*itr);
109   }
110 }
111
112 void InternalizePass::LoadFile(const char *Filename) {
113   // Load the APIFile...
114   std::ifstream In(Filename);
115   if (!In.good()) {
116     errs() << "WARNING: Internalize couldn't load file '" << Filename
117          << "'! Continuing as if it's empty.\n";
118     return; // Just continue as if the file were empty
119   }
120   while (In) {
121     std::string Symbol;
122     In >> Symbol;
123     if (!Symbol.empty())
124       ExternalNames.insert(Symbol);
125   }
126 }
127
128 static bool shouldInternalize(const GlobalValue &GV,
129                               const std::set<std::string> &ExternalNames,
130                               const std::set<std::string> &DSONames) {
131   // Function must be defined here
132   if (GV.isDeclaration())
133     return false;
134
135   // Available externally is really just a "declaration with a body".
136   if (GV.hasAvailableExternallyLinkage())
137     return false;
138
139   // Already has internal linkage
140   if (GV.hasLocalLinkage())
141     return false;
142
143   // Marked to keep external?
144   if (ExternalNames.count(GV.getName()))
145     return false;
146
147   // Not needed for the symbol table?
148   if (!DSONames.count(GV.getName()))
149     return true;
150
151   // Not a linkonce. Someone can depend on it being on the symbol table.
152   if (!GV.hasLinkOnceLinkage())
153     return false;
154
155   // The address is not important, we can hide it.
156   if (GV.hasUnnamedAddr())
157     return true;
158
159   GlobalStatus GS;
160   if (GlobalStatus::analyzeGlobal(&GV, GS))
161     return false;
162
163   return !GS.IsCompared;
164 }
165
166 bool InternalizePass::runOnModule(Module &M) {
167   CallGraph *CG = getAnalysisIfAvailable<CallGraph>();
168   CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : 0;
169   bool Changed = false;
170
171   SmallPtrSet<GlobalValue *, 8> Used;
172   collectUsedGlobalVariables(M, Used, false);
173
174   // We must assume that globals in llvm.used have a reference that not even
175   // the linker can see, so we don't internalize them.
176   // For llvm.compiler.used the situation is a bit fuzzy. The assembler and
177   // linker can drop those symbols. If this pass is running as part of LTO,
178   // one might think that it could just drop llvm.compiler.used. The problem
179   // is that even in LTO llvm doesn't see every reference. For example,
180   // we don't see references from function local inline assembly. To be
181   // conservative, we internalize symbols in llvm.compiler.used, but we
182   // keep llvm.compiler.used so that the symbol is not deleted by llvm.
183   for (SmallPtrSet<GlobalValue *, 8>::iterator I = Used.begin(), E = Used.end();
184        I != E; ++I) {
185     GlobalValue *V = *I;
186     ExternalNames.insert(V->getName());
187   }
188
189   // Mark all functions not in the api as internal.
190   // FIXME: maybe use private linkage?
191   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I) {
192     if (!shouldInternalize(*I, ExternalNames, DSONames))
193       continue;
194
195     I->setLinkage(GlobalValue::InternalLinkage);
196
197     if (ExternalNode)
198       // Remove a callgraph edge from the external node to this function.
199       ExternalNode->removeOneAbstractEdgeTo((*CG)[I]);
200
201     Changed = true;
202     ++NumFunctions;
203     DEBUG(dbgs() << "Internalizing func " << I->getName() << "\n");
204   }
205
206   // Never internalize the llvm.used symbol.  It is used to implement
207   // attribute((used)).
208   // FIXME: Shouldn't this just filter on llvm.metadata section??
209   ExternalNames.insert("llvm.used");
210   ExternalNames.insert("llvm.compiler.used");
211
212   // Never internalize anchors used by the machine module info, else the info
213   // won't find them.  (see MachineModuleInfo.)
214   ExternalNames.insert("llvm.global_ctors");
215   ExternalNames.insert("llvm.global_dtors");
216   ExternalNames.insert("llvm.global.annotations");
217
218   // Never internalize symbols code-gen inserts.
219   // FIXME: We should probably add this (and the __stack_chk_guard) via some
220   // type of call-back in CodeGen.
221   ExternalNames.insert("__stack_chk_fail");
222   ExternalNames.insert("__stack_chk_guard");
223
224   // Mark all global variables with initializers that are not in the api as
225   // internal as well.
226   // FIXME: maybe use private linkage?
227   for (Module::global_iterator I = M.global_begin(), E = M.global_end();
228        I != E; ++I) {
229     if (!shouldInternalize(*I, ExternalNames, DSONames))
230       continue;
231
232     I->setLinkage(GlobalValue::InternalLinkage);
233     Changed = true;
234     ++NumGlobals;
235     DEBUG(dbgs() << "Internalized gvar " << I->getName() << "\n");
236   }
237
238   // Mark all aliases that are not in the api as internal as well.
239   for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
240        I != E; ++I) {
241     if (!shouldInternalize(*I, ExternalNames, DSONames))
242       continue;
243
244     I->setLinkage(GlobalValue::InternalLinkage);
245     Changed = true;
246     ++NumAliases;
247     DEBUG(dbgs() << "Internalized alias " << I->getName() << "\n");
248   }
249
250   return Changed;
251 }
252
253 ModulePass *llvm::createInternalizePass() {
254   return new InternalizePass();
255 }
256
257 ModulePass *llvm::createInternalizePass(ArrayRef<const char *> ExportList,
258                                         ArrayRef<const char *> DSOList) {
259   return new InternalizePass(ExportList, DSOList);
260 }