Proteus
Programmable JIT compilation and optimization for C/C++ using LLVM
Loading...
Searching...
No Matches
Cloning.h
Go to the documentation of this file.
1#ifndef PROTEUS_CLONING_H
2#define PROTEUS_CLONING_H
3
4#include <llvm/Analysis/CallGraph.h>
5#include <llvm/IR/Constants.h>
6#include <llvm/IR/Verifier.h>
7#include <llvm/Transforms/Utils/Cloning.h>
8
9#include "proteus/Debug.h"
10#include "proteus/Error.h"
11#include "proteus/Logger.hpp"
12
13namespace proteus {
14
15using namespace llvm;
16
17inline std::unique_ptr<Module> cloneKernelFromModule(Module &M, StringRef Name,
18 CallGraph &CG) {
19 auto KernelModuleTmp = std::make_unique<Module>("JitModule", M.getContext());
20 KernelModuleTmp->setSourceFileName(M.getSourceFileName());
21 KernelModuleTmp->setDataLayout(M.getDataLayout());
22 KernelModuleTmp->setTargetTriple(M.getTargetTriple());
23 KernelModuleTmp->setModuleInlineAsm(M.getModuleInlineAsm());
24#if LLVM_VERSION_MAJOR >= 18
25 KernelModuleTmp->IsNewDbgInfoFormat = M.IsNewDbgInfoFormat;
26#endif
27
28 auto *KernelFunction = M.getFunction(Name);
29 if (!KernelFunction)
30 PROTEUS_FATAL_ERROR("Expected function " + Name);
31
32 SmallPtrSet<Function *, 8> ReachableFunctions;
33 SmallPtrSet<GlobalVariable *, 16> ReachableGlobals;
34 SmallPtrSet<Function *, 8> ReachableDeclarations;
35 SmallVector<Function *, 8> ToVisit;
36 ReachableFunctions.insert(KernelFunction);
37 ToVisit.push_back(KernelFunction);
38 while (!ToVisit.empty()) {
39 Function *VisitF = ToVisit.pop_back_val();
40 CallGraphNode *CGNode = CG[VisitF];
41
42 for (const auto &Callee : *CGNode) {
43 Function *CalleeF = Callee.second->getFunction();
44 if (!CalleeF)
45 continue;
46 if (CalleeF->isDeclaration()) {
47 ReachableDeclarations.insert(CalleeF);
48 continue;
49 }
50 if (ReachableFunctions.contains(CalleeF))
51 continue;
52 ReachableFunctions.insert(CalleeF);
53 ToVisit.push_back(CalleeF);
54 }
55 }
56
57 auto ProcessInstruction = [&](GlobalVariable &GV, const Instruction *I) {
58 const Function *ParentF = I->getFunction();
59 if (ReachableFunctions.contains(ParentF))
60 ReachableGlobals.insert(&GV);
61 };
62
63 for (auto &GV : M.globals()) {
64 for (const User *Usr : GV.users()) {
65 const Instruction *I = dyn_cast<Instruction>(Usr);
66
67 if (I) {
68 ProcessInstruction(GV, I);
69 continue;
70 }
71
72 // We follow non-instructions users to process them if those are
73 // instructions.
74 // TODO: We may need to follow deeper than just users of user and also
75 // expand to non-instruction users.
76 for (const User *NextUser : Usr->users()) {
77 I = dyn_cast<Instruction>(NextUser);
78 if (!I)
79 continue;
80
81 ProcessInstruction(GV, I);
82 }
83 }
84 }
85
86 ValueToValueMapTy VMap;
87
88 for (auto *GV : ReachableGlobals) {
89 // We will set the initializer later, after VMap has been populated.
90 GlobalVariable *NewGV = new GlobalVariable(
91 *KernelModuleTmp, GV->getValueType(), GV->isConstant(),
92 GV->getLinkage(), nullptr, GV->getName(), nullptr,
93 GV->getThreadLocalMode(), GV->getAddressSpace());
94 NewGV->copyAttributesFrom(GV);
95 VMap[GV] = NewGV;
96 }
97
98 for (auto *F : ReachableFunctions) {
99 auto *NewFunction = Function::Create(F->getFunctionType(), F->getLinkage(),
100 F->getAddressSpace(), F->getName(),
101 KernelModuleTmp.get());
102 NewFunction->copyAttributesFrom(F);
103 VMap[F] = NewFunction;
104 }
105
106 for (auto *F : ReachableDeclarations) {
107 auto *NewFunction = Function::Create(F->getFunctionType(), F->getLinkage(),
108 F->getAddressSpace(), F->getName(),
109 KernelModuleTmp.get());
110 NewFunction->copyAttributesFrom(F);
111 NewFunction->setLinkage(GlobalValue::ExternalLinkage);
112 VMap[F] = NewFunction;
113 }
114
115 for (GlobalVariable *GV : ReachableGlobals) {
116 if (GV->hasInitializer()) {
117 GlobalVariable *NewGV = cast<GlobalVariable>(VMap[GV]);
118 NewGV->setInitializer(MapValue(GV->getInitializer(), VMap));
119 }
120 }
121
122 for (auto *F : ReachableFunctions) {
123 SmallVector<ReturnInst *, 8> Returns;
124 auto *NewFunction = dyn_cast<Function>(VMap[F]);
125 Function::arg_iterator DestI = NewFunction->arg_begin();
126 for (const Argument &I : F->args())
127 if (VMap.count(&I) == 0) {
128 DestI->setName(I.getName());
129 VMap[&I] = &*DestI++;
130 }
131 llvm::CloneFunctionInto(NewFunction, F, VMap,
132 CloneFunctionChangeType::DifferentModule, Returns);
133 }
134
135 // Copy annotations from M into KernelModuleTmp now that VMap has been
136 // populated.
137 const std::string MetadataToCopy[] = {"llvm.annotations", "nvvm.annotations",
138 "nvvmir.version", "llvm.module.flags"};
139 for (auto &MetadataName : MetadataToCopy) {
140 NamedMDNode *NamedMD = M.getNamedMetadata(MetadataName);
141 if (!NamedMD)
142 continue;
143
144 auto *NewNamedMD = KernelModuleTmp->getOrInsertNamedMetadata(MetadataName);
145 for (unsigned I = 0, E = NamedMD->getNumOperands(); I < E; ++I) {
146 MDNode *MDEntry = NamedMD->getOperand(I);
147 bool ShouldClone = true;
148 // Skip if the operands of an MDNode refer to non-existing,
149 // unreachable global values.
150 for (auto &Operand : MDEntry->operands()) {
151 Metadata *MD = Operand.get();
152 auto *CMD = dyn_cast<ConstantAsMetadata>(MD);
153 if (!CMD)
154 continue;
155
156 auto *GV = dyn_cast<GlobalValue>(CMD->getValue());
157 if (!GV)
158 continue;
159
160 if (!VMap.count(GV)) {
161 ShouldClone = false;
162 break;
163 }
164 }
165
166 if (!ShouldClone)
167 continue;
168
169 NewNamedMD->addOperand(MapMetadata(MDEntry, VMap));
170 }
171 }
172
173#if PROTEUS_ENABLE_DEBUG
174 Logger::logfile(Name.str() + ".mini.ll", *KernelModuleTmp);
175 if (verifyModule(*KernelModuleTmp, &errs()))
176 PROTEUS_FATAL_ERROR("Broken mini-module found, JIT compilation aborted!");
177#endif
178
179 return KernelModuleTmp;
180}
181
183 // Definitions maps that map symbol name to GlobalValue.
184 struct DefMaps {
185 StringMap<Function *> FuncDefs;
186 StringMap<GlobalVariable *> GlobDefs;
187 };
188
189 // Stores declaration prototype and GVs that map to it.
191 FunctionType *FuncTy;
192 GlobalValue::LinkageTypes Linkage;
193 unsigned int AddrSpace;
194 AttributeList Attributes;
195 SmallPtrSet<GlobalValue *, 32> GVs;
196 };
197
201 GlobalValue::LinkageTypes Linkage;
202 Constant *Initializer;
203 GlobalValue::ThreadLocalMode TLM;
204 unsigned int AddrSpace;
205 AttributeSet Attributes;
206 SmallPtrSet<GlobalValue *, 32> GVs;
207 };
208
209 // Maps a resolved GV to cross-module GV references.
210 DenseMap<GlobalValue *, SmallVector<GlobalValue *>> ResolvedMap;
211 // Stores declaration info by symbol name to clone and update references.
212 StringMap<FuncDeclInfo> FuncDecls;
213 StringMap<GlobDeclInfo> GlobDecls;
214
215 DefMaps buildDefMaps(ArrayRef<std::reference_wrapper<Module>> Mods) {
216 DefMaps SymbolMaps;
217 for (Module &M : Mods) {
218 for (Function &F : M.functions())
219 if (!F.isDeclaration())
220 SymbolMaps.FuncDefs[F.getName()] = &F;
221 for (GlobalVariable &G : M.globals())
222 if (G.hasInitializer())
223 SymbolMaps.GlobDefs[G.getName()] = &G;
224 }
225 return SymbolMaps;
226 }
227
228 // Resolve GlobalValue to its definition across modules or fallback to the
229 // declartion if not found (e.g., intrinsics). Add to WorkList if unseen.
230 void resolveGV(const DefMaps &Defs, GlobalValue *G,
231 SmallVector<GlobalValue *> &WorkList,
232 SmallPtrSetImpl<GlobalValue *> &Found) {
233 GlobalValue *ResolvedGV = nullptr;
234 if (auto *F = dyn_cast<Function>(G)) {
235 if (!F->isDeclaration())
236 ResolvedGV = F;
237 else if (auto *D = Defs.FuncDefs.lookup(F->getName()))
238 ResolvedGV = D;
239 else {
240 if (FuncDecls.contains(F->getName()))
241 FuncDecls[F->getName()].GVs.insert(G);
242 else
243 FuncDecls[F->getName()] = {F->getFunctionType(),
244 F->getLinkage(),
245 F->getAddressSpace(),
246 F->getAttributes(),
247 {G}};
248 }
249 } else if (auto *GV = dyn_cast<GlobalVariable>(G)) {
250 if (GV->hasInitializer())
251 ResolvedGV = GV;
252 else if (auto *D = Defs.GlobDefs.lookup(GV->getName()))
253 ResolvedGV = D;
254 else {
255 if (GlobDecls.contains(GV->getName()))
256 GlobDecls[GV->getName()].GVs.insert(G);
257 else
258 GlobDecls[GV->getName()] = {
259 GV->getValueType(), GV->isConstant(),
260 GV->getLinkage(), nullptr,
261 GV->getThreadLocalMode(), GV->getAddressSpace(),
262 GV->getAttributes(), {G}};
263 }
264 } else if (auto *GA = dyn_cast<GlobalAlias>(G)) {
265 auto *GVA = dyn_cast<GlobalValue>(GA->getAliasee()->stripPointerCasts());
266 if (!GVA) {
267 SmallVector<char> ErrMsg;
268 raw_svector_ostream OS{ErrMsg};
269 G->print(OS);
270 PROTEUS_FATAL_ERROR("Expected aliasee to be a global value: " + ErrMsg);
271 }
272 ResolvedGV = GA;
273 } else {
274 PROTEUS_FATAL_ERROR("Unsupported global value: " + toString(*G));
275 }
276
277 if (ResolvedGV && Found.insert(ResolvedGV).second) {
278 WorkList.push_back(ResolvedGV);
279 ResolvedMap[ResolvedGV].push_back(G);
280 }
281 }
282
283 void scanConstant(Constant *C, const DefMaps &Defs,
284 SmallVector<GlobalValue *> &WorkList,
285 SmallPtrSetImpl<GlobalValue *> &Found) {
286 // If this is a constant expression (e.g., bitcast), unwrap and scan its
287 // operand.
288 if (auto *CE = dyn_cast<ConstantExpr>(C)) {
289 if (CE->isCast())
290 scanConstant(CE->getOperand(0), Defs, WorkList, Found);
291 }
292
293 // If C itself is a global value resolve its definition.
294 if (auto *G = dyn_cast<GlobalValue>(C))
295 resolveGV(Defs, G, WorkList, Found);
296
297 // Recurse into any operand constants.
298 for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I)
299 if (auto *OpC = dyn_cast<Constant>(C->getOperand(I)))
300 scanConstant(OpC, Defs, WorkList, Found);
301 }
302
303 SmallPtrSet<GlobalValue *, 32> findTransitiveClosure(Function *Entry,
304 const DefMaps &Defs) {
305 SmallPtrSet<GlobalValue *, 32> Found;
306 SmallVector<GlobalValue *> WorkList;
307
308 // Seed with the entry function.
309 resolveGV(Defs, Entry, WorkList, Found);
310
311 // Process DFS work-list.
312 while (!WorkList.empty()) {
313 auto *GV = WorkList.pop_back_val();
314
315 if (auto *F = dyn_cast<Function>(GV)) {
316 for (auto &BB : *F) {
317 for (auto &I : BB) {
318 // Add direct calls to other functions.
319 if (auto *CB = dyn_cast<CallBase>(&I))
320 if (Function *Callee = CB->getCalledFunction())
321 resolveGV(Defs, Callee, WorkList, Found);
322
323 // Scan GlobalValue operands or Constants.
324 for (Use &U : I.operands()) {
325 Value *Op = U.get()->stripPointerCasts();
326 if (auto *GVOp = dyn_cast<GlobalValue>(Op)) {
327 resolveGV(Defs, GVOp, WorkList, Found);
328 } else if (auto *C = dyn_cast<Constant>(Op)) {
329 scanConstant(C, Defs, WorkList, Found);
330 }
331 }
332 }
333 }
334 } else if (auto *GVar = dyn_cast<GlobalVariable>(GV)) {
335 if (auto *Init = GVar->getInitializer())
336 scanConstant(Init, Defs, WorkList, Found);
337 } else if (auto *GA = dyn_cast<GlobalAlias>(GV)) {
338 scanConstant(GA->getAliasee(), Defs, WorkList, Found);
339 } else {
340 PROTEUS_FATAL_ERROR("Unsupported global value: " + toString(*GV));
341 }
342 }
343
344 return Found;
345 }
346
347 std::unique_ptr<Module>
348 cloneClosure(Module &M, LLVMContext &Ctx,
349 SmallPtrSetImpl<GlobalValue *> const &Reachable) {
350 auto ModuleOut =
351 std::make_unique<Module>(M.getName().str() + ".closure.clone", Ctx);
352 ModuleOut->setSourceFileName(M.getSourceFileName());
353 ModuleOut->setDataLayout(M.getDataLayout());
354 ModuleOut->setTargetTriple(M.getTargetTriple());
355 ModuleOut->setModuleInlineAsm(M.getModuleInlineAsm());
356#if LLVM_VERSION_MAJOR >= 18
357 ModuleOut->IsNewDbgInfoFormat = M.IsNewDbgInfoFormat;
358#endif
359
360 ValueToValueMapTy VMap;
361
362 // Emit the function declarations.
363 for (auto &D : FuncDecls) {
364 StringRef FuncName = D.getKey();
365 FuncDeclInfo &FuncInfo = D.getValue();
366 Function *NF =
367 Function::Create(FuncInfo.FuncTy, FuncInfo.Linkage,
368 FuncInfo.AddrSpace, FuncName, ModuleOut.get());
369 NF->setAttributes(FuncInfo.Attributes);
370 for (auto *GV : FuncInfo.GVs)
371 VMap[GV] = NF;
372 }
373
374 // Emit the global variable declarations.
375 for (auto &D : GlobDecls) {
376 StringRef GVName = D.getKey();
377 GlobDeclInfo &GlobInfo = D.getValue();
378 auto *NG = new GlobalVariable(
379 *ModuleOut, GlobInfo.ValueType, GlobInfo.IsConstant, GlobInfo.Linkage,
380 nullptr, GVName, nullptr, GlobInfo.TLM, GlobInfo.AddrSpace);
381 NG->setAttributes(GlobInfo.Attributes);
382 for (auto *GV : GlobInfo.GVs)
383 VMap[GV] = NG;
384 }
385
386 // Create unpopulated declarations.
387 for (GlobalValue *GV : Reachable) {
388 if (auto *F = dyn_cast<Function>(GV)) {
389 Function *NF = Function::Create(F->getFunctionType(), F->getLinkage(),
390 F->getAddressSpace(), F->getName(),
391 ModuleOut.get());
392 NF->copyAttributesFrom(F);
393 VMap[F] = NF;
394
395 for (auto *DeclGV : ResolvedMap[F])
396 VMap[DeclGV] = NF;
397 } else if (auto *GVar = dyn_cast<GlobalVariable>(GV)) {
398 auto *NG = new GlobalVariable(
399 *ModuleOut, GV->getValueType(), GVar->isConstant(),
400 GV->getLinkage(), nullptr, GV->getName(), nullptr,
401 GV->getThreadLocalMode(), GV->getAddressSpace());
402 NG->copyAttributesFrom(GVar);
403 VMap[GVar] = NG;
404
405 for (auto *DeclGV : ResolvedMap[GVar])
406 VMap[DeclGV] = NG;
407 } else if (auto *GA = dyn_cast<GlobalAlias>(GV)) {
408 auto *NGA = GlobalAlias::create(GA->getValueType(),
409 GA->getAddressSpace(), GA->getLinkage(),
410 GA->getName(), ModuleOut.get());
411 NGA->copyAttributesFrom(GA);
412 NGA->setVisibility(GA->getVisibility());
413 VMap[GA] = NGA;
414 } else {
415 PROTEUS_FATAL_ERROR("Unsupported global value: " + toString(*GV));
416 }
417 }
418
419 // Clone function bodies and global variable initializers.
420 for (GlobalValue *GV : Reachable) {
421 if (auto *F = dyn_cast<Function>(GV)) {
422 Function *NF = cast<Function>(VMap[F]);
423 SmallVector<ReturnInst *, 8> Returns;
424 Function::arg_iterator DestI = NF->arg_begin();
425 for (const Argument &I : F->args())
426 if (VMap.count(&I) == 0) {
427 DestI->setName(I.getName());
428 VMap[&I] = &*DestI++;
429 }
430
431 CloneFunctionInto(NF, F, VMap,
432 /*Changes=*/CloneFunctionChangeType::DifferentModule,
433 Returns);
434 } else if (auto *GVar = dyn_cast<GlobalVariable>(GV)) {
435 auto *NG = cast<GlobalVariable>(VMap[GVar]);
436 if (GVar->hasInitializer())
437 NG->setInitializer(MapValue(GVar->getInitializer(), VMap));
438 } else if (auto *GA = dyn_cast<GlobalAlias>(GV)) {
439 auto *Aliasee = GA->getAliasee();
440 auto *NGA = cast<GlobalAlias>(VMap[GA]);
441 NGA->setAliasee(MapValue(Aliasee, VMap));
442 } else {
443 PROTEUS_FATAL_ERROR("Unsupported global value: " + toString(*GV));
444 }
445 }
446
447 // Copy annotations from the entry module M into KernelModuleTmp now that
448 // VMap has been populated.
449 const std::string MetadataToCopy[] = {"llvm.annotations",
450 "nvvm.annotations", "nvvmir.version",
451 "llvm.module.flags"};
452 for (auto &MetadataName : MetadataToCopy) {
453 NamedMDNode *NamedMD = M.getNamedMetadata(MetadataName);
454 if (!NamedMD)
455 continue;
456
457 auto *NewNamedMD = ModuleOut->getOrInsertNamedMetadata(MetadataName);
458 for (unsigned I = 0, E = NamedMD->getNumOperands(); I < E; ++I) {
459 MDNode *MDEntry = NamedMD->getOperand(I);
460 bool ShouldClone = true;
461 // Skip if the operands of an MDNode refer to non-existing,
462 // unreachable global values.
463 for (auto &Operand : MDEntry->operands()) {
464 Metadata *MD = Operand.get();
465 auto *CMD = dyn_cast<ConstantAsMetadata>(MD);
466 if (!CMD)
467 continue;
468
469 auto *GV = dyn_cast<GlobalValue>(CMD->getValue());
470 if (!GV)
471 continue;
472
473 if (!VMap.count(GV)) {
474 ShouldClone = false;
475 break;
476 }
477 }
478
479 if (!ShouldClone)
480 continue;
481
482 NewNamedMD->addOperand(MapMetadata(MDEntry, VMap));
483 }
484 }
485
486#if PROTEUS_ENABLE_DEBUG
487 if (verifyModule(*ModuleOut, &errs()))
489 "Broken cross-module clone found, JIT compilation aborted!");
490#endif
491 return ModuleOut;
492 }
493};
494
495inline std::unique_ptr<Module>
496cloneKernelFromModules(ArrayRef<std::reference_wrapper<Module>> Mods,
497 StringRef EntryName) {
498 auto Cloner = LinkingCloner();
499 LinkingCloner::DefMaps Defs = Cloner.buildDefMaps(Mods);
500
501 // Find the entry function and its module.
502 Function *EntryF = nullptr;
503 Module *EntryM = nullptr;
504 for (Module &M : Mods) {
505 if ((EntryF = M.getFunction(EntryName)) && !EntryF->isDeclaration()) {
506 EntryM = &M;
507 break;
508 }
509 }
510 if (!EntryF)
511 PROTEUS_FATAL_ERROR("Expected non-null entry function");
512
513 // Compute the transitive closure starting from the entry function.
514 SmallVector<Function *> ToVisit{EntryF};
515 SmallPtrSet<Function *, 32> VisitSet{EntryF};
516 SmallPtrSet<GlobalValue *, 32> Reachable;
517 while (!ToVisit.empty()) {
518 auto *F = ToVisit.pop_back_val();
519 // Due to lazy parsing, make sure the function is materialized before
520 // traversing it.
521 if (auto E = F->materialize())
522 PROTEUS_FATAL_ERROR("Failed to materialize: " + toString(std::move(E)));
523
524 auto ThisReachable = Cloner.findTransitiveClosure(F, Defs);
525 for (auto *GV : ThisReachable) {
526 Reachable.insert(GV);
527 if (auto *ThisF = dyn_cast<Function>(GV)) {
528 if (!VisitSet.contains(ThisF)) {
529 VisitSet.insert(ThisF);
530 ToVisit.push_back(ThisF);
531 }
532 }
533 }
534 }
535
536 // Clone closure in new module.
537 auto KernelModule =
538 Cloner.cloneClosure(*EntryM, EntryF->getContext(), Reachable);
539
540 return KernelModule;
541}
542
543} // namespace proteus
544
545#endif
#define PROTEUS_FATAL_ERROR(x)
Definition Error.h:4
static void logfile(const std::string &Filename, T &&Data)
Definition Logger.hpp:33
Definition Dispatcher.cpp:14
std::unique_ptr< Module > cloneKernelFromModule(Module &M, StringRef Name, CallGraph &CG)
Definition Cloning.h:17
std::unique_ptr< Module > cloneKernelFromModules(ArrayRef< std::reference_wrapper< Module > > Mods, StringRef EntryName)
Definition Cloning.h:496
std::string toString(CodegenOption Option)
Definition Config.hpp:23
Definition Cloning.h:184
StringMap< Function * > FuncDefs
Definition Cloning.h:185
StringMap< GlobalVariable * > GlobDefs
Definition Cloning.h:186
Definition Cloning.h:190
AttributeList Attributes
Definition Cloning.h:194
FunctionType * FuncTy
Definition Cloning.h:191
SmallPtrSet< GlobalValue *, 32 > GVs
Definition Cloning.h:195
GlobalValue::LinkageTypes Linkage
Definition Cloning.h:192
unsigned int AddrSpace
Definition Cloning.h:193
Definition Cloning.h:198
bool IsConstant
Definition Cloning.h:200
Type * ValueType
Definition Cloning.h:199
Constant * Initializer
Definition Cloning.h:202
GlobalValue::LinkageTypes Linkage
Definition Cloning.h:201
SmallPtrSet< GlobalValue *, 32 > GVs
Definition Cloning.h:206
AttributeSet Attributes
Definition Cloning.h:205
GlobalValue::ThreadLocalMode TLM
Definition Cloning.h:203
unsigned int AddrSpace
Definition Cloning.h:204
Definition Cloning.h:182
StringMap< FuncDeclInfo > FuncDecls
Definition Cloning.h:212
void scanConstant(Constant *C, const DefMaps &Defs, SmallVector< GlobalValue * > &WorkList, SmallPtrSetImpl< GlobalValue * > &Found)
Definition Cloning.h:283
SmallPtrSet< GlobalValue *, 32 > findTransitiveClosure(Function *Entry, const DefMaps &Defs)
Definition Cloning.h:303
DefMaps buildDefMaps(ArrayRef< std::reference_wrapper< Module > > Mods)
Definition Cloning.h:215
StringMap< GlobDeclInfo > GlobDecls
Definition Cloning.h:213
void resolveGV(const DefMaps &Defs, GlobalValue *G, SmallVector< GlobalValue * > &WorkList, SmallPtrSetImpl< GlobalValue * > &Found)
Definition Cloning.h:230
std::unique_ptr< Module > cloneClosure(Module &M, LLVMContext &Ctx, SmallPtrSetImpl< GlobalValue * > const &Reachable)
Definition Cloning.h:348
DenseMap< GlobalValue *, SmallVector< GlobalValue * > > ResolvedMap
Definition Cloning.h:210