text: //===-- ExtractGV.cpp - Global Value extraction pass ----------------------===//
  //
  //                     The LLVM Compiler Infrastructure
  //
  // This file is distributed under the University of Illinois Open Source
  // License. See LICENSE.TXT for details.
  //
  //===----------------------------------------------------------------------===//
  //
  // This pass extracts global values
  //
  //===----------------------------------------------------------------------===//
  
  #include "llvm/ADT/SetVector.h"
  #include "llvm/IR/LLVMContext.h"
  #include "llvm/IR/Module.h"
  #include "llvm/Pass.h"
  #include "llvm/Transforms/IPO.h"
  #include <algorithm>
  using namespace llvm;
  
  /// Make sure GV is visible from both modules. Delete is true if it is
  /// being deleted from this module.
  /// This also makes sure GV cannot be dropped so that references from
  /// the split module remain valid.
  static void makeVisible(GlobalValue &GV, bool Delete) {
    bool Local = GV.hasLocalLinkage();
    if (Local || Delete) {
      GV.setLinkage(GlobalValue::ExternalLinkage);
      if (Local)
        GV.setVisibility(GlobalValue::HiddenVisibility);
      return;
    }
  
    if (!GV.hasLinkOnceLinkage()) {
      assert(!GV.isDiscardableIfUnused());
      return;
    }
  
    // Map linkonce* to weak* so that llvm doesn't drop this GV.
    switch(GV.getLinkage()) {
    default:
      llvm_unreachable("Unexpected linkage");
    case GlobalValue::LinkOnceAnyLinkage:
      GV.setLinkage(GlobalValue::WeakAnyLinkage);
      return;
    case GlobalValue::LinkOnceODRLinkage:
      GV.setLinkage(GlobalValue::WeakODRLinkage);
      return;
    }
  }
  
  namespace {
    /// A pass to extract specific global values and their dependencies.
    class GVExtractorPass : public ModulePass {
      SetVector<GlobalValue *> Named;
      bool deleteStuff;
    public:
      static char ID; // Pass identification, replacement for typeid
  
      /// If deleteS is true, this pass deletes the specified global values.
      /// Otherwise, it deletes as much of the module as possible, except for the
      /// global values specified.
      explicit GVExtractorPass(std::vector<GlobalValue*> &GVs,
                               bool deleteS = true)
        : ModulePass(ID), Named(GVs.begin(), GVs.end()), deleteStuff(deleteS) {}
  
      bool runOnModule(Module &M) override {
        if (skipModule(M))
          return false;
  
        // Visit the global inline asm.
        if (!deleteStuff)
          M.setModuleInlineAsm("");
  
        // For simplicity, just give all GlobalValues ExternalLinkage. A trickier
        // implementation could figure out which GlobalValues are actually
        // referenced by the Named set, and which GlobalValues in the rest of
        // the module are referenced by the NamedSet, and get away with leaving
        // more internal and private things internal and private. But for now,
        // be conservative and simple.
  
        // Visit the GlobalVariables.
        for (Module::global_iterator I = M.global_begin(), E = M.global_end();
             I != E; ++I) {
          bool Delete =
              deleteStuff == (bool)Named.count(&*I) && !I->isDeclaration();
          if (!Delete) {
            if (I->hasAvailableExternallyLinkage())
              continue;
            if (I->getName() == "llvm.global_ctors")
              continue;
          }
  
          makeVisible(*I, Delete);
  
          if (Delete) {
            // Make this a declaration and drop it's comdat.
            I->setInitializer(nullptr);
            I->setComdat(nullptr);
          }
        }
  
        // Visit the Functions.
        for (Function &F : M) {
          bool Delete =
              deleteStuff == (bool)Named.count(&F) && !F.isDeclaration();
          if (!Delete) {
            if (F.hasAvailableExternallyLinkage())
              continue;
          }
  
          makeVisible(F, Delete);
  
          if (Delete) {
            // Make this a declaration and drop it's comdat.
            F.deleteBody();
            F.setComdat(nullptr);
          }
        }
  
        // Visit the Aliases.
        for (Module::alias_iterator I = M.alias_begin(), E = M.alias_end();
             I != E;) {
          Module::alias_iterator CurI = I;
          ++I;
  
          bool Delete = deleteStuff == (bool)Named.count(&*CurI);
          makeVisible(*CurI, Delete);
  
          if (Delete) {
            Type *Ty =  CurI->getValueType();
  
            CurI->removeFromParent();
            llvm::Value *Declaration;
            if (FunctionType *FTy = dyn_cast<FunctionType>(Ty)) {
              Declaration = Function::Create(FTy, GlobalValue::ExternalLinkage,
                                             CurI->getName(), &M);
  
            } else {
              Declaration =
                new GlobalVariable(M, Ty, false, GlobalValue::ExternalLinkage,
                                   nullptr, CurI->getName());
  
            }
            CurI->replaceAllUsesWith(Declaration);
            delete &*CurI;
          }
        }
  
        return true;
      }
    };
  
    char GVExtractorPass::ID = 0;
  }
  
  ModulePass *llvm::createGVExtractionPass(std::vector<GlobalValue *> &GVs,
                                           bool deleteFn) {
    return new GVExtractorPass(GVs, deleteFn);
  }
  