Skip to content

Commit ce2207a

Browse files
committed
[ORC] Add support for emulated TLS to ORCv2.
This commit adds a ManglingOptions struct to IRMaterializationUnit, and replaces IRCompileLayer::CompileFunction with a new IRCompileLayer::IRCompiler class. The ManglingOptions struct defines the emulated-TLS state (via a bool member, EmulatedTLS, which is true if emulated-TLS is enabled and false otherwise). The IRCompileLayer::IRCompiler class wraps an IRCompiler (the same way that the CompileFunction typedef used to), but adds a method to return the IRCompileLayer::ManglingOptions that the compiler will use. These changes allow us to correctly determine the symbols that will be produced when a thread local global variable defined at the IR level is compiled with or without emulated TLS. This is required for ORCv2, where MaterializationUnits must declare their interface up-front. Most ORCv2 clients should not require any changes. Clients writing custom IR compilers will need to wrap their compiler in an IRCompileLayer::IRCompiler, rather than an IRCompileLayer::CompileFunction, however this should be a straightforward change (see modifications to CompileUtils.* in this patch for an example).
1 parent dac7cda commit ce2207a

18 files changed

+244
-122
lines changed

llvm/include/llvm/ExecutionEngine/Orc/CompileUtils.h

+14-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#ifndef LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H
1414
#define LLVM_EXECUTIONENGINE_ORC_COMPILEUTILS_H
1515

16+
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
1617
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
18+
#include "llvm/ExecutionEngine/Orc/Layer.h"
1719
#include <memory>
1820

