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