Home | History | Annotate | Download | only in Orc
      1 #include "llvm/ADT/Triple.h"
      2 #include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
      3 #include <array>
      4 
      5 using namespace llvm::orc;
      6 
      7 namespace {
      8 
      9 uint64_t executeCompileCallback(JITCompileCallbackManagerBase *JCBM,
     10                                 TargetAddress CallbackID) {
     11   return JCBM->executeCompileCallback(CallbackID);
     12 }
     13 
     14 }
     15 
     16 namespace llvm {
     17 namespace orc {
     18 
     19 const char* OrcX86_64::ResolverBlockName = "orc_resolver_block";
     20 
     21 void OrcX86_64::insertResolverBlock(
     22     Module &M, JITCompileCallbackManagerBase &JCBM) {
     23 
     24   // Trampoline code-sequence length, used to get trampoline address from return
     25   // address.
     26   const unsigned X86_64_TrampolineLength = 6;
     27 
     28   // List of x86-64 GPRs to save. Note - RBP saved separately below.
     29   std::array<const char *, 14> GPRs = {{
     30       "rax", "rbx", "rcx", "rdx",
     31       "rsi", "rdi", "r8", "r9",
     32       "r10", "r11", "r12", "r13",
     33       "r14", "r15"
     34     }};
     35 
     36   // Address of the executeCompileCallback function.
     37   uint64_t CallbackAddr =
     38       static_cast<uint64_t>(
     39         reinterpret_cast<uintptr_t>(executeCompileCallback));
     40 
     41   std::ostringstream AsmStream;
     42   Triple TT(M.getTargetTriple());
     43 
     44   // Switch to text section.
     45   if (TT.getOS() == Triple::Darwin)
     46     AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
     47               << ".align 4, 0x90\n";
     48   else
     49     AsmStream << ".text\n"
     50               << ".align 16, 0x90\n";
     51 
     52   // Bake in a pointer to the callback manager immediately before the
     53   // start of the resolver function.
     54   AsmStream << "jit_callback_manager_addr:\n"
     55             << "  .quad " << &JCBM << "\n";
     56 
     57   // Start the resolver function.
     58   AsmStream << ResolverBlockName << ":\n"
     59             << "  pushq   %rbp\n"
     60             << "  movq    %rsp, %rbp\n";
     61 
     62   // Store the GPRs.
     63   for (const auto &GPR : GPRs)
     64     AsmStream << "  pushq   %" << GPR << "\n";
     65 
     66   // Store floating-point state with FXSAVE.
     67   // Note: We need to keep the stack 16-byte aligned, so if we've emitted an odd
     68   //       number of 64-bit pushes so far (GPRs.size() plus 1 for RBP) then add
     69   //       an extra 64 bits of padding to the FXSave area.
     70   unsigned Padding = (GPRs.size() + 1) % 2 ? 8 : 0;
     71   unsigned FXSaveSize = 512 + Padding;
     72   AsmStream << "  subq    $" << FXSaveSize << ", %rsp\n"
     73             << "  fxsave  (%rsp)\n"
     74 
     75   // Load callback manager address, compute trampoline address, call JIT.
     76             << "  lea     jit_callback_manager_addr(%rip), %rdi\n"
     77             << "  movq    (%rdi), %rdi\n"
     78             << "  movq    0x8(%rbp), %rsi\n"
     79             << "  subq    $" << X86_64_TrampolineLength << ", %rsi\n"
     80             << "  movabsq $" << CallbackAddr << ", %rax\n"
     81             << "  callq   *%rax\n"
     82 
     83   // Replace the return to the trampoline with the return address of the
     84   // compiled function body.
     85             << "  movq    %rax, 0x8(%rbp)\n"
     86 
     87   // Restore the floating point state.
     88             << "  fxrstor (%rsp)\n"
     89             << "  addq    $" << FXSaveSize << ", %rsp\n";
     90 
     91   for (const auto &GPR : make_range(GPRs.rbegin(), GPRs.rend()))
     92     AsmStream << "  popq    %" << GPR << "\n";
     93 
     94   // Restore original RBP and return to compiled function body.
     95   AsmStream << "  popq    %rbp\n"
     96             << "  retq\n";
     97 
     98   M.appendModuleInlineAsm(AsmStream.str());
     99 }
    100 
    101 OrcX86_64::LabelNameFtor
    102 OrcX86_64::insertCompileCallbackTrampolines(Module &M,
    103                                             TargetAddress ResolverBlockAddr,
    104                                             unsigned NumCalls,
    105                                             unsigned StartIndex) {
    106   const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";
    107 
    108   std::ostringstream AsmStream;
    109   Triple TT(M.getTargetTriple());
    110 
    111   if (TT.getOS() == Triple::Darwin)
    112     AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
    113               << ".align 4, 0x90\n";
    114   else
    115     AsmStream << ".text\n"
    116               << ".align 16, 0x90\n";
    117 
    118   AsmStream << ResolverBlockPtrName << ":\n"
    119             << "  .quad " << ResolverBlockAddr << "\n";
    120 
    121   auto GetLabelName =
    122     [=](unsigned I) {
    123       std::ostringstream LabelStream;
    124       LabelStream << "orc_jcc_" << (StartIndex + I);
    125       return LabelStream.str();
    126   };
    127 
    128   for (unsigned I = 0; I < NumCalls; ++I)
    129     AsmStream << GetLabelName(I) << ":\n"
    130               << "  callq *" << ResolverBlockPtrName << "(%rip)\n";
    131 
    132   M.appendModuleInlineAsm(AsmStream.str());
    133 
    134   return GetLabelName;
    135 }
    136 
    137 } // End namespace orc.
    138 } // End namespace llvm.
    139