1921
namespace llvm {
@@ -28,24 +30,31 @@ namespace orc {
2830

2931
class JITTargetMachineBuilder;
3032

33+
IRMaterializationUnit::ManglingOptions
34+
irManglingOptionsFromTargetOptions(const TargetOptions &Opts);
35+
3136
/// Simple compile functor: Takes a single IR module and returns an ObjectFile.
3237
/// This compiler supports a single compilation thread and LLVMContext only.
3338
/// For multithreaded compilation, use ConcurrentIRCompiler below.
34-
class SimpleCompiler {
39+
class SimpleCompiler : public IRCompileLayer::IRCompiler {
3540
public:
3641
using CompileResult = std::unique_ptr<MemoryBuffer>;
3742

3843
/// Construct a simple compile functor with the given target.
3944
SimpleCompiler(TargetMachine &TM, ObjectCache *ObjCache = nullptr)
40-
: TM(TM), ObjCache(ObjCache) {}
45+
: IRCompiler(irManglingOptionsFromTargetOptions(TM.Options)), TM(TM),
46+
ObjCache(ObjCache) {}
4147

4248
/// Set an ObjectCache to query before compiling.
4349
void setObjectCache(ObjectCache *NewCache) { ObjCache = NewCache; }
4450

4551
/// Compile a Module to an ObjectFile.
46-
CompileResult operator()(Module &M);
52+
Expected<CompileResult> operator()(Module &M) override;
4753

4854
private:
55+
IRMaterializationUnit::ManglingOptions
56+
manglingOptionsForTargetMachine(const TargetMachine &TM);
57+
4958
CompileResult tryToLoadFromObjectCache(const Module &M);
5059
void notifyObjectCompiled(const Module &M, const MemoryBuffer &ObjBuffer);
5160

@@ -73,14 +82,14 @@ class TMOwningSimpleCompiler : public SimpleCompiler {
7382
///
7483
/// This class creates a new TargetMachine and SimpleCompiler instance for each
7584
/// compile.
76-
class ConcurrentIRCompiler {
85+
class ConcurrentIRCompiler : public IRCompileLayer::IRCompiler {
7786
public:
7887
ConcurrentIRCompiler(JITTargetMachineBuilder JTMB,
7988
ObjectCache *ObjCache = nullptr);
8089

8190
void setObjectCache(ObjectCache *ObjCache) { this->ObjCache = ObjCache; }
8291

83-
std::unique_ptr<MemoryBuffer> operator()(Module &M);
92+
Expected<std::unique_ptr<MemoryBuffer>> operator()(Module &M) override;
8493

8594
private:
8695
JITTargetMachineBuilder JTMB;

llvm/include/llvm/ExecutionEngine/Orc/IRCompileLayer.h

+24-5
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,29 @@ namespace orc {
2929

3030
class IRCompileLayer : public IRLayer {
3131
public:
32-
using CompileFunction =
33-
std::function<Expected<std::unique_ptr<MemoryBuffer>>(Module &)>;
32+
class IRCompiler {
33+
public:
34+
IRCompiler(IRMaterializationUnit::ManglingOptions MO) : MO(std::move(MO)) {}
35+
virtual ~IRCompiler();
36+
const IRMaterializationUnit::ManglingOptions &getManglingOptions() const {
37+
return MO;
38+
}
39+
virtual Expected<std::unique_ptr<MemoryBuffer>> operator()(Module &M) = 0;
40+
41+
protected:
42+
IRMaterializationUnit::ManglingOptions &manglingOptions() { return MO; }
43+
44+
private:
45+
IRMaterializationUnit::ManglingOptions MO;
46+
};
3447

3548
using NotifyCompiledFunction =
3649
std::function<void(VModuleKey K, ThreadSafeModule TSM)>;
3750

3851
IRCompileLayer(ExecutionSession &ES, ObjectLayer &BaseLayer,
39-
CompileFunction Compile);
52+
std::unique_ptr<IRCompiler> Compile);
53+
54+
IRCompiler &getCompiler() { return *Compile; }
4055

4156
void setNotifyCompiled(NotifyCompiledFunction NotifyCompiled);
4257

@@ -45,7 +60,8 @@ class IRCompileLayer : public IRLayer {
4560
private:
4661
mutable std::mutex IRLayerMutex;
4762
ObjectLayer &BaseLayer;
48-
CompileFunction Compile;
63+
std::unique_ptr<IRCompiler> Compile;
64+
const IRMaterializationUnit::ManglingOptions *ManglingOpts;
4965
NotifyCompiledFunction NotifyCompiled = NotifyCompiledFunction();
5066
};
5167

@@ -90,7 +106,10 @@ class LegacyIRCompileLayer {
90106
/// Compile the module, and add the resulting object to the base layer
91107
/// along with the given memory manager and symbol resolver.
92108
Error addModule(VModuleKey K, std::unique_ptr<Module> M) {
93-
if (auto Err = BaseLayer.addObject(std::move(K), Compile(*M)))
109+
auto Obj = Compile(*M);
110+
if (!Obj)
111+
return Obj.takeError();
112+
if (auto Err = BaseLayer.addObject(std::move(K), std::move(*Obj)))
94113
return Err;
95114
if (NotifyCompiled)
96115
NotifyCompiled(std::move(K), std::move(M));

llvm/include/llvm/ExecutionEngine/Orc/LLJIT.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ class LLJIT {
130130
static std::unique_ptr<ObjectLayer>
131131
createObjectLinkingLayer(LLJITBuilderState &S, ExecutionSession &ES);
132132

133-
static Expected<IRCompileLayer::CompileFunction>
133+
static Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>
134134
createCompileFunction(LLJITBuilderState &S, JITTargetMachineBuilder JTMB);
135135

136136
/// Create an LLJIT instance with a single compile thread.
@@ -193,7 +193,7 @@ class LLJITBuilderState {
193193
ExecutionSession &, const Triple &TT)>;
194194

195195
using CompileFunctionCreator =
196-
std::function<Expected<IRCompileLayer::CompileFunction>(
196+
std::function<Expected<std::unique_ptr<IRCompileLayer::IRCompiler>>(
197197
JITTargetMachineBuilder JTMB)>;
198198

199199
std::unique_ptr<ExecutionSession> ES;

llvm/include/llvm/ExecutionEngine/Orc/Layer.h

+51-38
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,62 @@
2121
namespace llvm {
2222
namespace orc {
2323

24+
/// IRMaterializationUnit is a convenient base class for MaterializationUnits
25+
/// wrapping LLVM IR. Represents materialization responsibility for all symbols
26+
/// in the given module. If symbols are overridden by other definitions, then
27+
/// their linkage is changed to available-externally.
28+
class IRMaterializationUnit : public MaterializationUnit {
29+
public:
30+
struct ManglingOptions {
31+
bool EmulatedTLS = false;
32+
};
33+
34+
using SymbolNameToDefinitionMap = std::map<SymbolStringPtr, GlobalValue *>;
35+
36+
/// Create an IRMaterializationLayer. Scans the module to build the
37+
/// SymbolFlags and SymbolToDefinition maps.
38+
IRMaterializationUnit(ExecutionSession &ES, const ManglingOptions &MO,
39+
ThreadSafeModule TSM, VModuleKey K);
40+
41+
/// Create an IRMaterializationLayer from a module, and pre-existing
42+
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
43+
/// entries for each definition in M.
44+
/// This constructor is useful for delegating work from one
45+
/// IRMaterializationUnit to another.
46+
IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K,
47+
SymbolFlagsMap SymbolFlags,
48+
SymbolNameToDefinitionMap SymbolToDefinition);
49+
50+
/// Return the ModuleIdentifier as the name for this MaterializationUnit.
51+
StringRef getName() const override;
52+
53+
const ThreadSafeModule &getModule() const { return TSM; }
54+
55+
protected:
56+
ThreadSafeModule TSM;
57+
SymbolNameToDefinitionMap SymbolToDefinition;
58+
59+
private:
60+
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
61+
};
62+
2463
/// Interface for layers that accept LLVM IR.
2564
class IRLayer {
2665
public:
27-
IRLayer(ExecutionSession &ES);
66+
IRLayer(ExecutionSession &ES,
67+
const IRMaterializationUnit::ManglingOptions *&MO)
68+
: ES(ES), MO(MO) {}
69+
2870
virtual ~IRLayer();
2971

3072
/// Returns the ExecutionSession for this layer.
3173
ExecutionSession &getExecutionSession() { return ES; }
3274

75+
/// Get the mangling options for this layer.
76+
const IRMaterializationUnit::ManglingOptions *&getManglingOptions() const {
77+
return MO;
78+
}
79+
3380
/// Sets the CloneToNewContextOnEmit flag (false by default).
3481
///
3582
/// When set, IR modules added to this layer will be cloned on to a new
@@ -57,49 +104,15 @@ class IRLayer {
57104
private:
58105
bool CloneToNewContextOnEmit = false;
59106
ExecutionSession &ES;
60-
};
61-
62-
/// IRMaterializationUnit is a convenient base class for MaterializationUnits
63-
/// wrapping LLVM IR. Represents materialization responsibility for all symbols
64-
/// in the given module. If symbols are overridden by other definitions, then
65-
/// their linkage is changed to available-externally.
66-
class IRMaterializationUnit : public MaterializationUnit {
67-
public:
68-
using SymbolNameToDefinitionMap = std::map<SymbolStringPtr, GlobalValue *>;
69-
70-
/// Create an IRMaterializationLayer. Scans the module to build the
71-
/// SymbolFlags and SymbolToDefinition maps.
72-
IRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
73-
VModuleKey K);
74-
75-
/// Create an IRMaterializationLayer from a module, and pre-existing
76-
/// SymbolFlags and SymbolToDefinition maps. The maps must provide
77-
/// entries for each definition in M.
78-
/// This constructor is useful for delegating work from one
79-
/// IRMaterializationUnit to another.
80-
IRMaterializationUnit(ThreadSafeModule TSM, VModuleKey K,
81-
SymbolFlagsMap SymbolFlags,
82-
SymbolNameToDefinitionMap SymbolToDefinition);
83-
84-
/// Return the ModuleIdentifier as the name for this MaterializationUnit.
85-
StringRef getName() const override;
86-
87-
const ThreadSafeModule &getModule() const { return TSM; }
88-
89-
protected:
90-
ThreadSafeModule TSM;
91-
SymbolNameToDefinitionMap SymbolToDefinition;
92-
93-
private:
94-
void discard(const JITDylib &JD, const SymbolStringPtr &Name) override;
107+
const IRMaterializationUnit::ManglingOptions *&MO;
95108
};
96109

97110
/// MaterializationUnit that materializes modules by calling the 'emit' method
98111
/// on the given IRLayer.
99112
class BasicIRLayerMaterializationUnit : public IRMaterializationUnit {
100113
public:
101-
BasicIRLayerMaterializationUnit(IRLayer &L, VModuleKey K,
102-
ThreadSafeModule TSM);
114+
BasicIRLayerMaterializationUnit(IRLayer &L, const ManglingOptions &MO,
115+
ThreadSafeModule TSM, VModuleKey K);
103116

104117
private:
105118

llvm/include/llvm/ExecutionEngine/Orc/Speculation.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ class IRSpeculationLayer : public IRLayer {
182182
IRSpeculationLayer(ExecutionSession &ES, IRCompileLayer &BaseLayer,
183183
Speculator &Spec, MangleAndInterner &Mangle,
184184
ResultEval Interpreter)
185-
: IRLayer(ES), NextLayer(BaseLayer), S(Spec), Mangle(Mangle),
186-
QueryAnalysis(Interpreter) {}
185+
: IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer),
186+
S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {}
187187

188188
void emit(MaterializationResponsibility R, ThreadSafeModule TSM);
189189

llvm/lib/ExecutionEngine/Orc/CompileOnDemandLayer.cpp

+19-20
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,11 @@ namespace orc {
6767

6868
class PartitioningIRMaterializationUnit : public IRMaterializationUnit {
6969
public:
70-
PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM,
71-
VModuleKey K, CompileOnDemandLayer &Parent)
72-
: IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
70+
PartitioningIRMaterializationUnit(ExecutionSession &ES,
71+
const ManglingOptions &MO,
72+
ThreadSafeModule TSM, VModuleKey K,
73+
CompileOnDemandLayer &Parent)
74+
: IRMaterializationUnit(ES, MO, std::move(TSM), std::move(K)),
7375
Parent(Parent) {}
7476

7577
PartitioningIRMaterializationUnit(
@@ -111,7 +113,8 @@ CompileOnDemandLayer::compileWholeModule(GlobalValueSet Requested) {
111113
CompileOnDemandLayer::CompileOnDemandLayer(
112114
ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
113115
IndirectStubsManagerBuilder BuildIndirectStubsManager)
114-
: IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
116+
: IRLayer(ES, BaseLayer.getManglingOptions()), BaseLayer(BaseLayer),
117+
LCTMgr(LCTMgr),
115118
BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
116119

117120
void CompileOnDemandLayer::setPartitionFunction(PartitionFunction Partition) {
@@ -136,27 +139,23 @@ void CompileOnDemandLayer::emit(MaterializationResponsibility R,
136139
TSM.withModuleDo([&](Module &M) {
137140
// First, do some cleanup on the module:
138141
cleanUpModule(M);
139-
140-
MangleAndInterner Mangle(ES, M.getDataLayout());
141-
for (auto &GV : M.global_values()) {
142-
if (GV.isDeclaration() || GV.hasLocalLinkage() ||
143-
GV.hasAppendingLinkage())
144-
continue;
145-
146-
auto Name = Mangle(GV.getName());
147-
auto Flags = JITSymbolFlags::fromGlobalValue(GV);
148-
if (Flags.isCallable())
149-
Callables[Name] = SymbolAliasMapEntry(Name, Flags);
150-
else
151-
NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
152-
}
153142
});
154143

144+
for (auto &KV : R.getSymbols()) {
145+
auto &Name = KV.first;
146+
auto &Flags = KV.second;
147+
if (Flags.isCallable())
148+
Callables[Name] = SymbolAliasMapEntry(Name, Flags);
149+
else
150+
NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
151+
}
152+
155153
// Create a partitioning materialization unit and lodge it with the
156154
// implementation dylib.
157155
if (auto Err = PDR.getImplDylib().define(
158156
std::make_unique<PartitioningIRMaterializationUnit>(
159-
ES, std::move(TSM), R.getVModuleKey(), *this))) {
157+
ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(),
158+
*this))) {
160159
ES.reportError(std::move(Err));
161160
R.failMaterialization();
162161
return;
@@ -316,7 +315,7 @@ void CompileOnDemandLayer::emitPartition(
316315
}
317316

318317
R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
319-
ES, std::move(TSM), R.getVModuleKey(), *this));
318+
ES, *getManglingOptions(), std::move(TSM), R.getVModuleKey(), *this));
320319
BaseLayer.emit(std::move(R), std::move(*ExtractedTSM));
321320
}
322321

llvm/lib/ExecutionEngine/Orc/CompileUtils.cpp

+20-11
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,17 @@
2424
namespace llvm {
2525
namespace orc {
2626

27+
IRMaterializationUnit::ManglingOptions
28+
irManglingOptionsFromTargetOptions(const TargetOptions &Opts) {
29+
IRMaterializationUnit::ManglingOptions MO;
30+
31+
MO.EmulatedTLS = Opts.EmulatedTLS;
32+
33+
return MO;
34+
}
35+
2736
/// Compile a Module to an ObjectFile.
28-
SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
37+
Expected<SimpleCompiler::CompileResult> SimpleCompiler::operator()(Module &M) {
2938
CompileResult CachedObject = tryToLoadFromObjectCache(M);
3039
if (CachedObject)
3140
return CachedObject;
@@ -38,7 +47,8 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
3847
legacy::PassManager PM;
3948
MCContext *Ctx;
4049
if (TM.addPassesToEmitMC(PM, Ctx, ObjStream))
41-
llvm_unreachable("Target does not support MC emission.");
50+
return make_error<StringError>("Target does not support MC emission",
51+
inconvertibleErrorCode());
4252
PM.run(M);
4353
}
4454

@@ -47,14 +57,11 @@ SimpleCompiler::CompileResult SimpleCompiler::operator()(Module &M) {
4757

4858
auto Obj = object::ObjectFile::createObjectFile(ObjBuffer->getMemBufferRef());
4959

50-
if (Obj) {
51-
notifyObjectCompiled(M, *ObjBuffer);
52-
return std::move(ObjBuffer);
53-
}
60+
if (!Obj)
61+
return Obj.takeError();
5462

55-
// TODO: Actually report errors helpfully.
56-
consumeError(Obj.takeError());
57-
return nullptr;
63+
notifyObjectCompiled(M, *ObjBuffer);
64+
return std::move(ObjBuffer);
5865
}
5966

6067
SimpleCompiler::CompileResult
@@ -73,9 +80,11 @@ void SimpleCompiler::notifyObjectCompiled(const Module &M,
7380

7481
ConcurrentIRCompiler::ConcurrentIRCompiler(JITTargetMachineBuilder JTMB,
7582
ObjectCache *ObjCache)
76-
: JTMB(std::move(JTMB)), ObjCache(ObjCache) {}
83+
: IRCompiler(irManglingOptionsFromTargetOptions(JTMB.getOptions())),
84+
JTMB(std::move(JTMB)), ObjCache(ObjCache) {}
7785

78-
std::unique_ptr<MemoryBuffer> ConcurrentIRCompiler::operator()(Module &M) {
86+
Expected<std::unique_ptr<MemoryBuffer>>
87+
ConcurrentIRCompiler::operator()(Module &M) {
7988
auto TM = cantFail(JTMB.createTargetMachine());
8089
SimpleCompiler C(*TM, ObjCache);
8190
return C(M);

0 commit comments

Comments
 (0)