[Orc] Tidy up the assembly for the x86-64 resolver block.
[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.
29   std::array<const char *, 11> GPRs = {{
30       "rbx", "r12", "r13", "r14", "r15", // Callee saved (rbp preserved below).
31       "rdi", "rsi", "rdx", "rcx", "r8", "r9",   // Int args.
32     }};
33
34   // Address of the executeCompileCallback function.
35   uint64_t CallbackAddr =
36       static_cast<uint64_t>(
37         reinterpret_cast<uintptr_t>(executeCompileCallback));
38
39   std::ostringstream AsmStream;
40   Triple TT(M.getTargetTriple());
41
42   // Switch to text section.
43   if (TT.getOS() == Triple::Darwin)
44     AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
45               << ".align 4, 0x90\n";
46   else
47     AsmStream << ".text\n"
48               << ".align 16, 0x90\n";
49
50   // Bake in a pointer to the callback manager immediately before the
51   // start of the resolver function.
52   AsmStream << "jit_callback_manager_addr:\n"
53             << "  .quad " << &JCBM << "\n";
54
55   // Start the resolver function.
56   AsmStream << ResolverBlockName << ":\n"
57             << "  pushq   %rbp\n"
58             << "  movq    %rsp, %rbp\n";
59
60   // Store the GPRs.
61   for (const auto &GPR : GPRs)
62     AsmStream << "  pushq   %" << GPR << "\n";
63
64   // Store floating-point state with FXSAVE.
65   AsmStream << "  subq    $512, %rsp\n"
66             << "  fxsave  (%rsp)\n"
67
68   // Load callback manager address, compute trampoline address, call JIT.
69             << "  lea     jit_callback_manager_addr(%rip), %rdi\n"
70             << "  movq    (%rdi), %rdi\n"
71             << "  movq    0x8(%rbp), %rsi\n"
72             << "  subq    $" << X86_64_TrampolineLength << ", %rsi\n"
73             << "  movabsq $" << CallbackAddr << ", %rax\n"
74             << "  callq   *%rax\n"
75
76   // Replace the return to the trampoline with the return address of the
77   // compiled function body.
78             << "  movq    %rax, 0x8(%rbp)\n"
79
80   // Restore the floating point state.
81             << "  fxrstor (%rsp)\n"
82             << "  addq    $512, %rsp\n";
83
84   for (const auto &GPR : make_range(GPRs.rbegin(), GPRs.rend()))
85     AsmStream << "  popq    %" << GPR << "\n";
86
87   // Restore original RBP and return to compiled function body.
88   AsmStream << "  popq    %rbp\n"
89             << "  retq\n";
90
91   M.appendModuleInlineAsm(AsmStream.str());
92 }
93
94 OrcX86_64::LabelNameFtor
95 OrcX86_64::insertCompileCallbackTrampolines(Module &M,
96                                             TargetAddress ResolverBlockAddr,
97                                             unsigned NumCalls,
98                                             unsigned StartIndex) {
99   const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";
100
101   std::ostringstream AsmStream;
102   Triple TT(M.getTargetTriple());
103
104   if (TT.getOS() == Triple::Darwin)
105     AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
106               << ".align 4, 0x90\n";
107   else
108     AsmStream << ".text\n"
109               << ".align 16, 0x90\n";
110
111   AsmStream << ResolverBlockPtrName << ":\n"
112             << "  .quad " << ResolverBlockAddr << "\n";
113
114   auto GetLabelName =
115     [=](unsigned I) {
116       std::ostringstream LabelStream;
117       LabelStream << "orc_jcc_" << (StartIndex + I);
118       return LabelStream.str();
119   };
120
121   for (unsigned I = 0; I < NumCalls; ++I)
122     AsmStream << GetLabelName(I) << ":\n"
123               << "  callq *" << ResolverBlockPtrName << "(%rip)\n";
124
125   M.appendModuleInlineAsm(AsmStream.str());
126
127   return GetLabelName;
128 }
129
130 } // End namespace orc.
131 } // End namespace llvm.