Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 1 | //===-- SparcJITInfo.cpp - Implement the Sparc JIT Interface --------------===// |
| 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 | // |
| 10 | // This file implements the JIT interfaces for the Sparc target. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | #define DEBUG_TYPE "jit" |
| 14 | #include "SparcJITInfo.h" |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 15 | #include "Sparc.h" |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 16 | #include "SparcRelocations.h" |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/SmallVector.h" |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 18 | #include "llvm/CodeGen/JITCodeEmitter.h" |
| 19 | #include "llvm/Support/Memory.h" |
| 20 | |
| 21 | using namespace llvm; |
| 22 | |
| 23 | /// JITCompilerFunction - This contains the address of the JIT function used to |
| 24 | /// compile a function lazily. |
| 25 | static TargetJITInfo::JITCompilerFn JITCompilerFunction; |
| 26 | |
| 27 | extern "C" void SparcCompilationCallback(); |
| 28 | |
| 29 | extern "C" { |
| 30 | #if defined (__sparc__) |
Venkatraman Govindaraju | 902d97b | 2014-01-31 01:53:08 +0000 | [diff] [blame] | 31 | |
| 32 | #if defined(__arch64__) |
| 33 | #define FRAME_PTR(X) #X "+2047" |
| 34 | #else |
| 35 | #define FRAME_PTR(X) #X |
| 36 | #endif |
| 37 | |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 38 | asm( |
| 39 | ".text\n" |
| 40 | "\t.align 4\n" |
| 41 | "\t.global SparcCompilationCallback\n" |
| 42 | "\t.type SparcCompilationCallback, #function\n" |
| 43 | "SparcCompilationCallback:\n" |
Venkatraman Govindaraju | 902d97b | 2014-01-31 01:53:08 +0000 | [diff] [blame] | 44 | // Save current register window and create stack. |
| 45 | // 128 (save area) + 6*8 (for arguments) + 16*8 (for float regfile) = 304 |
| 46 | "\tsave %sp, -304, %sp\n" |
| 47 | // save float regfile to the stack. |
| 48 | "\tstd %f0, [" FRAME_PTR(%fp) "-0]\n" |
| 49 | "\tstd %f2, [" FRAME_PTR(%fp) "-8]\n" |
| 50 | "\tstd %f4, [" FRAME_PTR(%fp) "-16]\n" |
| 51 | "\tstd %f6, [" FRAME_PTR(%fp) "-24]\n" |
| 52 | "\tstd %f8, [" FRAME_PTR(%fp) "-32]\n" |
| 53 | "\tstd %f10, [" FRAME_PTR(%fp) "-40]\n" |
| 54 | "\tstd %f12, [" FRAME_PTR(%fp) "-48]\n" |
| 55 | "\tstd %f14, [" FRAME_PTR(%fp) "-56]\n" |
| 56 | "\tstd %f16, [" FRAME_PTR(%fp) "-64]\n" |
| 57 | "\tstd %f18, [" FRAME_PTR(%fp) "-72]\n" |
| 58 | "\tstd %f20, [" FRAME_PTR(%fp) "-80]\n" |
| 59 | "\tstd %f22, [" FRAME_PTR(%fp) "-88]\n" |
| 60 | "\tstd %f24, [" FRAME_PTR(%fp) "-96]\n" |
| 61 | "\tstd %f26, [" FRAME_PTR(%fp) "-104]\n" |
| 62 | "\tstd %f28, [" FRAME_PTR(%fp) "-112]\n" |
| 63 | "\tstd %f30, [" FRAME_PTR(%fp) "-120]\n" |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 64 | // stubaddr is in %g1. |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 65 | "\tcall SparcCompilationCallbackC\n" |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 66 | "\t mov %g1, %o0\n" |
Venkatraman Govindaraju | 902d97b | 2014-01-31 01:53:08 +0000 | [diff] [blame] | 67 | // restore float regfile from the stack. |
| 68 | "\tldd [" FRAME_PTR(%fp) "-0], %f0\n" |
| 69 | "\tldd [" FRAME_PTR(%fp) "-8], %f2\n" |
| 70 | "\tldd [" FRAME_PTR(%fp) "-16], %f4\n" |
| 71 | "\tldd [" FRAME_PTR(%fp) "-24], %f6\n" |
| 72 | "\tldd [" FRAME_PTR(%fp) "-32], %f8\n" |
| 73 | "\tldd [" FRAME_PTR(%fp) "-40], %f10\n" |
| 74 | "\tldd [" FRAME_PTR(%fp) "-48], %f12\n" |
| 75 | "\tldd [" FRAME_PTR(%fp) "-56], %f14\n" |
| 76 | "\tldd [" FRAME_PTR(%fp) "-64], %f16\n" |
| 77 | "\tldd [" FRAME_PTR(%fp) "-72], %f18\n" |
| 78 | "\tldd [" FRAME_PTR(%fp) "-80], %f20\n" |
| 79 | "\tldd [" FRAME_PTR(%fp) "-88], %f22\n" |
| 80 | "\tldd [" FRAME_PTR(%fp) "-96], %f24\n" |
| 81 | "\tldd [" FRAME_PTR(%fp) "-104], %f26\n" |
| 82 | "\tldd [" FRAME_PTR(%fp) "-112], %f28\n" |
| 83 | "\tldd [" FRAME_PTR(%fp) "-120], %f30\n" |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 84 | // restore original register window and |
| 85 | // copy %o0 to %g1 |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 86 | "\trestore %o0, 0, %g1\n" |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 87 | // call the new stub |
| 88 | "\tjmp %g1\n" |
| 89 | "\t nop\n" |
| 90 | "\t.size SparcCompilationCallback, .-SparcCompilationCallback" |
| 91 | ); |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 92 | #else |
| 93 | void SparcCompilationCallback() { |
| 94 | llvm_unreachable( |
| 95 | "Cannot call SparcCompilationCallback() on a non-sparc arch!"); |
| 96 | } |
| 97 | #endif |
| 98 | } |
| 99 | |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 100 | |
| 101 | #define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF)) |
| 102 | #define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \ |
| 103 | | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) |
| 104 | #define NOP_INST SETHI_INST(0, 0) |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 105 | #define OR_INST_I(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ |
| 106 | | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) |
| 107 | #define OR_INST_R(rs1, rs2, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \ |
| 108 | | ((rs1) << 14) | (0 << 13) | ((rs2) & 0x1F)) |
| 109 | #define RDPC_INST(rd) (0x80000000 | ((rd) << 25) | (0x28 << 19) \ |
| 110 | | (5 << 14)) |
| 111 | #define LDX_INST(rs1, imm, rd) (0xC0000000 | ((rd) << 25) | (0x0B << 19) \ |
| 112 | | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) |
| 113 | #define SLLX_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x25 << 19) \ |
| 114 | | ((rs1) << 14) | (3 << 12) | ((imm) & 0x3F)) |
| 115 | #define SUB_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x04 << 19) \ |
| 116 | | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) |
| 117 | #define XOR_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x03 << 19) \ |
| 118 | | ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF)) |
| 119 | #define BA_INST(tgt) (0x10800000 | ((tgt) & 0x3FFFFF)) |
| 120 | |
| 121 | // Emit instructions to jump to Addr and store the starting address of |
| 122 | // the instructions emitted in the scratch register. |
| 123 | static void emitInstrForIndirectJump(intptr_t Addr, |
| 124 | unsigned scratch, |
| 125 | SmallVectorImpl<uint32_t> &Insts) { |
| 126 | |
| 127 | if (isInt<13>(Addr)) { |
| 128 | // Emit: jmpl %g0+Addr, <scratch> |
| 129 | // nop |
| 130 | Insts.push_back(JMP_INST(0, LO10(Addr), scratch)); |
| 131 | Insts.push_back(NOP_INST); |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | if (isUInt<32>(Addr)) { |
| 136 | // Emit: sethi %hi(Addr), scratch |
| 137 | // jmpl scratch+%lo(Addr), scratch |
| 138 | // sub scratch, 4, scratch |
| 139 | Insts.push_back(SETHI_INST(HI22(Addr), scratch)); |
| 140 | Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); |
| 141 | Insts.push_back(SUB_INST(scratch, 4, scratch)); |
| 142 | return; |
| 143 | } |
| 144 | |
| 145 | if (Addr < 0 && isInt<33>(Addr)) { |
| 146 | // Emit: sethi %hix(Addr), scratch) |
| 147 | // xor scratch, %lox(Addr), scratch |
| 148 | // jmpl scratch+0, scratch |
| 149 | // sub scratch, 8, scratch |
| 150 | Insts.push_back(SETHI_INST(HIX22(Addr), scratch)); |
| 151 | Insts.push_back(XOR_INST(scratch, LOX10(Addr), scratch)); |
| 152 | Insts.push_back(JMP_INST(scratch, 0, scratch)); |
| 153 | Insts.push_back(SUB_INST(scratch, 8, scratch)); |
| 154 | return; |
| 155 | } |
| 156 | |
| 157 | // Emit: rd %pc, scratch |
| 158 | // ldx [scratch+16], scratch |
| 159 | // jmpl scratch+0, scratch |
| 160 | // sub scratch, 8, scratch |
| 161 | // <Addr: 8 byte> |
| 162 | Insts.push_back(RDPC_INST(scratch)); |
| 163 | Insts.push_back(LDX_INST(scratch, 16, scratch)); |
| 164 | Insts.push_back(JMP_INST(scratch, 0, scratch)); |
| 165 | Insts.push_back(SUB_INST(scratch, 8, scratch)); |
| 166 | Insts.push_back((uint32_t)(((int64_t)Addr) >> 32) & 0xffffffff); |
| 167 | Insts.push_back((uint32_t)(Addr & 0xffffffff)); |
| 168 | |
| 169 | // Instruction sequence without rdpc instruction |
| 170 | // 7 instruction and 2 scratch register |
| 171 | // Emit: sethi %hh(Addr), scratch |
| 172 | // or scratch, %hm(Addr), scratch |
| 173 | // sllx scratch, 32, scratch |
| 174 | // sethi %hi(Addr), scratch2 |
| 175 | // or scratch, scratch2, scratch |
| 176 | // jmpl scratch+%lo(Addr), scratch |
| 177 | // sub scratch, 20, scratch |
| 178 | // Insts.push_back(SETHI_INST(HH22(Addr), scratch)); |
| 179 | // Insts.push_back(OR_INST_I(scratch, HM10(Addr), scratch)); |
| 180 | // Insts.push_back(SLLX_INST(scratch, 32, scratch)); |
| 181 | // Insts.push_back(SETHI_INST(HI22(Addr), scratch2)); |
| 182 | // Insts.push_back(OR_INST_R(scratch, scratch2, scratch)); |
| 183 | // Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch)); |
| 184 | // Insts.push_back(SUB_INST(scratch, 20, scratch)); |
| 185 | } |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 186 | |
| 187 | extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) { |
| 188 | // Get the address of the compiled code for this function. |
| 189 | intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr); |
| 190 | |
| 191 | // Rewrite the function stub so that we don't end up here every time we |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 192 | // execute the call. We're replacing the stub instructions with code |
| 193 | // that jumps to the compiled function: |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 194 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 195 | SmallVector<uint32_t, 8> Insts; |
| 196 | intptr_t diff = (NewVal - StubAddr) >> 2; |
| 197 | if (isInt<22>(diff)) { |
| 198 | // Use branch instruction to jump |
| 199 | Insts.push_back(BA_INST(diff)); |
| 200 | Insts.push_back(NOP_INST); |
| 201 | } else { |
| 202 | // Otherwise, use indirect jump to the compiled function |
| 203 | emitInstrForIndirectJump(NewVal, 1, Insts); |
| 204 | } |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 205 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 206 | for (unsigned i = 0, e = Insts.size(); i != e; ++i) |
| 207 | *(uint32_t *)(StubAddr + i*4) = Insts[i]; |
| 208 | |
| 209 | sys::Memory::InvalidateInstructionCache((void*) StubAddr, Insts.size() * 4); |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 210 | return (void*)StubAddr; |
| 211 | } |
| 212 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 213 | |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 214 | void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) { |
| 215 | assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction"); |
| 216 | } |
| 217 | |
| 218 | |
| 219 | TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() { |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 220 | // The stub contains maximum of 4 4-byte instructions and 8 bytes for address, |
| 221 | // aligned at 32 bytes. |
| 222 | // See emitFunctionStub and emitInstrForIndirectJump for details. |
| 223 | StubLayout Result = { 4*4 + 8, 32 }; |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 224 | return Result; |
| 225 | } |
| 226 | |
| 227 | void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn, |
| 228 | JITCodeEmitter &JCE) |
| 229 | { |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 230 | JCE.emitAlignment(32); |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 231 | void *Addr = (void*) (JCE.getCurrentPCValue()); |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 232 | |
| 233 | intptr_t CurrentAddr = (intptr_t)Addr; |
| 234 | intptr_t EmittedAddr; |
| 235 | SmallVector<uint32_t, 8> Insts; |
| 236 | if (Fn != (void*)(intptr_t)SparcCompilationCallback) { |
| 237 | EmittedAddr = (intptr_t)Fn; |
| 238 | intptr_t diff = (EmittedAddr - CurrentAddr) >> 2; |
| 239 | if (isInt<22>(diff)) { |
| 240 | Insts.push_back(BA_INST(diff)); |
| 241 | Insts.push_back(NOP_INST); |
| 242 | } |
| 243 | } else { |
| 244 | EmittedAddr = (intptr_t)SparcCompilationCallback; |
| 245 | } |
| 246 | |
| 247 | if (Insts.size() == 0) |
| 248 | emitInstrForIndirectJump(EmittedAddr, 1, Insts); |
| 249 | |
| 250 | |
| 251 | if (!sys::Memory::setRangeWritable(Addr, 4 * Insts.size())) |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 252 | llvm_unreachable("ERROR: Unable to mark stub writable."); |
| 253 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 254 | for (unsigned i = 0, e = Insts.size(); i != e; ++i) |
| 255 | JCE.emitWordBE(Insts[i]); |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 256 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 257 | sys::Memory::InvalidateInstructionCache(Addr, 4 * Insts.size()); |
| 258 | if (!sys::Memory::setRangeExecutable(Addr, 4 * Insts.size())) |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 259 | llvm_unreachable("ERROR: Unable to mark stub executable."); |
| 260 | |
| 261 | return Addr; |
| 262 | } |
| 263 | |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 264 | |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 265 | TargetJITInfo::LazyResolverFn |
| 266 | SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) { |
| 267 | JITCompilerFunction = F; |
| 268 | return SparcCompilationCallback; |
| 269 | } |
| 270 | |
| 271 | /// relocate - Before the JIT can run a block of code that has been emitted, |
| 272 | /// it must rewrite the code to contain the actual addresses of any |
| 273 | /// referenced global symbols. |
| 274 | void SparcJITInfo::relocate(void *Function, MachineRelocation *MR, |
| 275 | unsigned NumRelocs, unsigned char *GOTBase) { |
| 276 | for (unsigned i = 0; i != NumRelocs; ++i, ++MR) { |
| 277 | void *RelocPos = (char*) Function + MR->getMachineCodeOffset(); |
| 278 | intptr_t ResultPtr = (intptr_t) MR->getResultPointer(); |
| 279 | |
| 280 | switch ((SP::RelocationType) MR->getRelocationType()) { |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 281 | case SP::reloc_sparc_hi: |
| 282 | ResultPtr = (ResultPtr >> 10) & 0x3fffff; |
| 283 | break; |
| 284 | |
| 285 | case SP::reloc_sparc_lo: |
| 286 | ResultPtr = (ResultPtr & 0x3ff); |
| 287 | break; |
| 288 | |
| 289 | case SP::reloc_sparc_pc30: |
| 290 | ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffffff; |
| 291 | break; |
| 292 | |
| 293 | case SP::reloc_sparc_pc22: |
| 294 | ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x3fffff; |
| 295 | break; |
| 296 | |
| 297 | case SP::reloc_sparc_pc19: |
| 298 | ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff; |
| 299 | break; |
Venkatraman Govindaraju | dc3bcc1 | 2014-01-24 07:10:19 +0000 | [diff] [blame] | 300 | |
| 301 | case SP::reloc_sparc_h44: |
| 302 | ResultPtr = (ResultPtr >> 22) & 0x3fffff; |
| 303 | break; |
| 304 | |
| 305 | case SP::reloc_sparc_m44: |
| 306 | ResultPtr = (ResultPtr >> 12) & 0x3ff; |
| 307 | break; |
| 308 | |
| 309 | case SP::reloc_sparc_l44: |
| 310 | ResultPtr = (ResultPtr & 0xfff); |
| 311 | break; |
| 312 | |
| 313 | case SP::reloc_sparc_hh: |
| 314 | ResultPtr = (((int64_t)ResultPtr) >> 42) & 0x3fffff; |
| 315 | break; |
| 316 | |
| 317 | case SP::reloc_sparc_hm: |
| 318 | ResultPtr = (((int64_t)ResultPtr) >> 32) & 0x3ff; |
| 319 | break; |
| 320 | |
Venkatraman Govindaraju | 2ea4c28 | 2013-10-08 07:15:22 +0000 | [diff] [blame] | 321 | } |
| 322 | *((unsigned*) RelocPos) |= (unsigned) ResultPtr; |
| 323 | } |
| 324 | } |