Speculation.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===-- Speculation.h - Speculative Compilation --*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Contains the definition to support speculative compilation when laziness is
  15. // enabled.
  16. //===----------------------------------------------------------------------===//
  17. #ifndef LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
  18. #define LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
  19. #include "llvm/ADT/DenseMap.h"
  20. #include "llvm/ADT/Optional.h"
  21. #include "llvm/ExecutionEngine/Orc/Core.h"
  22. #include "llvm/ExecutionEngine/Orc/DebugUtils.h"
  23. #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
  24. #include "llvm/Support/Debug.h"
  25. #include <mutex>
  26. #include <type_traits>
  27. #include <utility>
  28. namespace llvm {
  29. namespace orc {
  30. class Speculator;
  31. // Track the Impls (JITDylib,Symbols) of Symbols while lazy call through
  32. // trampolines are created. Operations are guarded by locks tp ensure that Imap
  33. // stays in consistent state after read/write
  34. class ImplSymbolMap {
  35. friend class Speculator;
  36. public:
  37. using AliaseeDetails = std::pair<SymbolStringPtr, JITDylib *>;
  38. using Alias = SymbolStringPtr;
  39. using ImapTy = DenseMap<Alias, AliaseeDetails>;
  40. void trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD);
  41. private:
  42. // FIX ME: find a right way to distinguish the pre-compile Symbols, and update
  43. // the callsite
  44. Optional<AliaseeDetails> getImplFor(const SymbolStringPtr &StubSymbol) {
  45. std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
  46. auto Position = Maps.find(StubSymbol);
  47. if (Position != Maps.end())
  48. return Position->getSecond();
  49. else
  50. return None;
  51. }
  52. std::mutex ConcurrentAccess;
  53. ImapTy Maps;
  54. };
  55. // Defines Speculator Concept,
  56. class Speculator {
  57. public:
  58. using TargetFAddr = JITTargetAddress;
  59. using FunctionCandidatesMap = DenseMap<SymbolStringPtr, SymbolNameSet>;
  60. using StubAddrLikelies = DenseMap<TargetFAddr, SymbolNameSet>;
  61. private:
  62. void registerSymbolsWithAddr(TargetFAddr ImplAddr,
  63. SymbolNameSet likelySymbols) {
  64. std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
  65. GlobalSpecMap.insert({ImplAddr, std::move(likelySymbols)});
  66. }
  67. void launchCompile(JITTargetAddress FAddr) {
  68. SymbolNameSet CandidateSet;
  69. // Copy CandidateSet is necessary, to avoid unsynchronized access to
  70. // the datastructure.
  71. {
  72. std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
  73. auto It = GlobalSpecMap.find(FAddr);
  74. if (It == GlobalSpecMap.end())
  75. return;
  76. CandidateSet = It->getSecond();
  77. }
  78. SymbolDependenceMap SpeculativeLookUpImpls;
  79. for (auto &Callee : CandidateSet) {
  80. auto ImplSymbol = AliaseeImplTable.getImplFor(Callee);
  81. // try to distinguish already compiled & library symbols
  82. if (!ImplSymbol.hasValue())
  83. continue;
  84. const auto &ImplSymbolName = ImplSymbol.getPointer()->first;
  85. JITDylib *ImplJD = ImplSymbol.getPointer()->second;
  86. auto &SymbolsInJD = SpeculativeLookUpImpls[ImplJD];
  87. SymbolsInJD.insert(ImplSymbolName);
  88. }
  89. DEBUG_WITH_TYPE("orc", {
  90. for (auto &I : SpeculativeLookUpImpls) {
  91. llvm::dbgs() << "\n In " << I.first->getName() << " JITDylib ";
  92. for (auto &N : I.second)
  93. llvm::dbgs() << "\n Likely Symbol : " << N;
  94. }
  95. });
  96. // for a given symbol, there may be no symbol qualified for speculatively
  97. // compile try to fix this before jumping to this code if possible.
  98. for (auto &LookupPair : SpeculativeLookUpImpls)
  99. ES.lookup(
  100. LookupKind::Static,
  101. makeJITDylibSearchOrder(LookupPair.first,
  102. JITDylibLookupFlags::MatchAllSymbols),
  103. SymbolLookupSet(LookupPair.second), SymbolState::Ready,
  104. [this](Expected<SymbolMap> Result) {
  105. if (auto Err = Result.takeError())
  106. ES.reportError(std::move(Err));
  107. },
  108. NoDependenciesToRegister);
  109. }
  110. public:
  111. Speculator(ImplSymbolMap &Impl, ExecutionSession &ref)
  112. : AliaseeImplTable(Impl), ES(ref), GlobalSpecMap(0) {}
  113. Speculator(const Speculator &) = delete;
  114. Speculator(Speculator &&) = delete;
  115. Speculator &operator=(const Speculator &) = delete;
  116. Speculator &operator=(Speculator &&) = delete;
  117. /// Define symbols for this Speculator object (__orc_speculator) and the
  118. /// speculation runtime entry point symbol (__orc_speculate_for) in the
  119. /// given JITDylib.
  120. Error addSpeculationRuntime(JITDylib &JD, MangleAndInterner &Mangle);
  121. // Speculatively compile likely functions for the given Stub Address.
  122. // destination of __orc_speculate_for jump
  123. void speculateFor(TargetFAddr StubAddr) { launchCompile(StubAddr); }
  124. // FIXME : Register with Stub Address, after JITLink Fix.
  125. void registerSymbols(FunctionCandidatesMap Candidates, JITDylib *JD) {
  126. for (auto &SymPair : Candidates) {
  127. auto Target = SymPair.first;
  128. auto Likely = SymPair.second;
  129. auto OnReadyFixUp = [Likely, Target,
  130. this](Expected<SymbolMap> ReadySymbol) {
  131. if (ReadySymbol) {
  132. auto RAddr = (*ReadySymbol)[Target].getAddress();
  133. registerSymbolsWithAddr(RAddr, std::move(Likely));
  134. } else
  135. this->getES().reportError(ReadySymbol.takeError());
  136. };
  137. // Include non-exported symbols also.
  138. ES.lookup(
  139. LookupKind::Static,
  140. makeJITDylibSearchOrder(JD, JITDylibLookupFlags::MatchAllSymbols),
  141. SymbolLookupSet(Target, SymbolLookupFlags::WeaklyReferencedSymbol),
  142. SymbolState::Ready, OnReadyFixUp, NoDependenciesToRegister);
  143. }
  144. }
  145. ExecutionSession &getES() { return ES; }
  146. private:
  147. static void speculateForEntryPoint(Speculator *Ptr, uint64_t StubId);
  148. std::mutex ConcurrentAccess;
  149. ImplSymbolMap &AliaseeImplTable;
  150. ExecutionSession &ES;
  151. StubAddrLikelies GlobalSpecMap;
  152. };
  153. class IRSpeculationLayer : public IRLayer {
  154. public:
  155. using IRlikiesStrRef = Optional<DenseMap<StringRef, DenseSet<StringRef>>>;
  156. using ResultEval = std::function<IRlikiesStrRef(Function &)>;
  157. using TargetAndLikelies = DenseMap<SymbolStringPtr, SymbolNameSet>;
  158. IRSpeculationLayer(ExecutionSession &ES, IRCompileLayer &BaseLayer,
  159. Speculator &Spec, MangleAndInterner &Mangle,
  160. ResultEval Interpreter)
  161. : IRLayer(ES, BaseLayer.getManglingOptions()), NextLayer(BaseLayer),
  162. S(Spec), Mangle(Mangle), QueryAnalysis(Interpreter) {}
  163. void emit(std::unique_ptr<MaterializationResponsibility> R,
  164. ThreadSafeModule TSM) override;
  165. private:
  166. TargetAndLikelies
  167. internToJITSymbols(DenseMap<StringRef, DenseSet<StringRef>> IRNames) {
  168. assert(!IRNames.empty() && "No IRNames received to Intern?");
  169. TargetAndLikelies InternedNames;
  170. for (auto &NamePair : IRNames) {
  171. DenseSet<SymbolStringPtr> TargetJITNames;
  172. for (auto &TargetNames : NamePair.second)
  173. TargetJITNames.insert(Mangle(TargetNames));
  174. InternedNames[Mangle(NamePair.first)] = std::move(TargetJITNames);
  175. }
  176. return InternedNames;
  177. }
  178. IRCompileLayer &NextLayer;
  179. Speculator &S;
  180. MangleAndInterner &Mangle;
  181. ResultEval QueryAnalysis;
  182. };
  183. } // namespace orc
  184. } // namespace llvm
  185. #endif // LLVM_EXECUTIONENGINE_ORC_SPECULATION_H
  186. #ifdef __GNUC__
  187. #pragma GCC diagnostic pop
  188. #endif