LLVM  3.7.0
OrcTargetSupport.cpp
Go to the documentation of this file.
1 #include "llvm/ADT/Triple.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 
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 
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.
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:114
const std::string & str() const
Definition: Triple.h:306
const std::string & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition: Module.h:261
static void insertResolverBlock(Module &M, JITCompileCallbackManagerBase &JCBM)
Insert module-level inline callback asm into module M for the symbols managed by JITResolveCallbackHa...
Base class for JITLayer independent aspects of JITCompileCallbackManager.
TargetAddress executeCompileCallback(TargetAddress TrampolineAddr)
Execute the callback for the given trampoline id.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
static const char * ResolverBlockName
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
uint64_t TargetAddress
Represents an address in the target process's address space.
Definition: JITSymbol.h:26
std::function< std::string(unsigned)> LabelNameFtor
Get a label name from the given index.
static LabelNameFtor insertCompileCallbackTrampolines(Module &M, TargetAddress TrampolineAddr, unsigned NumCalls, unsigned StartIndex=0)
Insert the requested number of trampolines into the given module.
#define I(x, y, z)
Definition: MD5.cpp:54
void appendModuleInlineAsm(StringRef Asm)
Append to the module-scope inline assembly blocks.
Definition: Module.h:307