LLVM  8.0.1
CompileOnDemandLayer.cpp
Go to the documentation of this file.
1 //===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
11 #include "llvm/IR/Mangler.h"
12 #include "llvm/IR/Module.h"
13 
14 using namespace llvm;
15 using namespace llvm::orc;
16 
18  StringRef Suffix,
19  GVPredicate ShouldExtract) {
20 
21  auto DeleteExtractedDefs = [](GlobalValue &GV) {
22  // Bump the linkage: this global will be provided by the external module.
23  GV.setLinkage(GlobalValue::ExternalLinkage);
24 
25  // Delete the definition in the source module.
26  if (isa<Function>(GV)) {
27  auto &F = cast<Function>(GV);
28  F.deleteBody();
29  F.setPersonalityFn(nullptr);
30  } else if (isa<GlobalVariable>(GV)) {
31  cast<GlobalVariable>(GV).setInitializer(nullptr);
32  } else if (isa<GlobalAlias>(GV)) {
33  // We need to turn deleted aliases into function or variable decls based
34  // on the type of their aliasee.
35  auto &A = cast<GlobalAlias>(GV);
36  Constant *Aliasee = A.getAliasee();
37  assert(A.hasName() && "Anonymous alias?");
38  assert(Aliasee->hasName() && "Anonymous aliasee");
39  std::string AliasName = A.getName();
40 
41  if (isa<Function>(Aliasee)) {
42  auto *F = cloneFunctionDecl(*A.getParent(), *cast<Function>(Aliasee));
43  A.replaceAllUsesWith(F);
44  A.eraseFromParent();
45  F->setName(AliasName);
46  } else if (isa<GlobalVariable>(Aliasee)) {
47  auto *G = cloneGlobalVariableDecl(*A.getParent(),
48  *cast<GlobalVariable>(Aliasee));
49  A.replaceAllUsesWith(G);
50  A.eraseFromParent();
51  G->setName(AliasName);
52  } else
53  llvm_unreachable("Alias to unsupported type");
54  } else
55  llvm_unreachable("Unsupported global type");
56  };
57 
58  auto NewTSMod = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
59  auto &M = *NewTSMod.getModule();
60  M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
61 
62  return NewTSMod;
63 }
64 
65 namespace llvm {
66 namespace orc {
67 
69 public:
72  : IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
73  Parent(Parent) {}
74 
76  ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
77  SymbolNameToDefinitionMap SymbolToDefinition,
78  CompileOnDemandLayer &Parent)
79  : IRMaterializationUnit(std::move(TSM), std::move(K),
80  std::move(SymbolFlags),
81  std::move(SymbolToDefinition)),
82  Parent(Parent) {}
83 
84 private:
85  void materialize(MaterializationResponsibility R) override {
86  Parent.emitPartition(std::move(R), std::move(TSM),
87  std::move(SymbolToDefinition));
88  }
89 
90  void discard(const JITDylib &V, const SymbolStringPtr &Name) override {
91  // All original symbols were materialized by the CODLayer and should be
92  // final. The function bodies provided by M should never be overridden.
93  llvm_unreachable("Discard should never be called on an "
94  "ExtractingIRMaterializationUnit");
95  }
96 
97  mutable std::mutex SourceModuleMutex;
98  CompileOnDemandLayer &Parent;
99 };
100 
103  return std::move(Requested);
104 }
105 
108  return None;
109 }
110 
112  ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
113  IndirectStubsManagerBuilder BuildIndirectStubsManager)
114  : IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
115  BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
116 
118  this->Partition = std::move(Partition);
119 }
120 
122  ThreadSafeModule TSM) {
123  assert(TSM.getModule() && "Null module");
124 
125  auto &ES = getExecutionSession();
126  auto &M = *TSM.getModule();
127 
128  // First, do some cleanup on the module:
129  cleanUpModule(M);
130 
131  // Now sort the callables and non-callables, build re-exports and lodge the
132  // actual module with the implementation dylib.
133  auto &PDR = getPerDylibResources(R.getTargetJITDylib());
134 
135  MangleAndInterner Mangle(ES, M.getDataLayout());
136  SymbolAliasMap NonCallables;
137  SymbolAliasMap Callables;
138  for (auto &GV : M.global_values()) {
139  if (GV.isDeclaration() || GV.hasLocalLinkage() || GV.hasAppendingLinkage())
140  continue;
141 
142  auto Name = Mangle(GV.getName());
143  auto Flags = JITSymbolFlags::fromGlobalValue(GV);
144  if (Flags.isCallable())
145  Callables[Name] = SymbolAliasMapEntry(Name, Flags);
146  else
147  NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
148  }
149 
150  // Create a partitioning materialization unit and lodge it with the
151  // implementation dylib.
152  if (auto Err = PDR.getImplDylib().define(
153  llvm::make_unique<PartitioningIRMaterializationUnit>(
154  ES, std::move(TSM), R.getVModuleKey(), *this))) {
155  ES.reportError(std::move(Err));
157  return;
158  }
159 
160  R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables), true));
161  R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
162  std::move(Callables)));
163 }
164 
165 CompileOnDemandLayer::PerDylibResources &
166 CompileOnDemandLayer::getPerDylibResources(JITDylib &TargetD) {
167  auto I = DylibResources.find(&TargetD);
168  if (I == DylibResources.end()) {
169  auto &ImplD = getExecutionSession().createJITDylib(
170  TargetD.getName() + ".impl", false);
171  TargetD.withSearchOrderDo([&](const JITDylibSearchList &TargetSearchOrder) {
172  auto NewSearchOrder = TargetSearchOrder;
173  assert(!NewSearchOrder.empty() &&
174  NewSearchOrder.front().first == &TargetD &&
175  NewSearchOrder.front().second == true &&
176  "TargetD must be at the front of its own search order and match "
177  "non-exported symbol");
178  NewSearchOrder.insert(std::next(NewSearchOrder.begin()), {&ImplD, true});
179  ImplD.setSearchOrder(std::move(NewSearchOrder), false);
180  });
181  PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
182  I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
183  }
184 
185  return I->second;
186 }
187 
188 void CompileOnDemandLayer::cleanUpModule(Module &M) {
189  for (auto &F : M.functions()) {
190  if (F.isDeclaration())
191  continue;
192 
193  if (F.hasAvailableExternallyLinkage()) {
194  F.deleteBody();
195  F.setPersonalityFn(nullptr);
196  continue;
197  }
198  }
199 }
200 
201 void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) {
202  // Expands the partition to ensure the following rules hold:
203  // (1) If any alias is in the partition, its aliasee is also in the partition.
204  // (2) If any aliasee is in the partition, its aliases are also in the
205  // partiton.
206  // (3) If any global variable is in the partition then all global variables
207  // are in the partition.
208  assert(!Partition.empty() && "Unexpected empty partition");
209 
210  const Module &M = *(*Partition.begin())->getParent();
211  bool ContainsGlobalVariables = false;
212  std::vector<const GlobalValue *> GVsToAdd;
213 
214  for (auto *GV : Partition)
215  if (isa<GlobalAlias>(GV))
216  GVsToAdd.push_back(
217  cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
218  else if (isa<GlobalVariable>(GV))
219  ContainsGlobalVariables = true;
220 
221  for (auto &A : M.aliases())
222  if (Partition.count(cast<GlobalValue>(A.getAliasee())))
223  GVsToAdd.push_back(&A);
224 
225  if (ContainsGlobalVariables)
226  for (auto &G : M.globals())
227  GVsToAdd.push_back(&G);
228 
229  for (auto *GV : GVsToAdd)
230  Partition.insert(GV);
231 }
232 
233 void CompileOnDemandLayer::emitPartition(
236 
237  // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
238  // extracted module key, extracted module, and source module key
239  // together. This could be used, for example, to provide a specific
240  // memory manager instance to the linking layer.
241 
242  auto &ES = getExecutionSession();
243 
244  GlobalValueSet RequestedGVs;
245  for (auto &Name : R.getRequestedSymbols()) {
246  assert(Defs.count(Name) && "No definition for symbol");
247  RequestedGVs.insert(Defs[Name]);
248  }
249 
250  auto GVsToExtract = Partition(RequestedGVs);
251 
252  // Take a 'None' partition to mean the whole module (as opposed to an empty
253  // partition, which means "materialize nothing"). Emit the whole module
254  // unmodified to the base layer.
255  if (GVsToExtract == None) {
256  Defs.clear();
257  BaseLayer.emit(std::move(R), std::move(TSM));
258  return;
259  }
260 
261  // If the partition is empty, return the whole module to the symbol table.
262  if (GVsToExtract->empty()) {
263  R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
264  std::move(TSM), R.getSymbols(), std::move(Defs), *this));
265  return;
266  }
267 
268  // Ok -- we actually need to partition the symbols. Promote the symbol
269  // linkages/names.
270  // FIXME: We apply this once per partitioning. It's safe, but overkill.
271  {
272  auto PromotedGlobals = PromoteSymbols(*TSM.getModule());
273  if (!PromotedGlobals.empty()) {
274  MangleAndInterner Mangle(ES, TSM.getModule()->getDataLayout());
275  SymbolFlagsMap SymbolFlags;
276  for (auto &GV : PromotedGlobals)
277  SymbolFlags[Mangle(GV->getName())] =
279  if (auto Err = R.defineMaterializing(SymbolFlags)) {
280  ES.reportError(std::move(Err));
282  return;
283  }
284  }
285  }
286 
287  expandPartition(*GVsToExtract);
288 
289  // Extract the requested partiton (plus any necessary aliases) and
290  // put the rest back into the impl dylib.
291  auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
292  return GVsToExtract->count(&GV);
293  };
294 
295  auto ExtractedTSM = extractSubModule(TSM, ".submodule", ShouldExtract);
296  R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
297  ES, std::move(TSM), R.getVModuleKey(), *this));
298 
299  BaseLayer.emit(std::move(R), std::move(ExtractedTSM));
300 }
301 
302 } // end namespace orc
303 } // end namespace llvm
const NoneType None
Definition: None.h:24
static JITSymbolFlags fromGlobalValue(const GlobalValue &GV)
Construct a JITSymbolFlags value based on the flags of the given global value.
Definition: JITSymbol.cpp:22
static ThreadSafeModule extractSubModule(ThreadSafeModule &TSM, StringRef Suffix, GVPredicate ShouldExtract)
This class represents lattice values for constants.
Definition: AllocatorList.h:24
Error defineMaterializing(const SymbolFlagsMap &SymbolFlags)
Adds new symbols to the JITDylib and this responsibility instance.
Definition: Core.cpp:426
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:65
static Optional< GlobalValueSet > compileRequested(GlobalValueSet Requested)
Off-the-shelf partitioning which compiles all requested symbols (usually a single function at a time)...
void replace(std::unique_ptr< MaterializationUnit > MU)
Transfers responsibility to the given MaterializationUnit for all symbols defined by that Materializa...
Definition: Core.cpp:453
Externally visible function.
Definition: GlobalValue.h:49
F(f)
uint64_t VModuleKey
VModuleKey provides a unique identifier (allocated and managed by ExecutionSessions) for a module add...
Definition: Core.h:40
std::function< std::unique_ptr< IndirectStubsManager >()> IndirectStubsManagerBuilder
Builder for IndirectStubsManagers.
std::function< bool(const GlobalValue &)> GVPredicate
amdgpu Simplify well known AMD library false Value Value const Twine & Name
Definition: BitVector.h:938
const DataLayout & getDataLayout() const
Get the data layout for the module&#39;s target platform.
Definition: Module.cpp:371
std::vector< std::pair< JITDylib *, bool > > JITDylibSearchList
A list of (JITDylib*, bool) pairs.
Definition: Core.h:58
std::function< Optional< GlobalValueSet >(GlobalValueSet Requested)> PartitionFunction
Partitioning function.
Mangles symbol names then uniques them in the context of an ExecutionSession.
Definition: Core.h:915
std::map< SymbolStringPtr, GlobalValue * > SymbolNameToDefinitionMap
Definition: Layer.h:69
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:155
IRMaterializationUnit is a convenient base class for MaterializationUnits wrapping LLVM IR...
Definition: Layer.h:67
auto withSearchOrderDo(Func &&F) -> decltype(F(std::declval< const JITDylibSearchList &>()))
Do something with the search order (run under the session lock).
Definition: Core.h:875
ExecutionSession & getExecutionSession()
Returns the ExecutionSession for this layer.
Definition: Layer.h:32
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition: Core.h:169
std::unique_ptr< ReExportsMaterializationUnit > reexports(JITDylib &SourceJD, SymbolAliasMap Aliases, bool MatchNonExported=false, VModuleKey K=VModuleKey())
Create a materialization unit for re-exporting symbols from another JITDylib with alternative names/f...
Definition: Core.h:399
GlobalVariable * cloneGlobalVariableDecl(Module &Dst, const GlobalVariable &GV, ValueToValueMapTy *VMap=nullptr)
Clone a global variable declaration into a new module.
Pointer to a pooled string representing a symbol name.
virtual void emit(MaterializationResponsibility R, ThreadSafeModule TSM)=0
Emit should materialize the given IR.
Module * getModule()
Get the module wrapped by this ThreadSafeModule.
iterator_range< iterator > functions()
Definition: Module.h:606
VModuleKey getVModuleKey() const
Returns the VModuleKey for this instance.
Definition: Core.h:172
This is an important base class in LLVM.
Definition: Constant.h:42
PartitioningIRMaterializationUnit(ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, SymbolNameToDefinitionMap SymbolToDefinition, CompileOnDemandLayer &Parent)
An LLVM Module together with a shared ThreadSafeContext.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Interface for layers that accept LLVM IR.
Definition: Layer.h:26
Function * cloneFunctionDecl(Module &Dst, const Function &F, ValueToValueMapTy *VMap=nullptr)
Clone a function declaration into a new module.
JITDylib & createJITDylib(std::string Name, bool AddToMainDylibSearchOrder=true)
Add a new JITDylib to this ExecutionSession.
Definition: Core.cpp:1585
std::unique_ptr< LazyReexportsMaterializationUnit > lazyReexports(LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, VModuleKey K=VModuleKey())
Define lazy-reexports based on the given SymbolAliasMap.
Module.h This file contains the declarations for the Module class.
const DataFlowGraph & G
Definition: RDFGraph.cpp:211
static Optional< GlobalValueSet > compileWholeModule(GlobalValueSet Requested)
Off-the-shelf partitioning which compiles whole modules whenever any symbol in them is requested...
SymbolNameSet getRequestedSymbols() const
Returns the names of any symbols covered by this MaterializationResponsibility object that have queri...
Definition: Core.cpp:389
An ExecutionSession represents a running JIT program.
Definition: Core.h:697
CompileOnDemandLayer(ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr, IndirectStubsManagerBuilder BuildIndirectStubsManager)
Construct a CompileOnDemandLayer.
void setPartitionFunction(PartitionFunction Partition)
Sets the partition function.
#define I(x, y, z)
Definition: MD5.cpp:58
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
const std::string & getName() const
Get the name for this JITDylib.
Definition: Core.h:513
ThreadSafeModule cloneToNewContext(ThreadSafeModule &TSMW, GVPredicate ShouldCloneDef=GVPredicate(), GVModifier UpdateClonedDefSource=GVModifier())
Clones the given module on to a new context.
PartitioningIRMaterializationUnit(ExecutionSession &ES, ThreadSafeModule TSM, VModuleKey K, CompileOnDemandLayer &Parent)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
void failMaterialization()
Notify all not-yet-emitted covered by this MaterializationResponsibility instance that an error has o...
Definition: Core.cpp:443
const SymbolFlagsMap & getSymbols()
Returns the symbol flags map for this responsibility instance.
Definition: Core.h:178
Manages a set of &#39;lazy call-through&#39; trampolines.
Definition: LazyReexports.h:37
static const Function * getParent(const Value *V)
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override
Emits the given module.
std::set< const GlobalValue * > GlobalValueSet
A symbol table that supports asynchoronous symbol queries.
Definition: Core.h:496