Lang Hames | 68c9b8d | 2018-06-18 18:01:43 +0000 | [diff] [blame^] | 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 | |
| 10 | #include "llvm/ExecutionEngine/Orc/CompileOnDemandLayer.h" |
| 11 | #include "llvm/IR/Mangler.h" |
| 12 | #include "llvm/IR/Module.h" |
| 13 | #include "llvm/Support/raw_ostream.h" |
| 14 | |
| 15 | using namespace llvm; |
| 16 | using namespace llvm::orc; |
| 17 | |
| 18 | namespace { |
| 19 | |
| 20 | template <typename MaterializerFtor> |
| 21 | class LambdaValueMaterializer final : public ValueMaterializer { |
| 22 | public: |
| 23 | LambdaValueMaterializer(MaterializerFtor M) : M(std::move(M)) {} |
| 24 | |
| 25 | Value *materialize(Value *V) final { return M(V); } |
| 26 | |
| 27 | private: |
| 28 | MaterializerFtor M; |
| 29 | }; |
| 30 | |
| 31 | template <typename MaterializerFtor> |
| 32 | LambdaValueMaterializer<MaterializerFtor> |
| 33 | createLambdaValueMaterializer(MaterializerFtor M) { |
| 34 | return LambdaValueMaterializer<MaterializerFtor>(std::move(M)); |
| 35 | } |
| 36 | } // namespace |
| 37 | |
| 38 | static std::unique_ptr<Module> extractGlobals(Module &M) { |
| 39 | // FIXME: Add alias support. |
| 40 | |
| 41 | if (M.global_empty() && M.alias_empty() && !M.getModuleFlagsMetadata()) |
| 42 | return nullptr; |
| 43 | |
| 44 | auto GlobalsModule = llvm::make_unique<Module>( |
| 45 | (M.getName() + ".globals").str(), M.getContext()); |
| 46 | GlobalsModule->setDataLayout(M.getDataLayout()); |
| 47 | |
| 48 | ValueToValueMapTy VMap; |
| 49 | |
| 50 | for (auto &GV : M.globals()) |
| 51 | if (!GV.isDeclaration() && !VMap.count(&GV)) |
| 52 | cloneGlobalVariableDecl(*GlobalsModule, GV, &VMap); |
| 53 | |
| 54 | // Clone the module flags. |
| 55 | cloneModuleFlagsMetadata(*GlobalsModule, M, VMap); |
| 56 | |
| 57 | auto Materializer = createLambdaValueMaterializer([&](Value *V) -> Value * { |
| 58 | if (auto *F = dyn_cast<Function>(V)) |
| 59 | return cloneFunctionDecl(*GlobalsModule, *F); |
| 60 | return nullptr; |
| 61 | }); |
| 62 | |
| 63 | // Move the global variable initializers. |
| 64 | for (auto &GV : M.globals()) { |
| 65 | if (!GV.isDeclaration()) |
| 66 | moveGlobalVariableInitializer(GV, VMap, &Materializer); |
| 67 | GV.setInitializer(nullptr); |
| 68 | } |
| 69 | |
| 70 | return GlobalsModule; |
| 71 | } |
| 72 | |
| 73 | namespace llvm { |
| 74 | namespace orc { |
| 75 | |
| 76 | class ExtractingIRMaterializationUnit : public IRMaterializationUnit { |
| 77 | public: |
| 78 | ExtractingIRMaterializationUnit( |
| 79 | ExecutionSession &ES, CompileOnDemandLayer2 &Parent, |
| 80 | std::unique_ptr<Module> M, |
| 81 | std::shared_ptr<SymbolResolver> BackingResolver) |
| 82 | : IRMaterializationUnit(ES, std::move(M)), Parent(Parent), |
| 83 | BackingResolver(std::move(BackingResolver)) {} |
| 84 | |
| 85 | ExtractingIRMaterializationUnit( |
| 86 | std::unique_ptr<Module> M, SymbolFlagsMap SymbolFlags, |
| 87 | SymbolNameToDefinitionMap SymbolToDefinition, |
| 88 | CompileOnDemandLayer2 &Parent, |
| 89 | std::shared_ptr<SymbolResolver> BackingResolver) |
| 90 | : IRMaterializationUnit(std::move(M), std::move(SymbolFlags), |
| 91 | std::move(SymbolToDefinition)), |
| 92 | Parent(Parent), BackingResolver(std::move(BackingResolver)) {} |
| 93 | |
| 94 | private: |
| 95 | void materialize(MaterializationResponsibility R) override { |
| 96 | // FIXME: Need a 'notify lazy-extracting/emitting' callback to tie the |
| 97 | // extracted module key, extracted module, and source module key |
| 98 | // together. This could be used, for example, to provide a specific |
| 99 | // memory manager instance to the linking layer. |
| 100 | |
| 101 | // FIXME: The derived constructor should *only* look for the names of |
| 102 | // original function definitions in the target VSO. All other |
| 103 | // symbols should be looked up in the backing resolver. |
| 104 | |
| 105 | // Find the functions that have been requested. |
| 106 | auto RequestedSymbols = R.getRequestedSymbols(); |
| 107 | |
| 108 | // Extract them into a new module. |
| 109 | auto ExtractedFunctionsModule = |
| 110 | Parent.extractFunctions(*M, RequestedSymbols, SymbolToDefinition); |
| 111 | |
| 112 | // Build a new ExtractingIRMaterializationUnit to delegate the unrequested |
| 113 | // symbols to. |
| 114 | SymbolFlagsMap DelegatedSymbolFlags; |
| 115 | IRMaterializationUnit::SymbolNameToDefinitionMap |
| 116 | DelegatedSymbolToDefinition; |
| 117 | for (auto &KV : SymbolToDefinition) { |
| 118 | if (RequestedSymbols.count(KV.first)) |
| 119 | continue; |
| 120 | DelegatedSymbolFlags[KV.first] = |
| 121 | JITSymbolFlags::fromGlobalValue(*KV.second); |
| 122 | DelegatedSymbolToDefinition[KV.first] = KV.second; |
| 123 | } |
| 124 | |
| 125 | if (!DelegatedSymbolFlags.empty()) { |
| 126 | assert(DelegatedSymbolFlags.size() == |
| 127 | DelegatedSymbolToDefinition.size() && |
| 128 | "SymbolFlags and SymbolToDefinition should have the same number " |
| 129 | "of entries"); |
| 130 | R.delegate(llvm::make_unique<ExtractingIRMaterializationUnit>( |
| 131 | std::move(M), std::move(DelegatedSymbolFlags), |
| 132 | std::move(DelegatedSymbolToDefinition), Parent, BackingResolver)); |
| 133 | } |
| 134 | |
| 135 | Parent.emitExtractedFunctionsModule( |
| 136 | std::move(R), std::move(ExtractedFunctionsModule), BackingResolver); |
| 137 | } |
| 138 | |
| 139 | void discard(const VSO &V, SymbolStringPtr Name) override { |
| 140 | // All original symbols were materialized by the CODLayer and should be |
| 141 | // final. The function bodies provided by M should never be overridden. |
| 142 | llvm_unreachable("Discard should never be called on an " |
| 143 | "ExtractingIRMaterializationUnit"); |
| 144 | } |
| 145 | |
| 146 | CompileOnDemandLayer2 &Parent; |
| 147 | std::shared_ptr<SymbolResolver> BackingResolver; |
| 148 | }; |
| 149 | |
| 150 | CompileOnDemandLayer2::CompileOnDemandLayer2( |
| 151 | ExecutionSession &ES, IRLayer &BaseLayer, JITCompileCallbackManager &CCMgr, |
| 152 | IndirectStubsManagerBuilder BuildIndirectStubsManager, |
| 153 | GetSymbolResolverFunction GetSymbolResolver, |
| 154 | SetSymbolResolverFunction SetSymbolResolver, |
| 155 | GetAvailableContextFunction GetAvailableContext) |
| 156 | : IRLayer(ES), BaseLayer(BaseLayer), CCMgr(CCMgr), |
| 157 | BuildIndirectStubsManager(std::move(BuildIndirectStubsManager)), |
| 158 | GetSymbolResolver(std::move(GetSymbolResolver)), |
| 159 | SetSymbolResolver(std::move(SetSymbolResolver)), |
| 160 | GetAvailableContext(std::move(GetAvailableContext)) {} |
| 161 | |
| 162 | Error CompileOnDemandLayer2::add(VSO &V, VModuleKey K, |
| 163 | std::unique_ptr<Module> M) { |
| 164 | makeAllSymbolsExternallyAccessible(*M); |
| 165 | return IRLayer::add(V, K, std::move(M)); |
| 166 | } |
| 167 | |
| 168 | void CompileOnDemandLayer2::emit(MaterializationResponsibility R, VModuleKey K, |
| 169 | std::unique_ptr<Module> M) { |
| 170 | auto &ES = getExecutionSession(); |
| 171 | assert(M && "M should not be null"); |
| 172 | |
| 173 | for (auto &GV : M->global_values()) |
| 174 | if (GV.hasWeakLinkage()) |
| 175 | GV.setLinkage(GlobalValue::ExternalLinkage); |
| 176 | |
| 177 | auto GlobalsModule = extractGlobals(*M); |
| 178 | |
| 179 | MangleAndInterner Mangle(ES, M->getDataLayout()); |
| 180 | |
| 181 | // Delete the bodies of any available externally functions, rename the |
| 182 | // rest, and build the compile callbacks. |
| 183 | std::map<SymbolStringPtr, std::pair<JITTargetAddress, JITSymbolFlags>> |
| 184 | StubCallbacksAndLinkages; |
| 185 | auto &TargetVSO = R.getTargetVSO(); |
| 186 | |
| 187 | for (auto &F : M->functions()) { |
| 188 | if (F.isDeclaration()) |
| 189 | continue; |
| 190 | |
| 191 | if (F.hasAvailableExternallyLinkage()) { |
| 192 | F.deleteBody(); |
| 193 | continue; |
| 194 | } |
| 195 | |
| 196 | assert(F.hasName() && "Function should have a name"); |
| 197 | auto StubName = Mangle(F.getName()); |
| 198 | F.setName(F.getName() + "$body"); |
| 199 | auto BodyName = Mangle(F.getName()); |
| 200 | if (auto CallbackAddr = CCMgr.getCompileCallback( |
| 201 | [BodyName, &TargetVSO, &ES]() -> JITTargetAddress { |
| 202 | if (auto Sym = lookup({&TargetVSO}, BodyName)) |
| 203 | return Sym->getAddress(); |
| 204 | else { |
| 205 | ES.reportError(Sym.takeError()); |
| 206 | return 0; |
| 207 | } |
| 208 | })) { |
| 209 | auto Flags = JITSymbolFlags::fromGlobalValue(F); |
| 210 | Flags &= ~JITSymbolFlags::Weak; |
| 211 | StubCallbacksAndLinkages[std::move(StubName)] = |
| 212 | std::make_pair(*CallbackAddr, Flags); |
| 213 | } else { |
| 214 | ES.reportError(CallbackAddr.takeError()); |
| 215 | R.failMaterialization(); |
| 216 | return; |
| 217 | } |
| 218 | } |
| 219 | |
| 220 | // Build the stub inits map. |
| 221 | IndirectStubsManager::StubInitsMap StubInits; |
| 222 | for (auto &KV : StubCallbacksAndLinkages) |
| 223 | StubInits[*KV.first] = KV.second; |
| 224 | |
| 225 | // Build the function-body-extracting materialization unit. |
| 226 | if (auto Err = R.getTargetVSO().define( |
| 227 | llvm::make_unique<ExtractingIRMaterializationUnit>( |
| 228 | ES, *this, std::move(M), GetSymbolResolver(K)))) { |
| 229 | ES.reportError(std::move(Err)); |
| 230 | R.failMaterialization(); |
| 231 | return; |
| 232 | } |
| 233 | |
| 234 | // Build the stubs. |
| 235 | // FIXME: Remove function bodies materialization unit if stub creation fails. |
| 236 | auto &StubsMgr = getStubsManager(TargetVSO); |
| 237 | if (auto Err = StubsMgr.createStubs(StubInits)) { |
| 238 | ES.reportError(std::move(Err)); |
| 239 | R.failMaterialization(); |
| 240 | return; |
| 241 | } |
| 242 | |
| 243 | // Resolve and finalize stubs. |
| 244 | SymbolMap ResolvedStubs; |
| 245 | for (auto &KV : StubCallbacksAndLinkages) { |
| 246 | if (auto Sym = StubsMgr.findStub(*KV.first, false)) |
| 247 | ResolvedStubs[KV.first] = Sym; |
| 248 | else |
| 249 | llvm_unreachable("Stub went missing"); |
| 250 | } |
| 251 | |
| 252 | R.resolve(ResolvedStubs); |
| 253 | |
| 254 | BaseLayer.emit(std::move(R), std::move(K), std::move(GlobalsModule)); |
| 255 | } |
| 256 | |
| 257 | IndirectStubsManager &CompileOnDemandLayer2::getStubsManager(const VSO &V) { |
| 258 | std::lock_guard<std::mutex> Lock(CODLayerMutex); |
| 259 | StubManagersMap::iterator I = StubsMgrs.find(&V); |
| 260 | if (I == StubsMgrs.end()) |
| 261 | I = StubsMgrs.insert(std::make_pair(&V, BuildIndirectStubsManager())).first; |
| 262 | return *I->second; |
| 263 | } |
| 264 | |
| 265 | std::unique_ptr<Module> CompileOnDemandLayer2::extractFunctions( |
| 266 | Module &M, const SymbolNameSet &SymbolNames, |
| 267 | const SymbolNameToDefinitionMap &SymbolToDefinition) { |
| 268 | assert(!SymbolNames.empty() && "Can not extract an empty function set"); |
| 269 | |
| 270 | std::string ExtractedModName; |
| 271 | { |
| 272 | raw_string_ostream ExtractedModNameStream(ExtractedModName); |
| 273 | ExtractedModNameStream << M.getName(); |
| 274 | for (auto &Name : SymbolNames) |
| 275 | ExtractedModNameStream << "." << *Name; |
| 276 | } |
| 277 | |
| 278 | auto ExtractedFunctionsModule = |
| 279 | llvm::make_unique<Module>(ExtractedModName, GetAvailableContext()); |
| 280 | ExtractedFunctionsModule->setDataLayout(M.getDataLayout()); |
| 281 | |
| 282 | ValueToValueMapTy VMap; |
| 283 | |
| 284 | auto Materializer = createLambdaValueMaterializer([&](Value *V) -> Value * { |
| 285 | if (auto *F = dyn_cast<Function>(V)) |
| 286 | return cloneFunctionDecl(*ExtractedFunctionsModule, *F); |
| 287 | else if (auto *GV = dyn_cast<GlobalVariable>(V)) |
| 288 | return cloneGlobalVariableDecl(*ExtractedFunctionsModule, *GV); |
| 289 | return nullptr; |
| 290 | }); |
| 291 | |
| 292 | std::vector<std::pair<Function *, Function *>> OrigToNew; |
| 293 | for (auto &FunctionName : SymbolNames) { |
| 294 | assert(SymbolToDefinition.count(FunctionName) && |
| 295 | "No definition for symbol"); |
| 296 | auto *OrigF = cast<Function>(SymbolToDefinition.find(FunctionName)->second); |
| 297 | auto *NewF = cloneFunctionDecl(*ExtractedFunctionsModule, *OrigF, &VMap); |
| 298 | OrigToNew.push_back(std::make_pair(OrigF, NewF)); |
| 299 | } |
| 300 | |
| 301 | for (auto &KV : OrigToNew) |
| 302 | moveFunctionBody(*KV.first, VMap, &Materializer, KV.second); |
| 303 | |
| 304 | return ExtractedFunctionsModule; |
| 305 | } |
| 306 | |
| 307 | void CompileOnDemandLayer2::emitExtractedFunctionsModule( |
| 308 | MaterializationResponsibility R, std::unique_ptr<Module> M, |
| 309 | std::shared_ptr<SymbolResolver> Resolver) { |
| 310 | auto &TargetVSO = R.getTargetVSO(); |
| 311 | auto K = getExecutionSession().allocateVModule(); |
| 312 | |
| 313 | auto ExtractedFunctionsResolver = createSymbolResolver( |
| 314 | [=](SymbolFlagsMap &Flags, const SymbolNameSet &Symbols) { |
| 315 | return Resolver->lookupFlags(Flags, Symbols); |
| 316 | }, |
| 317 | [=, &TargetVSO](std::shared_ptr<AsynchronousSymbolQuery> Query, |
| 318 | SymbolNameSet Symbols) { |
| 319 | auto RemainingSymbols = TargetVSO.lookup(Query, std::move(Symbols)); |
| 320 | return Resolver->lookup(std::move(Query), std::move(RemainingSymbols)); |
| 321 | }); |
| 322 | |
| 323 | SetSymbolResolver(K, std::move(ExtractedFunctionsResolver)); |
| 324 | BaseLayer.emit(std::move(R), std::move(K), std::move(M)); |
| 325 | } |
| 326 | |
| 327 | } // end namespace orc |
| 328 | } // end namespace llvm |