1f22ef01cSRoman Divacky //===-- Internalize.cpp - Mark functions internal -------------------------===//
2f22ef01cSRoman Divacky //
3f22ef01cSRoman Divacky //                     The LLVM Compiler Infrastructure
4f22ef01cSRoman Divacky //
5f22ef01cSRoman Divacky // This file is distributed under the University of Illinois Open Source
6f22ef01cSRoman Divacky // License. See LICENSE.TXT for details.
7f22ef01cSRoman Divacky //
8f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
9f22ef01cSRoman Divacky //
103861d79fSDimitry Andric // This pass loops over all of the functions and variables in the input module.
113ca95b02SDimitry Andric // If the function or variable does not need to be preserved according to the
123ca95b02SDimitry Andric // client supplied callback, it is marked as internal.
13f22ef01cSRoman Divacky //
14f785676fSDimitry Andric // This transformation would not be legal in a regular compilation, but it gets
15f785676fSDimitry Andric // extra information from the linker about what is safe.
16f785676fSDimitry Andric //
17f785676fSDimitry Andric // For example: Internalizing a function with external linkage. Only if we are
18f785676fSDimitry Andric // told it is only used from within this module, it is safe to do it.
19f785676fSDimitry Andric //
20f22ef01cSRoman Divacky //===----------------------------------------------------------------------===//
21f22ef01cSRoman Divacky 
223ca95b02SDimitry Andric #include "llvm/Transforms/IPO/Internalize.h"
23f785676fSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
24139f7f9bSDimitry Andric #include "llvm/ADT/Statistic.h"
253ca95b02SDimitry Andric #include "llvm/ADT/StringSet.h"
26139f7f9bSDimitry Andric #include "llvm/Analysis/CallGraph.h"
27139f7f9bSDimitry Andric #include "llvm/IR/Module.h"
28f22ef01cSRoman Divacky #include "llvm/Pass.h"
29f22ef01cSRoman Divacky #include "llvm/Support/CommandLine.h"
30f22ef01cSRoman Divacky #include "llvm/Support/Debug.h"
31f22ef01cSRoman Divacky #include "llvm/Support/raw_ostream.h"
323ca95b02SDimitry Andric #include "llvm/Transforms/IPO.h"
33f785676fSDimitry Andric #include "llvm/Transforms/Utils/GlobalStatus.h"
34f22ef01cSRoman Divacky #include <fstream>
35f22ef01cSRoman Divacky #include <set>
36f22ef01cSRoman Divacky using namespace llvm;
37f22ef01cSRoman Divacky 
3891bc56edSDimitry Andric #define DEBUG_TYPE "internalize"
3991bc56edSDimitry Andric 
40f22ef01cSRoman Divacky STATISTIC(NumAliases, "Number of aliases internalized");
41f22ef01cSRoman Divacky STATISTIC(NumFunctions, "Number of functions internalized");
42f22ef01cSRoman Divacky STATISTIC(NumGlobals, "Number of global vars internalized");
43f22ef01cSRoman Divacky 
44f22ef01cSRoman Divacky // APIFile - A file which contains a list of symbols that should not be marked
45f22ef01cSRoman Divacky // external.
46f22ef01cSRoman Divacky static cl::opt<std::string>
47f22ef01cSRoman Divacky     APIFile("internalize-public-api-file", cl::value_desc("filename"),
48f22ef01cSRoman Divacky             cl::desc("A file containing list of symbol names to preserve"));
49f22ef01cSRoman Divacky 
50f22ef01cSRoman Divacky // APIList - A list of symbols that should not be marked internal.
51f22ef01cSRoman Divacky static cl::list<std::string>
52f22ef01cSRoman Divacky     APIList("internalize-public-api-list", cl::value_desc("list"),
533ca95b02SDimitry Andric             cl::desc("A list of symbol names to preserve"), cl::CommaSeparated);
54f22ef01cSRoman Divacky 
55f22ef01cSRoman Divacky namespace {
563ca95b02SDimitry Andric // Helper to load an API list to preserve from file and expose it as a functor
573ca95b02SDimitry Andric // for internalization.
583ca95b02SDimitry Andric class PreserveAPIList {
59f22ef01cSRoman Divacky public:
603ca95b02SDimitry Andric   PreserveAPIList() {
613ca95b02SDimitry Andric     if (!APIFile.empty())
623ca95b02SDimitry Andric       LoadFile(APIFile);
63f22ef01cSRoman Divacky     ExternalNames.insert(APIList.begin(), APIList.end());
64f22ef01cSRoman Divacky   }
65f22ef01cSRoman Divacky 
663ca95b02SDimitry Andric   bool operator()(const GlobalValue &GV) {
673ca95b02SDimitry Andric     return ExternalNames.count(GV.getName());
68f22ef01cSRoman Divacky   }
69f22ef01cSRoman Divacky 
703ca95b02SDimitry Andric private:
713ca95b02SDimitry Andric   // Contains the set of symbols loaded from file
723ca95b02SDimitry Andric   StringSet<> ExternalNames;
733ca95b02SDimitry Andric 
743ca95b02SDimitry Andric   void LoadFile(StringRef Filename) {
75f22ef01cSRoman Divacky     // Load the APIFile...
763ca95b02SDimitry Andric     std::ifstream In(Filename.data());
77f22ef01cSRoman Divacky     if (!In.good()) {
78f22ef01cSRoman Divacky       errs() << "WARNING: Internalize couldn't load file '" << Filename
79f22ef01cSRoman Divacky              << "'! Continuing as if it's empty.\n";
80f22ef01cSRoman Divacky       return; // Just continue as if the file were empty
81f22ef01cSRoman Divacky     }
82f22ef01cSRoman Divacky     while (In) {
83f22ef01cSRoman Divacky       std::string Symbol;
84f22ef01cSRoman Divacky       In >> Symbol;
85f22ef01cSRoman Divacky       if (!Symbol.empty())
86f22ef01cSRoman Divacky         ExternalNames.insert(Symbol);
87f22ef01cSRoman Divacky     }
88f22ef01cSRoman Divacky   }
893ca95b02SDimitry Andric };
903ca95b02SDimitry Andric } // end anonymous namespace
91f22ef01cSRoman Divacky 
923ca95b02SDimitry Andric bool InternalizePass::shouldPreserveGV(const GlobalValue &GV) {
93f785676fSDimitry Andric   // Function must be defined here
94f785676fSDimitry Andric   if (GV.isDeclaration())
957d523365SDimitry Andric     return true;
96139f7f9bSDimitry Andric 
97f785676fSDimitry Andric   // Available externally is really just a "declaration with a body".
98f785676fSDimitry Andric   if (GV.hasAvailableExternallyLinkage())
997d523365SDimitry Andric     return true;
100f785676fSDimitry Andric 
10191bc56edSDimitry Andric   // Assume that dllexported symbols are referenced elsewhere
10291bc56edSDimitry Andric   if (GV.hasDLLExportStorageClass())
1037d523365SDimitry Andric     return true;
1047d523365SDimitry Andric 
1053ca95b02SDimitry Andric   // Already local, has nothing to do.
1063ca95b02SDimitry Andric   if (GV.hasLocalLinkage())
1073ca95b02SDimitry Andric     return false;
1083ca95b02SDimitry Andric 
1093ca95b02SDimitry Andric   // Check some special cases
1103ca95b02SDimitry Andric   if (AlwaysPreserved.count(GV.getName()))
1117d523365SDimitry Andric     return true;
1127d523365SDimitry Andric 
1133ca95b02SDimitry Andric   return MustPreserveGV(GV);
1147d523365SDimitry Andric }
1157d523365SDimitry Andric 
1167d523365SDimitry Andric bool InternalizePass::maybeInternalize(
1177d523365SDimitry Andric     GlobalValue &GV, const std::set<const Comdat *> &ExternalComdats) {
1187d523365SDimitry Andric   if (Comdat *C = GV.getComdat()) {
1197d523365SDimitry Andric     if (ExternalComdats.count(C))
12091bc56edSDimitry Andric       return false;
12191bc56edSDimitry Andric 
1227d523365SDimitry Andric     // If a comdat is not externally visible we can drop it.
1237d523365SDimitry Andric     if (auto GO = dyn_cast<GlobalObject>(&GV))
1247d523365SDimitry Andric       GO->setComdat(nullptr);
1257d523365SDimitry Andric 
1267d523365SDimitry Andric     if (GV.hasLocalLinkage())
1277d523365SDimitry Andric       return false;
1287d523365SDimitry Andric   } else {
129f785676fSDimitry Andric     if (GV.hasLocalLinkage())
130f785676fSDimitry Andric       return false;
131f785676fSDimitry Andric 
1323ca95b02SDimitry Andric     if (shouldPreserveGV(GV))
133f785676fSDimitry Andric       return false;
1347d523365SDimitry Andric   }
135f785676fSDimitry Andric 
1367d523365SDimitry Andric   GV.setVisibility(GlobalValue::DefaultVisibility);
1377d523365SDimitry Andric   GV.setLinkage(GlobalValue::InternalLinkage);
138f785676fSDimitry Andric   return true;
139139f7f9bSDimitry Andric }
140139f7f9bSDimitry Andric 
1417d523365SDimitry Andric // If GV is part of a comdat and is externally visible, keep track of its
1427d523365SDimitry Andric // comdat so that we don't internalize any of its members.
1437d523365SDimitry Andric void InternalizePass::checkComdatVisibility(
1447d523365SDimitry Andric     GlobalValue &GV, std::set<const Comdat *> &ExternalComdats) {
1457d523365SDimitry Andric   Comdat *C = GV.getComdat();
1467d523365SDimitry Andric   if (!C)
1477d523365SDimitry Andric     return;
1487d523365SDimitry Andric 
1493ca95b02SDimitry Andric   if (shouldPreserveGV(GV))
1507d523365SDimitry Andric     ExternalComdats.insert(C);
1517d523365SDimitry Andric }
1527d523365SDimitry Andric 
1533ca95b02SDimitry Andric bool InternalizePass::internalizeModule(Module &M, CallGraph *CG) {
1543ca95b02SDimitry Andric   bool Changed = false;
15591bc56edSDimitry Andric   CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : nullptr;
156f22ef01cSRoman Divacky 
157f785676fSDimitry Andric   SmallPtrSet<GlobalValue *, 8> Used;
158f785676fSDimitry Andric   collectUsedGlobalVariables(M, Used, false);
159f785676fSDimitry Andric 
1607d523365SDimitry Andric   // Collect comdat visiblity information for the module.
1617d523365SDimitry Andric   std::set<const Comdat *> ExternalComdats;
1627d523365SDimitry Andric   if (!M.getComdatSymbolTable().empty()) {
1637d523365SDimitry Andric     for (Function &F : M)
1647d523365SDimitry Andric       checkComdatVisibility(F, ExternalComdats);
1657d523365SDimitry Andric     for (GlobalVariable &GV : M.globals())
1667d523365SDimitry Andric       checkComdatVisibility(GV, ExternalComdats);
1677d523365SDimitry Andric     for (GlobalAlias &GA : M.aliases())
1687d523365SDimitry Andric       checkComdatVisibility(GA, ExternalComdats);
1697d523365SDimitry Andric   }
1707d523365SDimitry Andric 
171f785676fSDimitry Andric   // We must assume that globals in llvm.used have a reference that not even
172f785676fSDimitry Andric   // the linker can see, so we don't internalize them.
173f785676fSDimitry Andric   // For llvm.compiler.used the situation is a bit fuzzy. The assembler and
174f785676fSDimitry Andric   // linker can drop those symbols. If this pass is running as part of LTO,
175f785676fSDimitry Andric   // one might think that it could just drop llvm.compiler.used. The problem
176f785676fSDimitry Andric   // is that even in LTO llvm doesn't see every reference. For example,
177f785676fSDimitry Andric   // we don't see references from function local inline assembly. To be
178f785676fSDimitry Andric   // conservative, we internalize symbols in llvm.compiler.used, but we
179f785676fSDimitry Andric   // keep llvm.compiler.used so that the symbol is not deleted by llvm.
18039d628a0SDimitry Andric   for (GlobalValue *V : Used) {
1813ca95b02SDimitry Andric     AlwaysPreserved.insert(V->getName());
182f785676fSDimitry Andric   }
183dff0c46cSDimitry Andric 
184f22ef01cSRoman Divacky   // Mark all functions not in the api as internal.
1857d523365SDimitry Andric   for (Function &I : M) {
1867d523365SDimitry Andric     if (!maybeInternalize(I, ExternalComdats))
187f785676fSDimitry Andric       continue;
1883ca95b02SDimitry Andric     Changed = true;
189f785676fSDimitry Andric 
190f785676fSDimitry Andric     if (ExternalNode)
191f22ef01cSRoman Divacky       // Remove a callgraph edge from the external node to this function.
1927d523365SDimitry Andric       ExternalNode->removeOneAbstractEdgeTo((*CG)[&I]);
193f785676fSDimitry Andric 
194f22ef01cSRoman Divacky     ++NumFunctions;
1957d523365SDimitry Andric     DEBUG(dbgs() << "Internalizing func " << I.getName() << "\n");
196f22ef01cSRoman Divacky   }
197f22ef01cSRoman Divacky 
198f22ef01cSRoman Divacky   // Never internalize the llvm.used symbol.  It is used to implement
199f22ef01cSRoman Divacky   // attribute((used)).
200f22ef01cSRoman Divacky   // FIXME: Shouldn't this just filter on llvm.metadata section??
2013ca95b02SDimitry Andric   AlwaysPreserved.insert("llvm.used");
2023ca95b02SDimitry Andric   AlwaysPreserved.insert("llvm.compiler.used");
203f22ef01cSRoman Divacky 
204f22ef01cSRoman Divacky   // Never internalize anchors used by the machine module info, else the info
205f22ef01cSRoman Divacky   // won't find them.  (see MachineModuleInfo.)
2063ca95b02SDimitry Andric   AlwaysPreserved.insert("llvm.global_ctors");
2073ca95b02SDimitry Andric   AlwaysPreserved.insert("llvm.global_dtors");
2083ca95b02SDimitry Andric   AlwaysPreserved.insert("llvm.global.annotations");
209f22ef01cSRoman Divacky 
210dff0c46cSDimitry Andric   // Never internalize symbols code-gen inserts.
211f785676fSDimitry Andric   // FIXME: We should probably add this (and the __stack_chk_guard) via some
212f785676fSDimitry Andric   // type of call-back in CodeGen.
2133ca95b02SDimitry Andric   AlwaysPreserved.insert("__stack_chk_fail");
2143ca95b02SDimitry Andric   AlwaysPreserved.insert("__stack_chk_guard");
215dff0c46cSDimitry Andric 
216f22ef01cSRoman Divacky   // Mark all global variables with initializers that are not in the api as
217f22ef01cSRoman Divacky   // internal as well.
2183ca95b02SDimitry Andric   for (auto &GV : M.globals()) {
2193ca95b02SDimitry Andric     if (!maybeInternalize(GV, ExternalComdats))
220f785676fSDimitry Andric       continue;
2213ca95b02SDimitry Andric     Changed = true;
222f785676fSDimitry Andric 
223f22ef01cSRoman Divacky     ++NumGlobals;
2243ca95b02SDimitry Andric     DEBUG(dbgs() << "Internalized gvar " << GV.getName() << "\n");
225f22ef01cSRoman Divacky   }
226f22ef01cSRoman Divacky 
227f22ef01cSRoman Divacky   // Mark all aliases that are not in the api as internal as well.
2283ca95b02SDimitry Andric   for (auto &GA : M.aliases()) {
2293ca95b02SDimitry Andric     if (!maybeInternalize(GA, ExternalComdats))
230f785676fSDimitry Andric       continue;
2313ca95b02SDimitry Andric     Changed = true;
232f785676fSDimitry Andric 
233f22ef01cSRoman Divacky     ++NumAliases;
2343ca95b02SDimitry Andric     DEBUG(dbgs() << "Internalized alias " << GA.getName() << "\n");
235f22ef01cSRoman Divacky   }
236f22ef01cSRoman Divacky 
2373ca95b02SDimitry Andric   return Changed;
238f22ef01cSRoman Divacky }
239f22ef01cSRoman Divacky 
2403ca95b02SDimitry Andric InternalizePass::InternalizePass() : MustPreserveGV(PreserveAPIList()) {}
241f22ef01cSRoman Divacky 
2423ca95b02SDimitry Andric PreservedAnalyses InternalizePass::run(Module &M, AnalysisManager<Module> &AM) {
2433ca95b02SDimitry Andric   if (!internalizeModule(M, AM.getCachedResult<CallGraphAnalysis>(M)))
2443ca95b02SDimitry Andric     return PreservedAnalyses::all();
2453ca95b02SDimitry Andric 
2463ca95b02SDimitry Andric   PreservedAnalyses PA;
2473ca95b02SDimitry Andric   PA.preserve<CallGraphAnalysis>();
2483ca95b02SDimitry Andric   return PA;
2493ca95b02SDimitry Andric }
2503ca95b02SDimitry Andric 
2513ca95b02SDimitry Andric namespace {
2523ca95b02SDimitry Andric class InternalizeLegacyPass : public ModulePass {
2533ca95b02SDimitry Andric   // Client supplied callback to control wheter a symbol must be preserved.
2543ca95b02SDimitry Andric   std::function<bool(const GlobalValue &)> MustPreserveGV;
2553ca95b02SDimitry Andric 
2563ca95b02SDimitry Andric public:
2573ca95b02SDimitry Andric   static char ID; // Pass identification, replacement for typeid
2583ca95b02SDimitry Andric 
2593ca95b02SDimitry Andric   InternalizeLegacyPass() : ModulePass(ID), MustPreserveGV(PreserveAPIList()) {}
2603ca95b02SDimitry Andric 
2613ca95b02SDimitry Andric   InternalizeLegacyPass(std::function<bool(const GlobalValue &)> MustPreserveGV)
2623ca95b02SDimitry Andric       : ModulePass(ID), MustPreserveGV(std::move(MustPreserveGV)) {
2633ca95b02SDimitry Andric     initializeInternalizeLegacyPassPass(*PassRegistry::getPassRegistry());
2643ca95b02SDimitry Andric   }
2653ca95b02SDimitry Andric 
2663ca95b02SDimitry Andric   bool runOnModule(Module &M) override {
2673ca95b02SDimitry Andric     if (skipModule(M))
2683ca95b02SDimitry Andric       return false;
2693ca95b02SDimitry Andric 
2703ca95b02SDimitry Andric     CallGraphWrapperPass *CGPass =
2713ca95b02SDimitry Andric         getAnalysisIfAvailable<CallGraphWrapperPass>();
2723ca95b02SDimitry Andric     CallGraph *CG = CGPass ? &CGPass->getCallGraph() : nullptr;
2733ca95b02SDimitry Andric     return internalizeModule(M, MustPreserveGV, CG);
2743ca95b02SDimitry Andric   }
2753ca95b02SDimitry Andric 
2763ca95b02SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
2773ca95b02SDimitry Andric     AU.setPreservesCFG();
2783ca95b02SDimitry Andric     AU.addPreserved<CallGraphWrapperPass>();
2793ca95b02SDimitry Andric   }
2803ca95b02SDimitry Andric };
2813ca95b02SDimitry Andric }
2823ca95b02SDimitry Andric 
2833ca95b02SDimitry Andric char InternalizeLegacyPass::ID = 0;
2843ca95b02SDimitry Andric INITIALIZE_PASS(InternalizeLegacyPass, "internalize",
2853ca95b02SDimitry Andric                 "Internalize Global Symbols", false, false)
2863ca95b02SDimitry Andric 
2873ca95b02SDimitry Andric ModulePass *llvm::createInternalizePass() {
2883ca95b02SDimitry Andric   return new InternalizeLegacyPass();
2893ca95b02SDimitry Andric }
2903ca95b02SDimitry Andric 
2913ca95b02SDimitry Andric ModulePass *llvm::createInternalizePass(
2923ca95b02SDimitry Andric     std::function<bool(const GlobalValue &)> MustPreserveGV) {
2933ca95b02SDimitry Andric   return new InternalizeLegacyPass(std::move(MustPreserveGV));
294f22ef01cSRoman Divacky }
295