blob: c03b935baeb70e4c44f71594d3ba5b2eec5a5b09 [file] [log] [blame]
Lang Hames4df7ba72015-10-26 06:40:28 +00001//===------- OrcTargetSupport.cpp - Target support utilities for Orc ------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Lang Hames93de2a12015-01-23 21:25:00 +000010#include "llvm/ADT/Triple.h"
Lang Hames27547142015-02-17 01:18:38 +000011#include "llvm/ExecutionEngine/Orc/OrcTargetSupport.h"
Lang Hames98c2ac12015-10-19 17:43:51 +000012#include "llvm/Support/Process.h"
Lang Hames93de2a12015-01-23 21:25:00 +000013#include <array>
14
Rafael Espindola2f344632015-11-03 16:25:20 +000015using namespace llvm::orc;
16
17namespace {
18
19uint64_t executeCompileCallback(JITCompileCallbackManagerBase *JCBM,
20 TargetAddress CallbackID) {
21 return JCBM->executeCompileCallback(CallbackID);
22}
23
24}
25
Lang Hames93de2a12015-01-23 21:25:00 +000026namespace llvm {
Lang Hamese7380612015-02-21 20:44:36 +000027namespace orc {
Lang Hames93de2a12015-01-23 21:25:00 +000028
Rafael Espindola2f344632015-11-03 16:25:20 +000029const char* OrcX86_64::ResolverBlockName = "orc_resolver_block";
Lang Hames93de2a12015-01-23 21:25:00 +000030
Rafael Espindola2f344632015-11-03 16:25:20 +000031void OrcX86_64::insertResolverBlock(
32 Module &M, JITCompileCallbackManagerBase &JCBM) {
Lang Hamese51ab6e2015-04-06 03:01:29 +000033
Rafael Espindola2f344632015-11-03 16:25:20 +000034 // Trampoline code-sequence length, used to get trampoline address from return
35 // address.
36 const unsigned X86_64_TrampolineLength = 6;
Lang Hamese51ab6e2015-04-06 03:01:29 +000037
Rafael Espindola2f344632015-11-03 16:25:20 +000038 // List of x86-64 GPRs to save. Note - RBP saved separately below.
39 std::array<const char *, 14> GPRs = {{
40 "rax", "rbx", "rcx", "rdx",
41 "rsi", "rdi", "r8", "r9",
42 "r10", "r11", "r12", "r13",
43 "r14", "r15"
44 }};
Lang Hamese51ab6e2015-04-06 03:01:29 +000045
Rafael Espindola2f344632015-11-03 16:25:20 +000046 // Address of the executeCompileCallback function.
47 uint64_t CallbackAddr =
48 static_cast<uint64_t>(
49 reinterpret_cast<uintptr_t>(executeCompileCallback));
Lang Hames27547142015-02-17 01:18:38 +000050
Rafael Espindola2f344632015-11-03 16:25:20 +000051 std::ostringstream AsmStream;
52 Triple TT(M.getTargetTriple());
53
54 // Switch to text section.
55 if (TT.getOS() == Triple::Darwin)
56 AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
57 << ".align 4, 0x90\n";
58 else
59 AsmStream << ".text\n"
60 << ".align 16, 0x90\n";
61
62 // Bake in a pointer to the callback manager immediately before the
63 // start of the resolver function.
64 AsmStream << "jit_callback_manager_addr:\n"
65 << " .quad " << &JCBM << "\n";
66
67 // Start the resolver function.
68 AsmStream << ResolverBlockName << ":\n"
69 << " pushq %rbp\n"
70 << " movq %rsp, %rbp\n";
71
72 // Store the GPRs.
73 for (const auto &GPR : GPRs)
74 AsmStream << " pushq %" << GPR << "\n";
75
76 // Store floating-point state with FXSAVE.
77 // Note: We need to keep the stack 16-byte aligned, so if we've emitted an odd
78 // number of 64-bit pushes so far (GPRs.size() plus 1 for RBP) then add
79 // an extra 64 bits of padding to the FXSave area.
80 unsigned Padding = (GPRs.size() + 1) % 2 ? 8 : 0;
81 unsigned FXSaveSize = 512 + Padding;
82 AsmStream << " subq $" << FXSaveSize << ", %rsp\n"
83 << " fxsave64 (%rsp)\n"
84
85 // Load callback manager address, compute trampoline address, call JIT.
86 << " lea jit_callback_manager_addr(%rip), %rdi\n"
87 << " movq (%rdi), %rdi\n"
88 << " movq 0x8(%rbp), %rsi\n"
89 << " subq $" << X86_64_TrampolineLength << ", %rsi\n"
90 << " movabsq $" << CallbackAddr << ", %rax\n"
91 << " callq *%rax\n"
92
93 // Replace the return to the trampoline with the return address of the
94 // compiled function body.
95 << " movq %rax, 0x8(%rbp)\n"
96
97 // Restore the floating point state.
98 << " fxrstor64 (%rsp)\n"
99 << " addq $" << FXSaveSize << ", %rsp\n";
100
101 for (const auto &GPR : make_range(GPRs.rbegin(), GPRs.rend()))
102 AsmStream << " popq %" << GPR << "\n";
103
104 // Restore original RBP and return to compiled function body.
105 AsmStream << " popq %rbp\n"
106 << " retq\n";
107
108 M.appendModuleInlineAsm(AsmStream.str());
Lang Hamesa4a227f2015-11-03 16:10:18 +0000109}
Lang Hames27547142015-02-17 01:18:38 +0000110
Rafael Espindola2f344632015-11-03 16:25:20 +0000111OrcX86_64::LabelNameFtor
112OrcX86_64::insertCompileCallbackTrampolines(Module &M,
113 TargetAddress ResolverBlockAddr,
114 unsigned NumCalls,
115 unsigned StartIndex) {
116 const char *ResolverBlockPtrName = "Lorc_resolve_block_addr";
Lang Hames27547142015-02-17 01:18:38 +0000117
Rafael Espindola2f344632015-11-03 16:25:20 +0000118 std::ostringstream AsmStream;
119 Triple TT(M.getTargetTriple());
Lang Hamesa4a227f2015-11-03 16:10:18 +0000120
Rafael Espindola2f344632015-11-03 16:25:20 +0000121 if (TT.getOS() == Triple::Darwin)
122 AsmStream << ".section __TEXT,__text,regular,pure_instructions\n"
123 << ".align 4, 0x90\n";
124 else
125 AsmStream << ".text\n"
126 << ".align 16, 0x90\n";
Lang Hamesa4a227f2015-11-03 16:10:18 +0000127
Rafael Espindola2f344632015-11-03 16:25:20 +0000128 AsmStream << ResolverBlockPtrName << ":\n"
129 << " .quad " << ResolverBlockAddr << "\n";
Lang Hamesa4a227f2015-11-03 16:10:18 +0000130
Rafael Espindola2f344632015-11-03 16:25:20 +0000131 auto GetLabelName =
132 [=](unsigned I) {
133 std::ostringstream LabelStream;
134 LabelStream << "orc_jcc_" << (StartIndex + I);
135 return LabelStream.str();
136 };
137
138 for (unsigned I = 0; I < NumCalls; ++I)
139 AsmStream << GetLabelName(I) << ":\n"
140 << " callq *" << ResolverBlockPtrName << "(%rip)\n";
141
142 M.appendModuleInlineAsm(AsmStream.str());
143
144 return GetLabelName;
Lang Hames27547142015-02-17 01:18:38 +0000145}
146
Lang Hames98c2ac12015-10-19 17:43:51 +0000147std::error_code OrcX86_64::emitIndirectStubsBlock(IndirectStubsInfo &StubsInfo,
148 unsigned MinStubs,
149 void *InitialPtrVal) {
150 // Stub format is:
151 //
152 // .section __orc_stubs
153 // stub1:
154 // jmpq *ptr1(%rip)
155 // .byte 0xC4 ; <- Invalid opcode padding.
156 // .byte 0xF1
157 // stub2:
158 // jmpq *ptr2(%rip)
159 //
160 // ...
161 //
162 // .section __orc_ptrs
163 // ptr1:
164 // .quad 0x0
165 // ptr2:
166 // .quad 0x0
167 //
168 // ...
169
170 const unsigned StubSize = IndirectStubsInfo::StubSize;
171
172 // Emit at least MinStubs, rounded up to fill the pages allocated.
173 unsigned PageSize = sys::Process::getPageSize();
174 unsigned NumPages = ((MinStubs * StubSize) + (PageSize - 1)) / PageSize;
175 unsigned NumStubs = (NumPages * PageSize) / StubSize;
176
177 // Allocate memory for stubs and pointers in one call.
178 std::error_code EC;
Lang Hames5796eb22015-10-31 00:55:32 +0000179 auto StubsMem =
180 sys::OwningMemoryBlock(
181 sys::Memory::allocateMappedMemory(2 * NumPages * PageSize, nullptr,
182 sys::Memory::MF_READ |
183 sys::Memory::MF_WRITE,
184 EC));
Lang Hames98c2ac12015-10-19 17:43:51 +0000185
186 if (EC)
187 return EC;
188
189 // Create separate MemoryBlocks representing the stubs and pointers.
Lang Hames5796eb22015-10-31 00:55:32 +0000190 sys::MemoryBlock StubsBlock(StubsMem.base(), NumPages * PageSize);
191 sys::MemoryBlock PtrsBlock(static_cast<char*>(StubsMem.base()) +
192 NumPages * PageSize,
Lang Hames98c2ac12015-10-19 17:43:51 +0000193 NumPages * PageSize);
194
195 // Populate the stubs page stubs and mark it executable.
196 uint64_t *Stub = reinterpret_cast<uint64_t*>(StubsBlock.base());
197 uint64_t PtrOffsetField =
198 static_cast<uint64_t>(NumPages * PageSize - 6) << 16;
199 for (unsigned I = 0; I < NumStubs; ++I)
200 Stub[I] = 0xF1C40000000025ff | PtrOffsetField;
201
202 if (auto EC = sys::Memory::protectMappedMemory(StubsBlock,
203 sys::Memory::MF_READ |
204 sys::Memory::MF_EXEC))
205 return EC;
206
207 // Initialize all pointers to point at FailureAddress.
208 void **Ptr = reinterpret_cast<void**>(PtrsBlock.base());
209 for (unsigned I = 0; I < NumStubs; ++I)
210 Ptr[I] = InitialPtrVal;
211
212 StubsInfo.NumStubs = NumStubs;
Lang Hames5796eb22015-10-31 00:55:32 +0000213 StubsInfo.StubsMem = std::move(StubsMem);
Lang Hames98c2ac12015-10-19 17:43:51 +0000214
215 return std::error_code();
216}
217
Lang Hamese7380612015-02-21 20:44:36 +0000218} // End namespace orc.
219} // End namespace llvm.