27#define DEBUG_TYPE "split-module-by-category"
35struct EntryPointGroup {
37 EntryPointSet Functions;
39 EntryPointGroup() =
default;
41 EntryPointGroup(
int ID, EntryPointSet &&Functions = EntryPointSet())
42 :
ID(
ID), Functions(std::move(Functions)) {}
44 void clear() { Functions.clear(); }
46#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
48 constexpr size_t INDENT = 4;
50 <<
" " <<
ID <<
" {\n";
52 dbgs().
indent(INDENT) <<
" " <<
F->getName() <<
"\n";
63 std::unique_ptr<Module> M;
64 EntryPointGroup EntryPoints;
67 ModuleDesc(std::unique_ptr<Module> M,
68 EntryPointGroup &&EntryPoints = EntryPointGroup())
69 : M(std::move(M)), EntryPoints(std::move(EntryPoints)) {
70 assert(this->M &&
"Module should be non-null");
73 Module &getModule() {
return *M; }
74 const Module &getModule()
const {
return *M; }
76 std::unique_ptr<Module> releaseModule() {
81#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
83 dbgs() <<
"ModuleDesc[" << M->getName() <<
"] {\n";
118class DependencyGraph {
122 DependencyGraph(
const Module &M) {
126 for (
const Function &
F : M.functions()) {
131 FuncTypeToFuncsMap[
F.getFunctionType()].
insert(&
F);
134 for (
const Function &
F : M.functions()) {
136 for (
const Value *U :
F.users())
137 addUserToGraphRecursively(cast<const User>(U), &
F);
141 const CallBase *CB = dyn_cast<CallBase>(&
I);
146 GlobalSet &PotentialCallees = FuncTypeToFuncsMap[Signature];
147 Graph[&
F].
insert(PotentialCallees.begin(), PotentialCallees.end());
153 for (
const Value *U : GV.users())
154 addUserToGraphRecursively(cast<const User>(U), &GV);
159 auto It = Graph.find(Val);
160 return (It == Graph.end())
161 ?
make_range(EmptySet.begin(), EmptySet.end())
162 :
make_range(It->second.begin(), It->second.end());
166 void addUserToGraphRecursively(
const User *Root,
const GlobalValue *V) {
170 while (!WorkList.
empty()) {
172 if (
const auto *
I = dyn_cast<const Instruction>(U)) {
173 const Function *UFunc =
I->getFunction();
174 Graph[UFunc].insert(V);
175 }
else if (isa<const Constant>(U)) {
176 if (
const auto *GV = dyn_cast<const GlobalVariable>(U))
181 for (
const User *UU : U->users())
193void collectFunctionsAndGlobalVariablesToExtract(
195 const EntryPointGroup &ModuleEntryPoints,
const DependencyGraph &DG) {
197 for (
const Function *
F : ModuleEntryPoints.Functions)
202 if (!GV.isDiscardableIfUnused())
211 for (
const GlobalValue *Dep : DG.dependencies(Obj)) {
212 if (
const auto *Func = dyn_cast<const Function>(Dep)) {
213 if (!Func->isDeclaration())
224 EntryPointGroup &&ModuleEntryPoints) {
231 EntryPointSet NewEPs;
232 const EntryPointSet &EPs = ModuleEntryPoints.Functions;
234 EPs, [&](
const Function *
F) { NewEPs.insert(cast<Function>(VMap[
F])); });
235 ModuleEntryPoints.Functions = std::move(NewEPs);
236 return ModuleDesc{std::move(SubM), std::move(ModuleEntryPoints)};
242ModuleDesc extractCallGraph(
const Module &M,
243 EntryPointGroup &&ModuleEntryPoints,
244 const DependencyGraph &DG) {
246 collectFunctionsAndGlobalVariablesToExtract(GVs, M, ModuleEntryPoints, DG);
259class ModuleSplitter {
261 std::unique_ptr<Module> M;
262 EntryPointGroupVec Groups;
266 EntryPointGroup drawEntryPointGroup() {
267 assert(Groups.size() > 0 &&
"Reached end of entry point groups list.");
268 EntryPointGroup Group = std::move(Groups.back());
274 ModuleSplitter(std::unique_ptr<Module>
Module, EntryPointGroupVec &&GroupVec)
275 : M(std::move(
Module)), Groups(std::move(GroupVec)), DG(*M) {
276 assert(!Groups.empty() &&
"Entry points groups collection is empty!");
281 ModuleDesc getNextSplit() {
282 return extractCallGraph(*M, drawEntryPointGroup(), DG);
286 bool hasMoreSplits()
const {
return Groups.size() > 0; }
289EntryPointGroupVec selectEntryPointGroups(
295 std::map<int, EntryPointSet> EntryPointsMap;
297 for (
const auto &
F : M.functions())
298 if (std::optional<int> Category = EPC(
F); Category)
299 EntryPointsMap[*Category].insert(&
F);
301 EntryPointGroupVec
Groups;
302 Groups.reserve(EntryPointsMap.size());
303 for (
auto &[Key, EntryPoints] : EntryPointsMap)
304 Groups.emplace_back(Key, std::move(EntryPoints));
312 std::unique_ptr<Module> M,
314 function_ref<
void(std::unique_ptr<Module> Part)> Callback) {
315 EntryPointGroupVec
Groups = selectEntryPointGroups(*M, EntryPointCategorizer);
316 ModuleSplitter Splitter(std::move(M), std::move(
Groups));
317 while (Splitter.hasMoreSplits()) {
318 ModuleDesc MD = Splitter.getNextSplit();
319 Callback(MD.releaseModule());
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static SmallVector< const DIVariable *, 2 > dependencies(DbgVariable *Var)
Return all DIVariables that appear in count: expressions.
static ThreadSafeModule extractSubModule(ThreadSafeModule &TSM, StringRef Suffix, GVPredicate ShouldExtract)
Module.h This file contains the declarations for the Module class.
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
static const X86InstrFMA3Group Groups[]
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
LLVM_ABI bool isIndirectCall() const
Return true if the callsite is an indirect call.
FunctionType * getFunctionType() const
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
A Module instance is used to store all the information related to an LLVM module.
A vector that has set insertion semantics.
size_type size() const
Determine the number of elements in the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
bool contains(const key_type &key) const
Check if the SetVector contains the given key.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM Value Representation.
An efficient, type-erasing, non-owning reference to a callable.
A range adaptor for a pair of iterators.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ AMDGPU_KERNEL
Used for AMDGPU code object kernels.
@ SPIR_KERNEL
Used for SPIR kernel functions.
@ PTX_Kernel
Call to a PTX kernel. Passes all arguments in parameter space.
This is an optimization pass for GlobalISel generic memory operations.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
LLVM_ABI void splitModuleTransitiveFromEntryPoints(std::unique_ptr< Module > M, function_ref< std::optional< int >(const Function &F)> EntryPointCategorizer, function_ref< void(std::unique_ptr< Module > Part)> Callback)
Splits the given module M into parts.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI std::unique_ptr< Module > CloneModule(const Module &M)
Return an exact copy of the specified module.