blob: ef34c4a2b451dc589c7f27589362e7199a37d56e [file] [log] [blame]
Lang Hames93de2a12015-01-23 21:25:00 +00001#include "llvm/ADT/Triple.h"
Lang Hames27547142015-02-17 01:18:38 +00002#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
Lang Hames98c2ac12015-10-19 17:43:51 +00003#include "llvm/Support/Process.h"
Lang Hames93de2a12015-01-23 21:25:00 +00004#include <array>
5
Lang Hames98c2ac12015-10-19 17:43:51 +00006
Lang Hamese7380612015-02-21 20:44:36 +00007using namespace llvm::orc;
Lang Hames93de2a12015-01-23 21:25:00 +00008
9namespace {
10
Lang Hames8389b552015-03-25 02:45:50 +000011uint64_t executeCompileCallback(JITCompileCallbackManagerBase *JCBM,
Lang Hames27547142015-02-17 01:18:38 +000012 TargetAddress CallbackID) {
13 return JCBM->executeCompileCallback(CallbackID);
Lang Hames93de2a12015-01-23 21:25:00 +000014}
Lang Hames27547142015-02-17 01:18:38 +000015
Lang Hames93de2a12015-01-23 21:25:00 +000016}
17
18namespace llvm {
Lang Hamese7380612015-02-21 20:44:36 +000019namespace orc {
Lang Hames93de2a12015-01-23 21:25:00 +000020
Lang Hames27547142015-02-17 01:18:38 +000021const char* OrcX86_64::ResolverBlockName = "orc_resolver_block";
Lang Hames93de2a12015-01-23 21:25:00 +000022
Lang Hames27547142015-02-17 01:18:38 +000023void OrcX86_64::insertResolverBlock(
Lang Hames8389b552015-03-25 02:45:50 +000024 Module &M, JITCompileCallbackManagerBase &JCBM) {
Lang Hamese51ab6e2015-04-06 03:01:29 +000025
26 // Trampoline code-sequence length, used to get trampoline address from return
27 // address.
Lang Hamescd118e72015-03-24 04:27:02 +000028 const unsigned X86_64_TrampolineLength = 6;
Lang Hamese51ab6e2015-04-06 03:01:29 +000029
Lang Hamesed96cb72015-04-07 06:12:21 +000030 // List of x86-64 GPRs to save. Note - RBP saved separately below.
31 std::array<const char *, 14> GPRs = {{
32 "rax", "rbx", "rcx", "rdx",
33 "rsi", "rdi", "r8", "r9",
34 "r10", "r11", "r12", "r13",
35 "r14", "r15"
Lang Hamese51ab6e2015-04-06 03:01:29 +000036 }};
37
38 // Address of the executeCompileCallback function.
NAKAMURA Takumicd5a3672015-02-17 12:53:16 +000039 uint64_t CallbackAddr =
Lang Hamese51ab6e2015-04-06 03:01:29 +000040 static_cast<uint64_t>(
41 reinterpret_cast<uintptr_t>(executeCompileCallback));
Lang Hames93de2a12015-01-23 21:25:00 +000042
Lang Hames27547142015-02-17 01:18:38 +000043 std::ostringstream AsmStream;
Lang Hames93de2a12015-01-23 21:25:00 +000044 Triple TT(M.getTargetTriple());
45
Lang Hamese51ab6e2015-04-06 03:01:29 +000046 // Switch to text section.
Lang Hames93de2a12015-01-23 21:25:00 +000047 if (TT.getOS() == Triple::Darwin)
Lang Hames27547142015-02-17 01:18:38 +000048 AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
49 << ".align 4, 0x90\n";
Lang Hames93de2a12015-01-23 21:25:00 +000050 else
Lang Hames27547142015-02-17 01:18:38 +000051 AsmStream << ".text\n"
52 << ".align 16, 0x90\n";
Lang Hames93de2a12015-01-23 21:25:00 +000053
Lang Hamese51ab6e2015-04-06 03:01:29 +000054 // Bake in a pointer to the callback manager immediately before the
55 // start of the resolver function.
Lang Hames27547142015-02-17 01:18:38 +000056 AsmStream << "jit_callback_manager_addr:\n"
Lang Hamese51ab6e2015-04-06 03:01:29 +000057 << " .quad " << &JCBM << "\n";
Lang Hames93de2a12015-01-23 21:25:00 +000058
Lang Hamese51ab6e2015-04-06 03:01:29 +000059 // Start the resolver function.
60 AsmStream << ResolverBlockName << ":\n"
Lang Hames67e6e042015-04-20 18:25:44 +000061 << " pushq %rbp\n"
62 << " movq %rsp, %rbp\n";
Lang Hames93de2a12015-01-23 21:25:00 +000063
Lang Hamese51ab6e2015-04-06 03:01:29 +000064 // Store the GPRs.
65 for (const auto &GPR : GPRs)
Lang Hames67e6e042015-04-20 18:25:44 +000066 AsmStream << " pushq %" << GPR << "\n";
Lang Hamese51ab6e2015-04-06 03:01:29 +000067
68 // Store floating-point state with FXSAVE.
Lang Hamesed96cb72015-04-07 06:12:21 +000069 // Note: We need to keep the stack 16-byte aligned, so if we've emitted an odd
70 // number of 64-bit pushes so far (GPRs.size() plus 1 for RBP) then add
71 // an extra 64 bits of padding to the FXSave area.
72 unsigned Padding = (GPRs.size() + 1) % 2 ? 8 : 0;
73 unsigned FXSaveSize = 512 + Padding;
Lang Hames67e6e042015-04-20 18:25:44 +000074 AsmStream << " subq $" << FXSaveSize << ", %rsp\n"
75 << " fxsave64 (%rsp)\n"
Lang Hamese51ab6e2015-04-06 03:01:29 +000076
77 // Load callback manager address, compute trampoline address, call JIT.
Lang Hames67e6e042015-04-20 18:25:44 +000078 << " lea jit_callback_manager_addr(%rip), %rdi\n"
79 << " movq (%rdi), %rdi\n"
80 << " movq 0x8(%rbp), %rsi\n"
81 << " subq $" << X86_64_TrampolineLength << ", %rsi\n"
82 << " movabsq $" << CallbackAddr << ", %rax\n"
83 << " callq *%rax\n"
Lang Hames93de2a12015-01-23 21:25:00 +000084
Lang Hamese51ab6e2015-04-06 03:01:29 +000085 // Replace the return to the trampoline with the return address of the
86 // compiled function body.
Lang Hames67e6e042015-04-20 18:25:44 +000087 << " movq %rax, 0x8(%rbp)\n"
Lang Hames93de2a12015-01-23 21:25:00 +000088
Lang Hamese51ab6e2015-04-06 03:01:29 +000089 // Restore the floating point state.
Lang Hames67e6e042015-04-20 18:25:44 +000090 << " fxrstor64 (%rsp)\n"
91 << " addq $" << FXSaveSize << ", %rsp\n";
Lang Hamese51ab6e2015-04-06 03:01:29 +000092
93 for (const auto &GPR : make_range(GPRs.rbegin(), GPRs.rend()))
Lang Hames67e6e042015-04-20 18:25:44 +000094 AsmStream << " popq %" << GPR << "\n";
Lang Hamese51ab6e2015-04-06 03:01:29 +000095
96 // Restore original RBP and return to compiled function body.
Lang Hames67e6e042015-04-20 18:25:44 +000097 AsmStream << " popq %rbp\n"
Lang Hamese51ab6e2015-04-06 03:01:29 +000098 << " retq\n";
Lang Hames93de2a12015-01-23 21:25:00 +000099
Lang Hames27547142015-02-17 01:18:38 +0000100 M.appendModuleInlineAsm(AsmStream.str());
Lang Hames93de2a12015-01-23 21:25:00 +0000101}
Lang Hames27547142015-02-17 01:18:38 +0000102
103OrcX86_64::LabelNameFtor
104OrcX86_64::insertCompileCallbackTrampolines(Module &M,
105 TargetAddress ResolverBlockAddr,
106 unsigned NumCalls,
107 unsigned StartIndex) {
108 const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";
109
110 std::ostringstream AsmStream;
111 Triple TT(M.getTargetTriple());
112
113 if (TT.getOS() == Triple::Darwin)
114 AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
115 << ".align 4, 0x90\n";
116 else
117 AsmStream << ".text\n"
118 << ".align 16, 0x90\n";
119
120 AsmStream << ResolverBlockPtrName << ":\n"
121 << " .quad " << ResolverBlockAddr << "\n";
122
123 auto GetLabelName =
124 [=](unsigned I) {
125 std::ostringstream LabelStream;
126 LabelStream << "orc_jcc_" << (StartIndex + I);
127 return LabelStream.str();
128 };
129
130 for (unsigned I = 0; I < NumCalls; ++I)
131 AsmStream << GetLabelName(I) << ":\n"
132 << " callq *" << ResolverBlockPtrName << "(%rip)\n";
133
134 M.appendModuleInlineAsm(AsmStream.str());
135
136 return GetLabelName;
137}
138
Lang Hames98c2ac12015-10-19 17:43:51 +0000139OrcX86_64::IndirectStubsInfo::~IndirectStubsInfo() {
140 sys::Memory::releaseMappedMemory(StubsBlock);
141 sys::Memory::releaseMappedMemory(PtrsBlock);
142}
143
144std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
145 unsigned MinStubs,
146 void *InitialPtrVal) {
147 // Stub format is:
148 //
149 // .section __orc_stubs
150 // stub1:
151 // jmpq *ptr1(%rip)
152 // .byte 0xC4 ; <- Invalid opcode padding.
153 // .byte 0xF1
154 // stub2:
155 // jmpq *ptr2(%rip)
156 //
157 // ...
158 //
159 // .section __orc_ptrs
160 // ptr1:
161 // .quad 0x0
162 // ptr2:
163 // .quad 0x0
164 //
165 // ...
166
167 const unsigned StubSize = IndirectStubsInfo::StubSize;
168
169 // Emit at least MinStubs, rounded up to fill the pages allocated.
170 unsigned PageSize = sys::Process::getPageSize();
171 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
172 unsigned NumStubs = (NumPages * PageSize) / StubSize;
173
174 // Allocate memory for stubs and pointers in one call.
175 std::error_code EC;
176 auto InitialBlock = sys::Memory::allocateMappedMemory(2 * NumPages * PageSize,
177 nullptr,
178 sys::Memory::MF_READ |
179 sys::Memory::MF_WRITE,
180 EC);
181
182 if (EC)
183 return EC;
184
185 // Create separate MemoryBlocks representing the stubs and pointers.
186 sys::MemoryBlock StubsBlock(InitialBlock.base(), NumPages * PageSize);
187 sys::MemoryBlock PtrsBlock(static_cast<char*>(InitialBlock.base()) +
188 NumPages * PageSize,
189 NumPages * PageSize);
190
191 // Populate the stubs page stubs and mark it executable.
192 uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
193 uint64_t PtrOffsetField =
194 static_cast<uint64_t>(NumPages * PageSize - 6) << 16;
195 for (unsigned I = 0; I < NumStubs; ++I)
196 Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
197
198 if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
199 sys::Memory::MF_READ |
200 sys::Memory::MF_EXEC))
201 return EC;
202
203 // Initialize all pointers to point at FailureAddress.
204 void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
205 for (unsigned I = 0; I < NumStubs; ++I)
206 Ptr[I] = InitialPtrVal;
207
208 StubsInfo.NumStubs = NumStubs;
209 StubsInfo.StubsBlock = std::move(StubsBlock);
210 StubsInfo.PtrsBlock = std::move(PtrsBlock);
211
212 return std::error_code();
213}
214
Lang Hamese7380612015-02-21 20:44:36 +0000215} // End namespace orc.
216} // End namespace llvm.