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:
PreserveAPIList()603ca95b02SDimitry Andric PreserveAPIList() {
613ca95b02SDimitry Andric if (!APIFile.empty())
623ca95b02SDimitry Andric LoadFile(APIFile);
63f22ef01cSRoman Divacky ExternalNames.insert(APIList.begin(), APIList.end());
64f22ef01cSRoman Divacky }
65f22ef01cSRoman Divacky
operator ()(const GlobalValue & GV)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
LoadFile(StringRef Filename)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
shouldPreserveGV(const GlobalValue & GV)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
maybeInternalize(GlobalValue & GV,const std::set<const Comdat * > & ExternalComdats)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.
checkComdatVisibility(GlobalValue & GV,std::set<const Comdat * > & ExternalComdats)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
internalizeModule(Module & M,CallGraph * CG)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;
195*4ba319b5SDimitry Andric LLVM_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;
224*4ba319b5SDimitry Andric LLVM_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;
234*4ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Internalized alias " << GA.getName() << "\n");
235f22ef01cSRoman Divacky }
236f22ef01cSRoman Divacky
2373ca95b02SDimitry Andric return Changed;
238f22ef01cSRoman Divacky }
239f22ef01cSRoman Divacky
InternalizePass()2403ca95b02SDimitry Andric InternalizePass::InternalizePass() : MustPreserveGV(PreserveAPIList()) {}
241f22ef01cSRoman Divacky
run(Module & M,ModuleAnalysisManager & AM)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
InternalizeLegacyPass()2593ca95b02SDimitry Andric InternalizeLegacyPass() : ModulePass(ID), MustPreserveGV(PreserveAPIList()) {}
2603ca95b02SDimitry Andric
InternalizeLegacyPass(std::function<bool (const GlobalValue &)> MustPreserveGV)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
runOnModule(Module & M)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
getAnalysisUsage(AnalysisUsage & AU) const2763ca95b02SDimitry 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
createInternalizePass()2873ca95b02SDimitry Andric ModulePass *llvm::createInternalizePass() {
2883ca95b02SDimitry Andric return new InternalizeLegacyPass();
2893ca95b02SDimitry Andric }
2903ca95b02SDimitry Andric
createInternalizePass(std::function<bool (const GlobalValue &)> MustPreserveGV)2913ca95b02SDimitry Andric ModulePass *llvm::createInternalizePass(
2923ca95b02SDimitry Andric std::function<bool(const GlobalValue &)> MustPreserveGV) {
2933ca95b02SDimitry Andric return new InternalizeLegacyPass(std::move(MustPreserveGV));
294f22ef01cSRoman Divacky }
295