Skip to content

Commit de304b5

Browse files
committed
[NFC] Introduce GeneratedModule
swift::GeneratedModule encapsulates an llvm::Module, llvm::LLVMContext pair that must live and die together. It has convenient accessors for projecting the module and context components. The meat of this type is the two conversion functions, which transfer ownership of either the module component to the caller or the module and context to ORCJIT. This is because ORC enforces an ownership contract that is distinct from LLVM's rather wild ownership story for modules and their associated contexts. See http://llvm.org/docs/ORCv2.html#how-to-use-threadsafemodule-and-threadsafecontext
1 parent 6601c30 commit de304b5

File tree

11 files changed

+150
-54
lines changed

11 files changed

+150
-54
lines changed

include/swift/AST/IRGenRequests.h

Lines changed: 74 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,80 @@ namespace llvm {
3838
class GlobalVariable;
3939
class LLVMContext;
4040
class Module;
41+
42+
namespace orc {
43+
class ThreadSafeModule;
44+
}; // namespace orc
45+
4146
}; // namespace llvm
4247

4348
namespace swift {
4449

50+
/// A pair consisting of an \c LLVMContext and an \c llvm::Module that enforces
51+
/// exclusive ownership of those resources, and ensures that they are
52+
/// deallocated or transferred together.
53+
///
54+
/// Note that the underlying module and context are either both valid pointers
55+
/// or both null. This class forbids the remaining cases by construction.
56+
class GeneratedModule final {
57+
private:
58+
std::unique_ptr<llvm::LLVMContext> Context;
59+
std::unique_ptr<llvm::Module> Module;
60+
61+
GeneratedModule() : Context(nullptr), Module(nullptr) {}
62+
63+
GeneratedModule(GeneratedModule const &) = delete;
64+
GeneratedModule &operator=(GeneratedModule const &) = delete;
65+
66+
public:
67+
/// Construct a \c GeneratedModule that owns a given module and context.
68+
///
69+
/// The given pointers must not be null. If a null \c GeneratedModule is
70+
/// needed, use \c GeneratedModule::null() instead.
71+
explicit GeneratedModule(std::unique_ptr<llvm::LLVMContext> &&Context,
72+
std::unique_ptr<llvm::Module> &&Module)
73+
: Context(std::move(Context)), Module(std::move(Module)) {
74+
assert(getModule() && "Use GeneratedModule::null() instead");
75+
assert(getContext() && "Use GeneratedModule::null() instead");
76+
}
77+
78+
GeneratedModule(GeneratedModule &&) = default;
79+
GeneratedModule& operator=(GeneratedModule &&) = default;
80+
81+
public:
82+
/// Construct a \c GeneratedModule that does not own any resources.
83+
static GeneratedModule null() {
84+
return GeneratedModule{};
85+
}
86+
87+
public:
88+
explicit operator bool() const {
89+
return Module != nullptr && Context != nullptr;
90+
}
91+
92+
public:
93+
const llvm::Module *getModule() const { return Module.get(); }
94+
llvm::Module *getModule() { return Module.get(); }
95+
96+
const llvm::LLVMContext *getContext() const { return Context.get(); }
97+
llvm::LLVMContext *getContext() { return Context.get(); }
98+
99+
public:
100+
/// Release ownership of the context and module to the caller, consuming
101+
/// this value in the process.
102+
///
103+
/// The REPL is the only caller that needs this. New uses of this function
104+
/// should be avoided at all costs.
105+
std::pair<llvm::LLVMContext *, llvm::Module *> release() && {
106+
return { Context.release(), Module.release() };
107+
}
108+
109+
public:
110+
/// Transfers ownership of the underlying module and context to an
111+
/// ORC-compatible context.
112+
llvm::orc::ThreadSafeModule intoThreadSafeContext() &&;
113+
};
114+
45115
struct IRGenDescriptor {
46116
const IRGenOptions &Opts;
47117
llvm::PointerUnion<ModuleDecl *, SourceFile *> Ctx;
@@ -112,7 +182,7 @@ void reportEvaluatedRequest(UnifiedStatsReporter &stats,
112182

113183
class IRGenSourceFileRequest
114184
: public SimpleRequest<IRGenSourceFileRequest,
115-
std::unique_ptr<llvm::Module>(IRGenDescriptor),
185+
GeneratedModule(IRGenDescriptor),
116186
RequestFlags::Uncached|RequestFlags::DependencySource> {
117187
public:
118188
using SimpleRequest::SimpleRequest;
@@ -121,7 +191,7 @@ class IRGenSourceFileRequest
121191
friend SimpleRequest;
122192

123193
// Evaluation.
124-
std::unique_ptr<llvm::Module>
194+
GeneratedModule
125195
evaluate(Evaluator &evaluator, IRGenDescriptor desc) const;
126196

127197
public:
@@ -134,7 +204,7 @@ class IRGenSourceFileRequest
134204

135205
class IRGenWholeModuleRequest
136206
: public SimpleRequest<IRGenWholeModuleRequest,
137-
std::unique_ptr<llvm::Module>(IRGenDescriptor),
207+
GeneratedModule(IRGenDescriptor),
138208
RequestFlags::Uncached> {
139209
public:
140210
using SimpleRequest::SimpleRequest;
@@ -143,7 +213,7 @@ class IRGenWholeModuleRequest
143213
friend SimpleRequest;
144214

145215
// Evaluation.
146-
std::unique_ptr<llvm::Module>
216+
GeneratedModule
147217
evaluate(Evaluator &evaluator, IRGenDescriptor desc) const;
148218

149219
public:

include/swift/AST/IRGenTypeIDZone.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
SWIFT_REQUEST(IRGen, IRGenSourceFileRequest,
18-
std::unique_ptr<llvm::Module>(IRGenDescriptor),
18+
GeneratedModule(IRGenDescriptor),
1919
Uncached, NoLocationInfo)
2020
SWIFT_REQUEST(IRGen, IRGenWholeModuleRequest,
21-
std::unique_ptr<llvm::Module>(IRGenDescriptor),
21+
GeneratedModule(IRGenDescriptor),
2222
Uncached, NoLocationInfo)
2323

include/swift/Subsystems.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace swift {
4848
class DiagnosticEngine;
4949
class Evaluator;
5050
class FileUnit;
51+
class GeneratedModule;
5152
class GenericEnvironment;
5253
class GenericParamList;
5354
class IRGenOptions;
@@ -230,7 +231,7 @@ namespace swift {
230231
/// Turn the given Swift module into either LLVM IR or native code
231232
/// and return the generated LLVM IR module.
232233
/// If you set an outModuleHash, then you need to call performLLVM.
233-
std::unique_ptr<llvm::Module>
234+
GeneratedModule
234235
performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M,
235236
std::unique_ptr<SILModule> SILMod,
236237
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
@@ -241,7 +242,7 @@ namespace swift {
241242
/// Turn the given Swift module into either LLVM IR or native code
242243
/// and return the generated LLVM IR module.
243244
/// If you set an outModuleHash, then you need to call performLLVM.
244-
std::unique_ptr<llvm::Module>
245+
GeneratedModule
245246
performIRGeneration(const IRGenOptions &Opts, SourceFile &SF,
246247
std::unique_ptr<SILModule> SILMod,
247248
StringRef ModuleName, const PrimarySpecificPaths &PSPs,

lib/FrontendTool/FrontendTool.cpp

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include "swift/AST/FineGrainedDependencies.h"
3333
#include "swift/AST/GenericSignatureBuilder.h"
3434
#include "swift/AST/IRGenOptions.h"
35+
#include "swift/AST/IRGenRequests.h"
3536
#include "swift/AST/NameLookup.h"
3637
#include "swift/AST/ASTMangler.h"
3738
#include "swift/AST/ReferencedNameTracker.h"
@@ -1376,24 +1377,26 @@ static bool serializeSIB(SILModule *SM, const PrimarySpecificPaths &PSPs,
13761377
return Context.hadError();
13771378
}
13781379

1379-
static void generateIR(const IRGenOptions &IRGenOpts,
1380-
std::unique_ptr<SILModule> SM,
1381-
const PrimarySpecificPaths &PSPs,
1382-
StringRef OutputFilename, ModuleOrSourceFile MSF,
1383-
std::unique_ptr<llvm::Module> &IRModule,
1384-
llvm::GlobalVariable *&HashGlobal,
1385-
ArrayRef<std::string> parallelOutputFilenames,
1386-
llvm::StringSet<> &LinkerDirectives) {
1387-
IRModule = MSF.is<SourceFile *>()
1388-
? performIRGeneration(IRGenOpts, *MSF.get<SourceFile *>(),
1389-
std::move(SM), OutputFilename, PSPs,
1390-
MSF.get<SourceFile *>()->getPrivateDiscriminator().str(),
1391-
&HashGlobal,
1392-
&LinkerDirectives)
1393-
: performIRGeneration(IRGenOpts, MSF.get<ModuleDecl *>(),
1394-
std::move(SM), OutputFilename, PSPs,
1395-
parallelOutputFilenames,
1396-
&HashGlobal, &LinkerDirectives);
1380+
static GeneratedModule
1381+
generateIR(const IRGenOptions &IRGenOpts,
1382+
std::unique_ptr<SILModule> SM,
1383+
const PrimarySpecificPaths &PSPs,
1384+
StringRef OutputFilename, ModuleOrSourceFile MSF,
1385+
llvm::GlobalVariable *&HashGlobal,
1386+
ArrayRef<std::string> parallelOutputFilenames,
1387+
llvm::StringSet<> &LinkerDirectives) {
1388+
if (auto *SF = MSF.dyn_cast<SourceFile *>()) {
1389+
return performIRGeneration(IRGenOpts, *SF,
1390+
std::move(SM), OutputFilename, PSPs,
1391+
SF->getPrivateDiscriminator().str(),
1392+
&HashGlobal,
1393+
&LinkerDirectives);
1394+
} else {
1395+
return performIRGeneration(IRGenOpts, MSF.get<ModuleDecl *>(),
1396+
std::move(SM), OutputFilename, PSPs,
1397+
parallelOutputFilenames,
1398+
&HashGlobal, &LinkerDirectives);
1399+
}
13971400
}
13981401

13991402
static bool processCommandLineAndRunImmediately(const CompilerInvocation &Invocation,
@@ -1422,7 +1425,7 @@ static bool processCommandLineAndRunImmediately(const CompilerInvocation &Invoca
14221425
static bool validateTBDIfNeeded(const CompilerInvocation &Invocation,
14231426
ModuleOrSourceFile MSF,
14241427
bool astGuaranteedToCorrespondToSIL,
1425-
llvm::Module &IRModule) {
1428+
const llvm::Module &IRModule) {
14261429
if (!astGuaranteedToCorrespondToSIL ||
14271430
!inputFileKindCanHaveTBDValidated(Invocation.getInputKind()))
14281431
return false;
@@ -1674,10 +1677,9 @@ static bool performCompileStepsPostSILGen(
16741677
StringRef OutputFilename = PSPs.OutputFilename;
16751678
std::vector<std::string> ParallelOutputFilenames =
16761679
Invocation.getFrontendOptions().InputsAndOutputs.copyOutputFilenames();
1677-
std::unique_ptr<llvm::Module> IRModule;
16781680
llvm::GlobalVariable *HashGlobal;
1679-
generateIR(
1680-
IRGenOpts, std::move(SM), PSPs, OutputFilename, MSF, IRModule, HashGlobal,
1681+
auto IRModule = generateIR(
1682+
IRGenOpts, std::move(SM), PSPs, OutputFilename, MSF, HashGlobal,
16811683
ParallelOutputFilenames, LinkerDirectives);
16821684

16831685
// Walk the AST for indexing after IR generation. Walking it before seems
@@ -1695,10 +1697,11 @@ static bool performCompileStepsPostSILGen(
16951697
return HadError;
16961698

16971699
if (validateTBDIfNeeded(Invocation, MSF, astGuaranteedToCorrespondToSIL,
1698-
*IRModule))
1700+
*IRModule.getModule()))
16991701
return true;
17001702

1701-
return generateCode(Invocation, Instance, OutputFilename, IRModule.get(),
1703+
return generateCode(Invocation, Instance, OutputFilename,
1704+
IRModule.getModule(),
17021705
HashGlobal) ||
17031706
HadError;
17041707
}

lib/IRGen/IRGen.cpp

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ static void runIRGenPreparePasses(SILModule &Module,
948948

949949
/// Generates LLVM IR, runs the LLVM passes and produces the output file.
950950
/// All this is done in a single thread.
951-
static std::unique_ptr<llvm::Module>
951+
static GeneratedModule
952952
performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M,
953953
std::unique_ptr<SILModule> SILMod, StringRef ModuleName,
954954
const PrimarySpecificPaths &PSPs,
@@ -962,7 +962,7 @@ performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M,
962962
IRGenerator irgen(Opts, *SILMod);
963963

964964
auto targetMachine = irgen.createTargetMachine();
965-
if (!targetMachine) return nullptr;
965+
if (!targetMachine) return GeneratedModule::null();
966966

967967
// Create the IR emitter.
968968
IRGenModule IGM(irgen, std::move(targetMachine), SF, ModuleName,
@@ -1032,13 +1032,13 @@ performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M,
10321032
});
10331033

10341034
if (!IGM.finalize())
1035-
return nullptr;
1035+
return GeneratedModule::null();
10361036

10371037
setModuleFlags(IGM);
10381038
}
10391039

10401040
// Bail out if there are any errors.
1041-
if (Ctx.hadError()) return nullptr;
1041+
if (Ctx.hadError()) return GeneratedModule::null();
10421042

10431043
// Free the memory occupied by the SILModule.
10441044
// Execute this task in parallel to the LLVM compilation.
@@ -1059,10 +1059,10 @@ performIRGeneration(const IRGenOptions &Opts, ModuleDecl *M,
10591059
IGM.getModule(), IGM.TargetMachine.get(),
10601060
IGM.Context.LangOpts.EffectiveLanguageVersion,
10611061
IGM.OutputFilename, IGM.Context.Stats))
1062-
return nullptr;
1062+
return GeneratedModule::null();
10631063
}
10641064

1065-
return std::unique_ptr<llvm::Module>(IGM.releaseModule());
1065+
return std::move(IGM).intoGeneratedModule();
10661066
}
10671067

10681068
namespace {
@@ -1184,9 +1184,7 @@ static void performParallelIRGeneration(
11841184
~IGMDeleter() {
11851185
for (auto it = IRGen.begin(); it != IRGen.end(); ++it) {
11861186
IRGenModule *IGM = it->second;
1187-
LLVMContext *Context = &IGM->LLVMContext;
11881187
delete IGM;
1189-
delete Context;
11901188
}
11911189
}
11921190
} _igmDeleter(irgen);
@@ -1361,7 +1359,7 @@ static void performParallelIRGeneration(
13611359
codeGenThreads.join();
13621360
}
13631361

1364-
std::unique_ptr<llvm::Module> swift::performIRGeneration(
1362+
GeneratedModule swift::performIRGeneration(
13651363
const IRGenOptions &Opts, swift::ModuleDecl *M,
13661364
std::unique_ptr<SILModule> SILMod, StringRef ModuleName,
13671365
const PrimarySpecificPaths &PSPs,
@@ -1374,7 +1372,7 @@ std::unique_ptr<llvm::Module> swift::performIRGeneration(
13741372
M->getASTContext().evaluator(IRGenWholeModuleRequest{desc}));
13751373
}
13761374

1377-
std::unique_ptr<llvm::Module>
1375+
GeneratedModule
13781376
IRGenWholeModuleRequest::evaluate(Evaluator &evaluator,
13791377
IRGenDescriptor desc) const {
13801378
auto *M = desc.Ctx.get<ModuleDecl *>();
@@ -1386,15 +1384,15 @@ IRGenWholeModuleRequest::evaluate(Evaluator &evaluator,
13861384
NumThreads, desc.parallelOutputFilenames, desc.LinkerDirectives);
13871385
// TODO: Parallel LLVM compilation cannot be used if a (single) module is
13881386
// needed as return value.
1389-
return nullptr;
1387+
return GeneratedModule::null();
13901388
}
13911389
return ::performIRGeneration(
13921390
desc.Opts, M, std::unique_ptr<SILModule>(desc.SILMod), desc.ModuleName,
13931391
desc.PSPs, "", nullptr, desc.outModuleHash,
13941392
desc.LinkerDirectives);
13951393
}
13961394

1397-
std::unique_ptr<llvm::Module> swift::
1395+
GeneratedModule swift::
13981396
performIRGeneration(const IRGenOptions &Opts, SourceFile &SF,
13991397
std::unique_ptr<SILModule> SILMod,
14001398
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
@@ -1408,7 +1406,7 @@ performIRGeneration(const IRGenOptions &Opts, SourceFile &SF,
14081406
SF.getASTContext().evaluator(IRGenSourceFileRequest{desc}));
14091407
}
14101408

1411-
std::unique_ptr<llvm::Module>
1409+
GeneratedModule
14121410
IRGenSourceFileRequest::evaluate(Evaluator &evaluator,
14131411
IRGenDescriptor desc) const {
14141412
auto *SF = desc.Ctx.get<SourceFile *>();

lib/IRGen/IRGenModule.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -909,8 +909,8 @@ llvm::Module *IRGenModule::getModule() const {
909909

910910
GeneratedModule IRGenModule::intoGeneratedModule() && {
911911
return GeneratedModule{
912+
std::move(LLVMContext),
912913
std::unique_ptr<llvm::Module>{ClangCodeGen->ReleaseModule()},
913-
std::move(LLVMContext)
914914
};
915915
}
916916

lib/IRGen/IRGenModule.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ namespace swift {
9090
class BaseConformance;
9191
class BraceStmt;
9292
class CanType;
93+
class GeneratedModule;
9394
class LinkLibrary;
9495
class SILFunction;
9596
class IRGenOptions;
@@ -1285,6 +1286,9 @@ private: \
12851286

12861287
~IRGenModule();
12871288

1289+
public:
1290+
GeneratedModule intoGeneratedModule() &&;
1291+
12881292
public:
12891293
llvm::LLVMContext &getLLVMContext() const { return *LLVMContext; }
12901294

lib/IRGen/IRGenRequests.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/SIL/SILModule.h"
1919
#include "swift/Subsystems.h"
2020
#include "llvm/IR/Module.h"
21+
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
2122

2223
using namespace swift;
2324

@@ -30,6 +31,9 @@ namespace swift {
3031
#undef SWIFT_TYPEID_HEADER
3132
} // end namespace swift
3233

34+
llvm::orc::ThreadSafeModule GeneratedModule::intoThreadSafeContext() && {
35+
return {std::move(Module), std::move(Context)};
36+
}
3337

3438
void swift::simple_display(llvm::raw_ostream &out,
3539
const IRGenDescriptor &desc) {

0 commit comments

Comments
 (0)