Home | History | Annotate | Download | only in IPO
      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 //===----------------------------------------------------------------------===//
     15 
     16 #define DEBUG_TYPE "internalize"
     17 #include "llvm/Transforms/IPO.h"
     18 #include "llvm/ADT/Statistic.h"
     19 #include "llvm/Analysis/CallGraph.h"
     20 #include "llvm/IR/Module.h"
     21 #include "llvm/Pass.h"
     22 #include "llvm/Support/CommandLine.h"
     23 #include "llvm/Support/Debug.h"
     24 #include "llvm/Support/raw_ostream.h"
     25 #include <fstream>
     26 #include <set>
     27 using namespace llvm;
     28 
     29 STATISTIC(NumAliases  , "Number of aliases internalized");
     30 STATISTIC(NumFunctions, "Number of functions internalized");
     31 STATISTIC(NumGlobals  , "Number of global vars internalized");
     32 
     33 // APIFile - A file which contains a list of symbols that should not be marked
     34 // external.
     35 static cl::opt<std::string>
     36 APIFile("internalize-public-api-file", cl::value_desc("filename"),
     37         cl::desc("A file containing list of symbol names to preserve"));
     38 
     39 // APIList - A list of symbols that should not be marked internal.
     40 static cl::list<std::string>
     41 APIList("internalize-public-api-list", cl::value_desc("list"),
     42         cl::desc("A list of symbol names to preserve"),
     43         cl::CommaSeparated);
     44 
     45 namespace {
     46   class InternalizePass : public ModulePass {
     47     std::set<std::string> ExternalNames;
     48   public:
     49     static char ID; // Pass identification, replacement for typeid
     50     explicit InternalizePass();
     51     explicit InternalizePass(ArrayRef<const char *> exportList);
     52     void LoadFile(const char *Filename);
     53     void ClearExportList();
     54     void AddToExportList(const std::string &val);
     55     virtual bool runOnModule(Module &M);
     56 
     57     virtual void getAnalysisUsage(AnalysisUsage &AU) const {
     58       AU.setPreservesCFG();
     59       AU.addPreserved<CallGraph>();
     60     }
     61   };
     62 } // end anonymous namespace
     63 
     64 char InternalizePass::ID = 0;
     65 INITIALIZE_PASS(InternalizePass, "internalize",
     66                 "Internalize Global Symbols", false, false)
     67 
     68 InternalizePass::InternalizePass()
     69   : ModulePass(ID) {
     70   initializeInternalizePassPass(*PassRegistry::getPassRegistry());
     71   if (!APIFile.empty())           // If a filename is specified, use it.
     72     LoadFile(APIFile.c_str());
     73   if (!APIList.empty())           // If a list is specified, use it as well.
     74     ExternalNames.insert(APIList.begin(), APIList.end());
     75 }
     76 
     77 InternalizePass::InternalizePass(ArrayRef<const char *> exportList)
     78   : ModulePass(ID){
     79   initializeInternalizePassPass(*PassRegistry::getPassRegistry());
     80   for(ArrayRef<const char *>::const_iterator itr = exportList.begin();
     81         itr != exportList.end(); itr++) {
     82     ExternalNames.insert(*itr);
     83   }
     84 }
     85 
     86 void InternalizePass::LoadFile(const char *Filename) {
     87   // Load the APIFile...
     88   std::ifstream In(Filename);
     89   if (!In.good()) {
     90     errs() << "WARNING: Internalize couldn't load file '" << Filename
     91          << "'! Continuing as if it's empty.\n";
     92     return; // Just continue as if the file were empty
     93   }
     94   while (In) {
     95     std::string Symbol;
     96     In >> Symbol;
     97     if (!Symbol.empty())
     98       ExternalNames.insert(Symbol);
     99   }
    100 }
    101 
    102 void InternalizePass::ClearExportList() {
    103   ExternalNames.clear();
    104 }
    105 
    106 void InternalizePass::AddToExportList(const std::string &val) {
    107   ExternalNames.insert(val);
    108 }
    109 
    110 bool InternalizePass::runOnModule(Module &M) {
    111   CallGraph *CG = getAnalysisIfAvailable<CallGraph>();
    112   CallGraphNode *ExternalNode = CG ? CG->getExternalCallingNode() : 0;
    113   bool Changed = false;
    114 
    115   // Never internalize functions which code-gen might insert.
    116   // FIXME: We should probably add this (and the __stack_chk_guard) via some
    117   // type of call-back in CodeGen.
    118   ExternalNames.insert("__stack_chk_fail");
    119 
    120   // Mark all functions not in the api as internal.
    121   // FIXME: maybe use private linkage?
    122   for (Module::iterator I = M.begin(), E = M.end(); I != E; ++I)
    123     if (!I->isDeclaration() &&         // Function must be defined here
    124         // Available externally is really just a "declaration with a body".
    125         !I->hasAvailableExternallyLinkage() &&
    126         !I->hasLocalLinkage() &&  // Can't already have internal linkage
    127         !ExternalNames.count(I->getName())) {// Not marked to keep external?
    128       I->setLinkage(GlobalValue::InternalLinkage);
    129       // Remove a callgraph edge from the external node to this function.
    130       if (ExternalNode) ExternalNode->removeOneAbstractEdgeTo((*CG)[I]);
    131       Changed = true;
    132       ++NumFunctions;
    133       DEBUG(dbgs() << "Internalizing func " << I->getName() << "\n");
    134     }
    135 
    136   // Never internalize the llvm.used symbol.  It is used to implement
    137   // attribute((used)).
    138   // FIXME: Shouldn't this just filter on llvm.metadata section??
    139   ExternalNames.insert("llvm.used");
    140   ExternalNames.insert("llvm.compiler.used");
    141 
    142   // Never internalize anchors used by the machine module info, else the info
    143   // won't find them.  (see MachineModuleInfo.)
    144   ExternalNames.insert("llvm.global_ctors");
    145   ExternalNames.insert("llvm.global_dtors");
    146   ExternalNames.insert("llvm.global.annotations");
    147 
    148   // Never internalize symbols code-gen inserts.
    149   ExternalNames.insert("__stack_chk_guard");
    150 
    151   // Mark all global variables with initializers that are not in the api as
    152   // internal as well.
    153   // FIXME: maybe use private linkage?
    154   for (Module::global_iterator I = M.global_begin(), E = M.global_end();
    155        I != E; ++I)
    156     if (!I->isDeclaration() && !I->hasLocalLinkage() &&
    157         // Available externally is really just a "declaration with a body".
    158         !I->hasAvailableExternallyLinkage() &&
    159         !ExternalNames.count(I->getName())) {
    160       I->setLinkage(GlobalValue::InternalLinkage);
    161       Changed = true;
    162       ++NumGlobals;
    163       DEBUG(dbgs() << "Internalized gvar " << I->getName() << "\n");
    164     }
    165 
    166   // Mark all aliases that are not in the api as internal as well.
    167   for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
    168        I != E; ++I)
    169     if (!I->isDeclaration() && !I->hasInternalLinkage() &&
    170         // Available externally is really just a "declaration with a body".
    171         !I->hasAvailableExternallyLinkage() &&
    172         !ExternalNames.count(I->getName())) {
    173       I->setLinkage(GlobalValue::InternalLinkage);
    174       Changed = true;
    175       ++NumAliases;
    176       DEBUG(dbgs() << "Internalized alias " << I->getName() << "\n");
    177     }
    178 
    179   return Changed;
    180 }
    181 
    182 ModulePass *llvm::createInternalizePass() {
    183   return new InternalizePass();
    184 }
    185 
    186 ModulePass *llvm::createInternalizePass(ArrayRef<const char *> el) {
    187   return new InternalizePass(el);
    188 }
    189