//===- SplitModule.cpp - Split a module into partitions -------------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines the function llvm::SplitModule, which splits a module // into multiple linkable partitions. It can be used to implement parallel code // generation for link-time optimization. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/SplitModule.h" #include "llvm/ADT/Hashing.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalAlias.h" #include "llvm/IR/GlobalObject.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Module.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/Cloning.h" using namespace llvm; static void externalize(GlobalValue *GV) { if (GV->hasLocalLinkage()) { GV->setLinkage(GlobalValue::ExternalLinkage); GV->setVisibility(GlobalValue::HiddenVisibility); } // Unnamed entities must be named consistently between modules. setName will // give a distinct name to each such entity. if (!GV->hasName()) GV->setName("__llvmsplit_unnamed"); } // Returns whether GV should be in partition (0-based) I of N. static bool isInPartition(const GlobalValue *GV, unsigned I, unsigned N) { if (auto GA = dyn_cast(GV)) if (const GlobalObject *Base = GA->getBaseObject()) GV = Base; StringRef Name; if (const Comdat *C = GV->getComdat()) Name = C->getName(); else Name = GV->getName(); // Partition by MD5 hash. We only need a few bits for evenness as the number // of partitions will generally be in the 1-2 figure range; the low 16 bits // are enough. MD5 H; MD5::MD5Result R; H.update(Name); H.final(R); return (R[0] | (R[1] << 8)) % N == I; } void llvm::SplitModule( std::unique_ptr M, unsigned N, std::function MPart)> ModuleCallback) { for (Function &F : *M) externalize(&F); for (GlobalVariable &GV : M->globals()) externalize(&GV); for (GlobalAlias &GA : M->aliases()) externalize(&GA); // FIXME: We should be able to reuse M as the last partition instead of // cloning it. for (unsigned I = 0; I != N; ++I) { ValueToValueMapTy VMap; std::unique_ptr MPart( CloneModule(M.get(), VMap, [=](const GlobalValue *GV) { return isInPartition(GV, I, N); })); if (I != 0) MPart->setModuleInlineAsm(""); ModuleCallback(std::move(MPart)); } }