Speculation.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. //===---------- speculation.cpp - Utilities for Speculation ----------===//
  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. #include "llvm/ExecutionEngine/Orc/Speculation.h"
  9. #include "llvm/IR/BasicBlock.h"
  10. #include "llvm/IR/Function.h"
  11. #include "llvm/IR/IRBuilder.h"
  12. #include "llvm/IR/Instruction.h"
  13. #include "llvm/IR/Instructions.h"
  14. #include "llvm/IR/LLVMContext.h"
  15. #include "llvm/IR/Module.h"
  16. #include "llvm/IR/Type.h"
  17. #include "llvm/IR/Verifier.h"
  18. namespace llvm {
  19. namespace orc {
  20. // ImplSymbolMap methods
  21. void ImplSymbolMap::trackImpls(SymbolAliasMap ImplMaps, JITDylib *SrcJD) {
  22. assert(SrcJD && "Tracking on Null Source .impl dylib");
  23. std::lock_guard<std::mutex> Lockit(ConcurrentAccess);
  24. for (auto &I : ImplMaps) {
  25. auto It = Maps.insert({I.first, {I.second.Aliasee, SrcJD}});
  26. // check rationale when independent dylibs have same symbol name?
  27. assert(It.second && "ImplSymbols are already tracked for this Symbol?");
  28. (void)(It);
  29. }
  30. }
  31. // Trigger Speculative Compiles.
  32. void Speculator::speculateForEntryPoint(Speculator *Ptr, uint64_t StubId) {
  33. assert(Ptr && " Null Address Received in orc_speculate_for ");
  34. Ptr->speculateFor(StubId);
  35. }
  36. Error Speculator::addSpeculationRuntime(JITDylib &JD,
  37. MangleAndInterner &Mangle) {
  38. JITEvaluatedSymbol ThisPtr(pointerToJITTargetAddress(this),
  39. JITSymbolFlags::Exported);
  40. JITEvaluatedSymbol SpeculateForEntryPtr(
  41. pointerToJITTargetAddress(&speculateForEntryPoint),
  42. JITSymbolFlags::Exported);
  43. return JD.define(absoluteSymbols({
  44. {Mangle("__orc_speculator"), ThisPtr}, // Data Symbol
  45. {Mangle("__orc_speculate_for"), SpeculateForEntryPtr} // Callable Symbol
  46. }));
  47. }
  48. // If two modules, share the same LLVMContext, different threads must
  49. // not access them concurrently without locking the associated LLVMContext
  50. // this implementation follows this contract.
  51. void IRSpeculationLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
  52. ThreadSafeModule TSM) {
  53. assert(TSM && "Speculation Layer received Null Module ?");
  54. assert(TSM.getContext().getContext() != nullptr &&
  55. "Module with null LLVMContext?");
  56. // Instrumentation of runtime calls, lock the Module
  57. TSM.withModuleDo([this, &R](Module &M) {
  58. auto &MContext = M.getContext();
  59. auto SpeculatorVTy = StructType::create(MContext, "Class.Speculator");
  60. auto RuntimeCallTy = FunctionType::get(
  61. Type::getVoidTy(MContext),
  62. {SpeculatorVTy->getPointerTo(), Type::getInt64Ty(MContext)}, false);
  63. auto RuntimeCall =
  64. Function::Create(RuntimeCallTy, Function::LinkageTypes::ExternalLinkage,
  65. "__orc_speculate_for", &M);
  66. auto SpeclAddr = new GlobalVariable(
  67. M, SpeculatorVTy, false, GlobalValue::LinkageTypes::ExternalLinkage,
  68. nullptr, "__orc_speculator");
  69. IRBuilder<> Mutator(MContext);
  70. // QueryAnalysis allowed to transform the IR source, one such example is
  71. // Simplify CFG helps the static branch prediction heuristics!
  72. for (auto &Fn : M.getFunctionList()) {
  73. if (!Fn.isDeclaration()) {
  74. auto IRNames = QueryAnalysis(Fn);
  75. // Instrument and register if Query has result
  76. if (IRNames) {
  77. // Emit globals for each function.
  78. auto LoadValueTy = Type::getInt8Ty(MContext);
  79. auto SpeculatorGuard = new GlobalVariable(
  80. M, LoadValueTy, false, GlobalValue::LinkageTypes::InternalLinkage,
  81. ConstantInt::get(LoadValueTy, 0),
  82. "__orc_speculate.guard.for." + Fn.getName());
  83. SpeculatorGuard->setAlignment(Align(1));
  84. SpeculatorGuard->setUnnamedAddr(GlobalValue::UnnamedAddr::Local);
  85. BasicBlock &ProgramEntry = Fn.getEntryBlock();
  86. // Create BasicBlocks before the program's entry basicblock
  87. BasicBlock *SpeculateBlock = BasicBlock::Create(
  88. MContext, "__orc_speculate.block", &Fn, &ProgramEntry);
  89. BasicBlock *SpeculateDecisionBlock = BasicBlock::Create(
  90. MContext, "__orc_speculate.decision.block", &Fn, SpeculateBlock);
  91. assert(SpeculateDecisionBlock == &Fn.getEntryBlock() &&
  92. "SpeculateDecisionBlock not updated?");
  93. Mutator.SetInsertPoint(SpeculateDecisionBlock);
  94. auto LoadGuard =
  95. Mutator.CreateLoad(LoadValueTy, SpeculatorGuard, "guard.value");
  96. // if just loaded value equal to 0,return true.
  97. auto CanSpeculate =
  98. Mutator.CreateICmpEQ(LoadGuard, ConstantInt::get(LoadValueTy, 0),
  99. "compare.to.speculate");
  100. Mutator.CreateCondBr(CanSpeculate, SpeculateBlock, &ProgramEntry);
  101. Mutator.SetInsertPoint(SpeculateBlock);
  102. auto ImplAddrToUint =
  103. Mutator.CreatePtrToInt(&Fn, Type::getInt64Ty(MContext));
  104. Mutator.CreateCall(RuntimeCallTy, RuntimeCall,
  105. {SpeclAddr, ImplAddrToUint});
  106. Mutator.CreateStore(ConstantInt::get(LoadValueTy, 1),
  107. SpeculatorGuard);
  108. Mutator.CreateBr(&ProgramEntry);
  109. assert(Mutator.GetInsertBlock()->getParent() == &Fn &&
  110. "IR builder association mismatch?");
  111. S.registerSymbols(internToJITSymbols(*IRNames),
  112. &R->getTargetJITDylib());
  113. }
  114. }
  115. }
  116. });
  117. assert(!TSM.withModuleDo([](const Module &M) { return verifyModule(M); }) &&
  118. "Speculation Instrumentation breaks IR?");
  119. NextLayer.emit(std::move(R), std::move(TSM));
  120. }
  121. } // namespace orc
  122. } // namespace llvm