LLVM  9.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 NewTSMod = cloneToNewContext(TSM, ShouldExtract, DeleteExtractedDefs);
58  auto &M = *NewTSMod.getModule();
59  M.setModuleIdentifier((M.getModuleIdentifier() + Suffix).str());
60 
61  return NewTSMod;
62 }
63 
64 namespace llvm {
65 namespace orc {
66 
68 public:
71  : IRMaterializationUnit(ES, std::move(TSM), std::move(K)),
72  Parent(Parent) {}
73 
75  ThreadSafeModule TSM, SymbolFlagsMap SymbolFlags,
76  SymbolNameToDefinitionMap SymbolToDefinition,
77  CompileOnDemandLayer &Parent)
78  : IRMaterializationUnit(std::move(TSM), std::move(K),
79  std::move(SymbolFlags),
80  std::move(SymbolToDefinition)),
81  Parent(Parent) {}
82 
83 private:
84  void materialize(MaterializationResponsibility R) override {
85  Parent.emitPartition(std::move(R), std::move(TSM),
86  std::move(SymbolToDefinition));
87  }
88 
89  void discard(const JITDylib &V, const SymbolStringPtr &Name) override {
90  // All original symbols were materialized by the CODLayer and should be
91  // final. The function bodies provided by M should never be overridden.
92  llvm_unreachable("Discard should never be called on an "
93  "ExtractingIRMaterializationUnit");
94  }
95 
96  mutable std::mutex SourceModuleMutex;
97  CompileOnDemandLayer &Parent;
98 };
99 
102  return std::move(Requested);
103 }
104 
107  return None;
108 }
109 
111  ExecutionSession &ES, IRLayer &BaseLayer, LazyCallThroughManager &LCTMgr,
112  IndirectStubsManagerBuilder BuildIndirectStubsManager)
113  : IRLayer(ES), BaseLayer(BaseLayer), LCTMgr(LCTMgr),
114  BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)) {}
115 
117  this->Partition = std::move(Partition);
118 }
119 
121  ThreadSafeModule TSM) {
122  assert(TSM.getModule() && "Null module");
123 
124  auto &ES = getExecutionSession();
125  auto &M = *TSM.getModule();
126 
127  // First, do some cleanup on the module:
128  cleanUpModule(M);
129 
130  // Now 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  MangleAndInterner Mangle(ES, M.getDataLayout());
135  SymbolAliasMap NonCallables;
136  SymbolAliasMap Callables;
137  for (auto &GV : M.global_values()) {
138  if (GV.isDeclaration() || GV.hasLocalLinkage() || GV.hasAppendingLinkage())
139  continue;
140 
141  auto Name = Mangle(GV.getName());
142  auto Flags = JITSymbolFlags::fromGlobalValue(GV);
143  if (Flags.isCallable())
144  Callables[Name] = SymbolAliasMapEntry(Name, Flags);
145  else
146  NonCallables[Name] = SymbolAliasMapEntry(Name, Flags);
147  }
148 
149  // Create a partitioning materialization unit and lodge it with the
150  // implementation dylib.
151  if (auto Err = PDR.getImplDylib().define(
152  llvm::make_unique<PartitioningIRMaterializationUnit>(
153  ES, std::move(TSM), R.getVModuleKey(), *this))) {
154  ES.reportError(std::move(Err));
156  return;
157  }
158 
159  R.replace(reexports(PDR.getImplDylib(), std::move(NonCallables), true));
160  R.replace(lazyReexports(LCTMgr, PDR.getISManager(), PDR.getImplDylib(),
161  std::move(Callables)));
162 }
163 
164 CompileOnDemandLayer::PerDylibResources &
165 CompileOnDemandLayer::getPerDylibResources(JITDylib &TargetD) {
166  auto I = DylibResources.find(&TargetD);
167  if (I == DylibResources.end()) {
168  auto &ImplD = getExecutionSession().createJITDylib(
169  TargetD.getName() + ".impl", false);
170  TargetD.withSearchOrderDo([&](const JITDylibSearchList &TargetSearchOrder) {
171  auto NewSearchOrder = TargetSearchOrder;
172  assert(!NewSearchOrder.empty() &&
173  NewSearchOrder.front().first == &TargetD &&
174  NewSearchOrder.front().second == true &&
175  "TargetD must be at the front of its own search order and match "
176  "non-exported symbol");
177  NewSearchOrder.insert(std::next(NewSearchOrder.begin()), {&ImplD, true});
178  ImplD.setSearchOrder(std::move(NewSearchOrder), false);
179  });
180  PerDylibResources PDR(ImplD, BuildIndirectStubsManager());
181  I = DylibResources.insert(std::make_pair(&TargetD, std::move(PDR))).first;
182  }
183 
184  return I->second;
185 }
186 
187 void CompileOnDemandLayer::cleanUpModule(Module &M) {
188  for (auto &F : M.functions()) {
189  if (F.isDeclaration())
190  continue;
191 
192  if (F.hasAvailableExternallyLinkage()) {
193  F.deleteBody();
194  F.setPersonalityFn(nullptr);
195  continue;
196  }
197  }
198 }
199 
200 void CompileOnDemandLayer::expandPartition(GlobalValueSet &Partition) {
201  // Expands the partition to ensure the following rules hold:
202  // (1) If any alias is in the partition, its aliasee is also in the partition.
203  // (2) If any aliasee is in the partition, its aliases are also in the
204  // partiton.
205  // (3) If any global variable is in the partition then all global variables
206  // are in the partition.
207  assert(!Partition.empty() && "Unexpected empty partition");
208 
209  const Module &M = *(*Partition.begin())->getParent();
210  bool ContainsGlobalVariables = false;
211  std::vector<const GlobalValue *> GVsToAdd;
212 
213  for (auto *GV : Partition)
214  if (isa<GlobalAlias>(GV))
215  GVsToAdd.push_back(
216  cast<GlobalValue>(cast<GlobalAlias>(GV)->getAliasee()));
217  else if (isa<GlobalVariable>(GV))
218  ContainsGlobalVariables = true;
219 
220  for (auto &A : M.aliases())
221  if (Partition.count(cast<GlobalValue>(A.getAliasee())))
222  GVsToAdd.push_back(&A);
223 
224  if (ContainsGlobalVariables)
225  for (auto &G : M.globals())
226  GVsToAdd.push_back(&G);
227 
228  for (auto *GV : GVsToAdd)
229  Partition.insert(GV);
230 }
231 
232 void CompileOnDemandLayer::emitPartition(
235 
236  // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the
237  // extracted module key, extracted module, and source module key
238  // together. This could be used, for example, to provide a specific
239  // memory manager instance to the linking layer.
240 
241  auto &ES = getExecutionSession();
242 
243  GlobalValueSet RequestedGVs;
244  for (auto &Name : R.getRequestedSymbols()) {
245  assert(Defs.count(Name) && "No definition for symbol");
246  RequestedGVs.insert(Defs[Name]);
247  }
248 
249  auto GVsToExtract = Partition(RequestedGVs);
250 
251  // Take a 'None' partition to mean the whole module (as opposed to an empty
252  // partition, which means "materialize nothing"). Emit the whole module
253  // unmodified to the base layer.
254  if (GVsToExtract == None) {
255  Defs.clear();
256  BaseLayer.emit(std::move(R), std::move(TSM));
257  return;
258  }
259 
260  // If the partition is empty, return the whole module to the symbol table.
261  if (GVsToExtract->empty()) {
262  R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
263  std::move(TSM), R.getSymbols(), std::move(Defs), *this));
264  return;
265  }
266 
267  // Ok -- we actually need to partition the symbols. Promote the symbol
268  // linkages/names.
269  // FIXME: We apply this once per partitioning. It's safe, but overkill.
270  {
271  auto PromotedGlobals = PromoteSymbols(*TSM.getModule());
272  if (!PromotedGlobals.empty()) {
273  MangleAndInterner Mangle(ES, TSM.getModule()->getDataLayout());
274  SymbolFlagsMap SymbolFlags;
275  for (auto &GV : PromotedGlobals)
276  SymbolFlags[Mangle(GV->getName())] =
278  if (auto Err = R.defineMaterializing(SymbolFlags)) {
279  ES.reportError(std::move(Err));
281  return;
282  }
283  }
284  }
285 
286  expandPartition(*GVsToExtract);
287 
288  // Extract the requested partiton (plus any necessary aliases) and
289  // put the rest back into the impl dylib.
290  auto ShouldExtract = [&](const GlobalValue &GV) -> bool {
291  return GVsToExtract->count(&GV);
292  };
293 
294  auto ExtractedTSM = extractSubModule(TSM, ".submodule", ShouldExtract);
295  R.replace(llvm::make_unique<PartitioningIRMaterializationUnit>(
296  ES, std::move(TSM), R.getVModuleKey(), *this));
297 
298  BaseLayer.emit(std::move(R), std::move(ExtractedTSM));
299 }
300 
301 } // end namespace orc
302 } // 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:425
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:64
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 replace(std::unique_ptr< MaterializationUnit > MU)
Transfers responsibility to the given MaterializationUnit for all symbols defined by that Materializa...
Definition: Core.cpp:452
Externally visible function.
Definition: GlobalValue.h:48
F(f)
uint64_t VModuleKey
VModuleKey provides a unique identifier (allocated and managed by ExecutionSessions) for a module add...
Definition: Core.h:39
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:57
std::function< Optional< GlobalValueSet >(GlobalValueSet Requested)> PartitionFunction
Partitioning function.
Mangles symbol names then uniques them in the context of an ExecutionSession.
Definition: Core.h:914
std::map< SymbolStringPtr, GlobalValue * > SymbolNameToDefinitionMap
Definition: Layer.h:68
Tracks responsibility for materialization, and mediates interactions between MaterializationUnits and...
Definition: Core.h:154
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:874
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:168
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:398
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:608
VModuleKey getVModuleKey() const
Returns the VModuleKey for this instance.
Definition: Core.h:171
This is an important base class in LLVM.
Definition: Constant.h:41
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: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:1584
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:210
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:388
An ExecutionSession represents a running JIT program.
Definition: Core.h:696
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:512
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:442
const SymbolFlagsMap & getSymbols()
Returns the symbol flags map for this responsibility instance.
Definition: Core.h:177
Manages a set of &#39;lazy call-through&#39; trampolines.
Definition: LazyReexports.h:36
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.
std::set< const GlobalValue * > GlobalValueSet
A symbol table that supports asynchoronous symbol queries.
Definition: Core.h:495