LLVM  10.0.0svn
CompileOnDemandLayer.cpp
Go to the documentation of this file.
1 //===----- CompileOnDemandLayer.cpp - Lazily emit IR on first call --------===//
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 
10 #include "llvm/IR/Mangler.h"
11 #include "llvm/IR/Module.h"
12 
13 using namespace llvm;
14 using namespace llvm::orc;
15 
17  StringRef Suffix,
18  GVPredicate ShouldExtract) {
19 
20  auto DeleteExtractedDefs = [](GlobalValue &GV) {
21  // Bump the linkage: this global will be provided by the external module.
22  GV.setLinkage(GlobalValue::ExternalLinkage);
23 
24  // Delete the definition in the source module.
25  if (isa<Function>(GV)) {
26  auto &F = cast<Function>(GV);
27  F.deleteBody();
28  F.setPersonalityFn(nullptr);
29  } else if (isa<GlobalVariable>(GV)) {
30  cast<GlobalVariable>(GV).setInitializer(nullptr);
31  } else if (isa<GlobalAlias>(GV)) {
32  // We need to turn deleted aliases into function or variable decls based
33  // on the type of their aliasee.
34  auto &A = cast<GlobalAlias>(GV);
35  Constant *Aliasee = A.getAliasee();
36  assert(A.hasName() && "Anonymous alias?");
37  assert(Aliasee->hasName() && "Anonymous aliasee");
38  std::string AliasName = A.getName();
39 
40  if (isa<Function>(Aliasee)) {
41  auto *F = cloneFunctionDecl(*A.getParent(), *cast<Function>(Aliasee));
42  A.replaceAllUsesWith(F);
43  A.eraseFromParent();
44  F->setName(AliasName);
45  } else if (isa<GlobalVariable>(Aliasee)) {
46  auto *G = cloneGlobalVariableDecl(*A.getParent(),
47  *cast<GlobalVariable>(Aliasee));
48  A.replaceAllUsesWith(G);
49  A.eraseFromParent();
50  G->setName(AliasName);
51  } else
52  llvm_unreachable("Alias to unsupported type");
53  } else
54  llvm_unreachable("Unsupported global type");
55  };
56 
57  auto NewTSM = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
58  NewTSM.withModuleDo([&](Module &M) {
59  M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
60  });
61 
62  return NewTSM;
63 }
64 
65 namespace llvm {
66 namespace orc {
67 
69 public:
72  : IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
73  Parent(Parent) {}
74 
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  this->AliaseeImpls = Imp;
123 }
125  ThreadSafeModule TSM) {
126  assert(TSM && "Null module");
127 
128  auto &ES = getExecutionSession();
129 
130  // Sort the callables and non-callables, build re-exports and lodge the
131  // actual module with the implementation dylib.
132  auto &PDR = getPerDylibResources(R.getTargetJITDylib());
133 
134  SymbolAliasMap NonCallables;
135  SymbolAliasMap Callables;
136  TSM.withModuleDo([&](Module &M) {
137  // First, do some cleanup on the module:
138  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  }
153  });
154 
155  // Create a partitioning materialization unit and lodge it with the
156  // implementation dylib.
157  if (auto Err = PDR.getImplDylib().define(
158  std::make_unique<PartitioningIRMaterializationUnit>(
159  ES, std::move(TSM), R.getVModuleKey(), *this))) {
160  ES.reportError(std::move(Err));
162  return;
163  }
164 
165  R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables), true));
166  R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
167  std::move(Callables), AliaseeImpls));
168 }
169 
170 CompileOnDemandLayer::PerDylibResources &
171 CompileOnDemandLayer::getPerDylibResources(JITDylib &TargetD) {
172  auto I = DylibResources.find(&TargetD);
173  if (I == DylibResources.end()) {
174  auto &ImplD = getExecutionSession().createJITDylib(
175  TargetD.getName() + ".impl", false);
176  TargetD.withSearchOrderDo([&](const JITDylibSearchList &TargetSearchOrder) {
177  auto NewSearchOrder = TargetSearchOrder;
178  assert(!NewSearchOrder.empty() &&
179  NewSearchOrder.front().first == &TargetD &&
180  NewSearchOrder.front().second == true &&
181  "TargetD must be at the front of its own search order and match "
182  "non-exported symbol");
183  NewSearchOrder.insert(std::next(NewSearchOrder.begin()), {&ImplD, true});
184  ImplD.setSearchOrder(std::move(NewSearchOrder), false);
185  });
186  PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
187  I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
188  }
189 
190  return I->second;
191 }
192 
193 void CompileOnDemandLayer::cleanUpModule(Module &M) {
194  for (auto &F : M.functions()) {
195  if (F.isDeclaration())
196  continue;
197 
198  if (F.hasAvailableExternallyLinkage()) {
199  F.deleteBody();
200  F.setPersonalityFn(nullptr);
201  continue;
202  }
203  }
204 }
205 
206 void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) {
207  // Expands the partition to ensure the following rules hold:
208  // (1) If any alias is in the partition, its aliasee is also in the partition.
209  // (2) If any aliasee is in the partition, its aliases are also in the
210  // partiton.
211  // (3) If any global variable is in the partition then all global variables
212  // are in the partition.
213  assert(!Partition.empty() && "Unexpected empty partition");
214 
215  const Module &M = *(*Partition.begin())->getParent();
216  bool ContainsGlobalVariables = false;
217  std::vector<const GlobalValue *> GVsToAdd;
218 
219  for (auto *GV : Partition)
220  if (isa<GlobalAlias>(GV))
221  GVsToAdd.push_back(
222  cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
223  else if (isa<GlobalVariable>(GV))
224  ContainsGlobalVariables = true;
225 
226  for (auto &A : M.aliases())
227  if (Partition.count(cast<GlobalValue>(A.getAliasee())))
228  GVsToAdd.push_back(&A);
229 
230  if (ContainsGlobalVariables)
231  for (auto &G : M.globals())
232  GVsToAdd.push_back(&G);
233 
234  for (auto *GV : GVsToAdd)
235  Partition.insert(GV);
236 }
237 
238 void CompileOnDemandLayer::emitPartition(
241 
242  // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
243  // extracted module key, extracted module, and source module key
244  // together. This could be used, for example, to provide a specific
245  // memory manager instance to the linking layer.
246 
247  auto &ES = getExecutionSession();
248  GlobalValueSet RequestedGVs;
249  for (auto &Name : R.getRequestedSymbols()) {
250  assert(Defs.count(Name) && "No definition for symbol");
251  RequestedGVs.insert(Defs[Name]);
252  }
253 
254  /// Perform partitioning with the context lock held, since the partition
255  /// function is allowed to access the globals to compute the partition.
256  auto GVsToExtract =
257  TSM.withModuleDo([&](Module &M) { return Partition(RequestedGVs); });
258 
259  // Take a 'None' partition to mean the whole module (as opposed to an empty
260  // partition, which means "materialize nothing"). Emit the whole module
261  // unmodified to the base layer.
262  if (GVsToExtract == None) {
263  Defs.clear();
264  BaseLayer.emit(std::move(R), std::move(TSM));
265  return;
266  }
267 
268  // If the partition is empty, return the whole module to the symbol table.
269  if (GVsToExtract->empty()) {
270  R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
271  std::move(TSM), R.getSymbols(), std::move(Defs), *this));
272  return;
273  }
274 
275  // Ok -- we actually need to partition the symbols. Promote the symbol
276  // linkages/names, expand the partition to include any required symbols
277  // (i.e. symbols that can't be separated from our partition), and
278  // then extract the partition.
279  //
280  // FIXME: We apply this promotion once per partitioning. It's safe, but
281  // overkill.
282 
283  auto ExtractedTSM =
285  auto PromotedGlobals = PromoteSymbols(M);
286  if (!PromotedGlobals.empty()) {
287  MangleAndInterner Mangle(ES, M.getDataLayout());
289  for (auto &GV : PromotedGlobals)
290  SymbolFlags[Mangle(GV->getName())] =
292  if (auto Err = R.defineMaterializing(SymbolFlags))
293  return std::move(Err);
294  }
295 
296  expandPartition(*GVsToExtract);
297 
298  // Extract the requested partiton (plus any necessary aliases) and
299  // put the rest back into the impl dylib.
300  auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
301  return GVsToExtract->count(&GV);
302  };
303 
304  return extractSubModule(TSM, ".submodule", ShouldExtract);
305  });
306 
307  if (!ExtractedTSM) {
308  ES.reportError(ExtractedTSM.takeError());
310  return;
311  }
312 
313  R.replace(std::make_unique<PartitioningIRMaterializationUnit>(
314  ES, std::move(TSM), R.getVModuleKey(), *this));
315  BaseLayer.emit(std::move(R), std::move(*ExtractedTSM));
316 }
317 
318 } // end namespace orc
319 } // end namespace llvm
const NoneType None
Definition: None.h:23
static JITSymbolFlags fromGlobalValue(const GlobalValue &GV)
Construct a JITSymbolFlags value based on the flags of the given global value.
Definition: JITSymbol.cpp:21
static ThreadSafeModule extractSubModule(ThreadSafeModule &TSM, StringRef Suffix, GVPredicate ShouldExtract)
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error defineMaterializing(const SymbolFlagsMap &SymbolFlags)
Adds new symbols to the JITDylib and this responsibility instance.
Definition: Core.cpp:406
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:66
static Optional< GlobalValueSet > compileRequested(GlobalValueSet Requested)
Off-the-shelf partitioning which compiles all requested symbols (usually a single function at a time)...
amdgpu Simplify well known AMD library false FunctionCallee Value const Twine & Name
void setModuleIdentifier(StringRef ID)
Set the module identifier.
Definition: Module.h:274
void replace(std::unique_ptr< MaterializationUnit > MU)
Transfers responsibility to the given MaterializationUnit for all symbols defined by that Materializa...
Definition: Core.cpp:434
auto withModuleDo(Func &&F) -> decltype(F(std::declval< Module &>()))
Locks the associated ThreadSafeContext and calls the given function on the contained Module...
Externally visible function.
Definition: GlobalValue.h:48
F(f)
std::function< std::unique_ptr< IndirectStubsManager >()> IndirectStubsManagerBuilder
Builder for IndirectStubsManagers.
std::function< bool(const GlobalValue &)> GVPredicate
Definition: BitVector.h:937
const DataLayout & getDataLayout() const
Get the data layout for the module&#39;s target platform.
Definition: Module.cpp:369
std::vector< std::pair< JITDylib *, bool > > JITDylibSearchList
A list of (JITDylib*, bool) pairs.
Definition: Core.h:59
std::function< Optional< GlobalValueSet >(GlobalValueSet Requested)> PartitionFunction
Partitioning function.
SymbolFlags
Symbol flags.
Definition: Symbol.h:25
Mangles symbol names then uniques them in the context of an ExecutionSession.
Definition: Core.h:1014
std::map< SymbolStringPtr, GlobalValue * > SymbolNameToDefinitionMap
Definition: Layer.h:68
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:171
IRMaterializationUnit is a convenient base class for MaterializationUnits wrapping LLVM IR...
Definition: Layer.h:66
auto withSearchOrderDo(Func &&F) -> decltype(F(std::declval< const JITDylibSearchList &>()))
Do something with the search order (run under the session lock).
Definition: Core.h:953
ExecutionSession & getExecutionSession()
Returns the ExecutionSession for this layer.
Definition: Layer.h:31
JITDylib & getTargetJITDylib() const
Returns the target JITDylib that these symbols are being materialized into.
Definition: Core.h:185
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:417
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.
iterator_range< iterator > functions()
Definition: Module.h:610
VModuleKey getVModuleKey() const
Returns the VModuleKey for this instance.
Definition: Core.h:188
This is an important base class in LLVM.
Definition: Constant.h:41
std::unique_ptr< LazyReexportsMaterializationUnit > lazyReexports(LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc=nullptr, VModuleKey K=VModuleKey())
Define lazy-reexports based on the given SymbolAliasMap.
PartitioningIRMaterializationUnit(ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags, SymbolNameToDefinitionMap SymbolToDefinition, CompileOnDemandLayer &Parent)
An LLVM Module together with a shared ThreadSafeContext.
const std::string & getModuleIdentifier() const
Get the module identifier which is, essentially, the name of the module.
Definition: Module.h:211
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void setImplMap(ImplSymbolMap *Imp)
Sets the ImplSymbolMap.
Interface for layers that accept LLVM IR.
Definition: Layer.h:25
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:1840
Module.h This file contains the declarations for the Module class.
const DataFlowGraph & G
Definition: RDFGraph.cpp:202
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:371
An ExecutionSession represents a running JIT program.
Definition: Core.h:761
const SymbolFlagsMap & getSymbols() const
Returns the symbol flags map for this responsibility instance.
Definition: Core.h:194
CompileOnDemandLayer(ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr, IndirectStubsManagerBuilder BuildIndirectStubsManager)
Construct a CompileOnDemandLayer.
uint8_t uint64_t VModuleKey
VModuleKey provides a unique identifier (allocated and managed by ExecutionSessions) for a module add...
Definition: Core.h:42
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:516
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:418
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:48
void emit(MaterializationResponsibility R, ThreadSafeModule TSM) override
Emits the given module.
iterator_range< global_value_iterator > global_values()
Definition: Module.h:689
std::set< const GlobalValue * > GlobalValueSet
A symbol table that supports asynchoronous symbol queries.
Definition: Core.h:495