[Orc] Use the 64-bit versions of FXSAVE/FXRSTOR for JIT reentry.
[oota-llvm.git] / lib / ExecutionEngine / Orc / OrcTargetSupport.cpp
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             << "  fxsave64  (%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             << "  fxrstor64 (%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.