1//===-- ThreadSafeModule.cpp - Thread safe Module, Context, and Utilities -===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
10#include "llvm/Bitcode/BitcodeReader.h"
11#include "llvm/Bitcode/BitcodeWriter.h"
12#include "llvm/Transforms/Utils/Cloning.h"
13
14namespace llvm {
15namespace orc {
16
17static std::pair<std::string, SmallVector<char, 1>>
18serializeModule(const Module &M, GVPredicate ShouldCloneDef,
19 GVModifier UpdateClonedDefSource) {
20 std::string ModuleName;
21 SmallVector<char, 1> ClonedModuleBuffer;
22
23 ModuleName = M.getModuleIdentifier();
24 std::set<GlobalValue *> ClonedDefsInSrc;
25 ValueToValueMapTy VMap;
26 auto Tmp = CloneModule(M, VMap, ShouldCloneDefinition: [&](const GlobalValue *GV) {
27 if (ShouldCloneDef(*GV)) {
28 ClonedDefsInSrc.insert(x: const_cast<GlobalValue *>(GV));
29 return true;
30 }
31 return false;
32 });
33
34 if (UpdateClonedDefSource)
35 for (auto *GV : ClonedDefsInSrc)
36 UpdateClonedDefSource(*GV);
37
38 BitcodeWriter BCWriter(ClonedModuleBuffer);
39 BCWriter.writeModule(M: *Tmp);
40 BCWriter.writeSymtab();
41 BCWriter.writeStrtab();
42
43 return {std::move(ModuleName), std::move(ClonedModuleBuffer)};
44}
45
46ThreadSafeModule
47deserializeModule(std::string ModuleName,
48 const SmallVector<char, 1> &ClonedModuleBuffer,
49 ThreadSafeContext TSCtx) {
50 MemoryBufferRef ClonedModuleBufferRef(
51 StringRef(ClonedModuleBuffer.data(), ClonedModuleBuffer.size()),
52 "cloned module buffer");
53
54 // Then parse the buffer into the new Module.
55 auto M = TSCtx.withContextDo(F: [&](LLVMContext *Ctx) {
56 assert(Ctx && "No LLVMContext provided");
57 auto TmpM = cantFail(ValOrErr: parseBitcodeFile(Buffer: ClonedModuleBufferRef, Context&: *Ctx));
58 TmpM->setModuleIdentifier(ModuleName);
59 return TmpM;
60 });
61
62 return ThreadSafeModule(std::move(M), std::move(TSCtx));
63}
64
65ThreadSafeModule
66cloneExternalModuleToContext(const Module &M, ThreadSafeContext TSCtx,
67 GVPredicate ShouldCloneDef,
68 GVModifier UpdateClonedDefSource) {
69
70 if (!ShouldCloneDef)
71 ShouldCloneDef = [](const GlobalValue &) { return true; };
72
73 auto [ModuleName, ClonedModuleBuffer] = serializeModule(
74 M, ShouldCloneDef: std::move(ShouldCloneDef), UpdateClonedDefSource: std::move(UpdateClonedDefSource));
75
76 return deserializeModule(ModuleName: std::move(ModuleName), ClonedModuleBuffer,
77 TSCtx: std::move(TSCtx));
78}
79
80ThreadSafeModule cloneToContext(const ThreadSafeModule &TSM,
81 ThreadSafeContext TSCtx,
82 GVPredicate ShouldCloneDef,
83 GVModifier UpdateClonedDefSource) {
84 assert(TSM && "Can not clone null module");
85
86 if (!ShouldCloneDef)
87 ShouldCloneDef = [](const GlobalValue &) { return true; };
88
89 // First copy the source module into a buffer.
90 auto [ModuleName, ClonedModuleBuffer] = TSM.withModuleDo(F: [&](Module &M) {
91 return serializeModule(M, ShouldCloneDef: std::move(ShouldCloneDef),
92 UpdateClonedDefSource: std::move(UpdateClonedDefSource));
93 });
94
95 return deserializeModule(ModuleName: std::move(ModuleName), ClonedModuleBuffer,
96 TSCtx: std::move(TSCtx));
97}
98
99ThreadSafeModule cloneToNewContext(const ThreadSafeModule &TSM,
100 GVPredicate ShouldCloneDef,
101 GVModifier UpdateClonedDefSource) {
102 assert(TSM && "Can not clone null module");
103
104 ThreadSafeContext TSCtx(std::make_unique<LLVMContext>());
105 return cloneToContext(TSM, TSCtx: std::move(TSCtx), ShouldCloneDef: std::move(ShouldCloneDef),
106 UpdateClonedDefSource: std::move(UpdateClonedDefSource));
107}
108
109} // end namespace orc
110} // end namespace llvm
111