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 242d88c1a5aSDimitry Andric PreservedAnalyses InternalizePass::run(Module &M, ModuleAnalysisManager &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