Speculation.h 7.4 KB

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