blob: 15b2aa1bddf4af7b2c674e56fd0fd4423ab90bc9 [file] [log] [blame]
Chris Lattner9b3d9892004-11-23 06:02:06 +00001//===-- PPC32JITInfo.cpp - Implement the JIT interfaces for the PowerPC ---===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by the LLVM research group and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the JIT interfaces for the 32-bit PowerPC target.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "jit"
15#include "PPC32JITInfo.h"
16#include "PPC32Relocations.h"
17#include "llvm/CodeGen/MachineCodeEmitter.h"
18#include "llvm/Config/alloca.h"
Chris Lattner5efb75d2004-11-24 22:30:08 +000019#include <map>
Chris Lattner9b3d9892004-11-23 06:02:06 +000020using namespace llvm;
21
22static TargetJITInfo::JITCompilerFn JITCompilerFunction;
23
24#define BUILD_ADDIS(RD,RS,IMM16) \
25 ((15 << 26) | ((RD) << 21) | ((RS) << 16) | ((IMM16) & 65535))
26#define BUILD_ORI(RD,RS,UIMM16) \
27 ((24 << 26) | ((RS) << 21) | ((RD) << 16) | ((UIMM16) & 65535))
28#define BUILD_MTSPR(RS,SPR) \
29 ((31 << 26) | ((RS) << 21) | ((SPR) << 16) | (467 << 1))
30#define BUILD_BCCTRx(BO,BI,LINK) \
31 ((19 << 26) | ((BO) << 21) | ((BI) << 16) | (528 << 1) | ((LINK) & 1))
32
33// Pseudo-ops
34#define BUILD_LIS(RD,IMM16) BUILD_ADDIS(RD,0,IMM16)
35#define BUILD_MTCTR(RS) BUILD_MTSPR(RS,9)
36#define BUILD_BCTR(LINK) BUILD_BCCTRx(20,0,LINK)
37
Chris Lattner9b3d9892004-11-23 06:02:06 +000038
Chris Lattner7c83dc22004-11-23 06:27:02 +000039static void EmitBranchToAt(void *At, void *To, bool isCall) {
Chris Lattner9b3d9892004-11-23 06:02:06 +000040 intptr_t Addr = (intptr_t)To;
41
42 // FIXME: should special case the short branch case.
43 unsigned *AtI = (unsigned*)At;
44
45 AtI[0] = BUILD_LIS(12, Addr >> 16); // lis r12, hi16(address)
46 AtI[1] = BUILD_ORI(12, 12, Addr); // ori r12, r12, low16(address)
47 AtI[2] = BUILD_MTCTR(12); // mtctr r12
Chris Lattner7c83dc22004-11-23 06:27:02 +000048 AtI[3] = BUILD_BCTR(isCall); // bctr/bctrl
Chris Lattner9b3d9892004-11-23 06:02:06 +000049}
50
Chris Lattner73278082004-11-24 21:01:46 +000051extern "C" void PPC32CompilationCallback();
52
Nate Begemanca6d0f52004-11-23 21:34:18 +000053#if defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)
Chris Lattner73278082004-11-24 21:01:46 +000054// CompilationCallback stub - We can't use a C function with inline assembly in
55// it, because we the prolog/epilog inserted by GCC won't work for us. Instead,
56// write our own wrapper, which does things our way, so we have complete control
57// over register saving and restoring.
58asm(
59 ".text\n"
60 ".align 2\n"
61 ".globl _PPC32CompilationCallback\n"
62"_PPC32CompilationCallback:\n"
63 // Make space for 29 ints r[3-31] and 14 doubles f[0-13]
64 "stwu r1, -272(r1)\n"
65 "mflr r11\n"
66 "stw r11, 280(r1)\n" // Set up a proper stack frame
67 "stmw r3, 156(r1)\n" // Save all of the integer registers
68 // Save all call-clobbered FP regs.
69 "stfd f1, 44(r1)\n" "stfd f2, 52(r1)\n" "stfd f3, 60(r1)\n"
70 "stfd f4, 68(r1)\n" "stfd f5, 76(r1)\n" "stfd f6, 84(r1)\n"
71 "stfd f7, 92(r1)\n" "stfd f8, 100(r1)\n" "stfd f9, 108(r1)\n"
72 "stfd f10, 116(r1)\n" "stfd f11, 124(r1)\n" "stfd f12, 132(r1)\n"
73 "stfd f13, 140(r1)\n"
74
75 // Now that everything is saved, go to the C compilation callback function,
76 // passing the address of the intregs and fpregs.
77 "addi r3, r1, 156\n" // &IntRegs[0]
78 "addi r4, r1, 44\n" // &FPRegs[0]
79 "bl _PPC32CompilationCallbackC\n"
80 );
Nate Begemanca6d0f52004-11-23 21:34:18 +000081#endif
82
Chris Lattner73278082004-11-24 21:01:46 +000083extern "C" void PPC32CompilationCallbackC(unsigned *IntRegs, double *FPRegs) {
84 unsigned *CameFromStub = (unsigned*)__builtin_return_address(0+1);
85 unsigned *CameFromOrig = (unsigned*)__builtin_return_address(1+1);
Chris Lattnerd9d06b32004-11-23 18:49:46 +000086 unsigned *CCStackPtr = (unsigned*)__builtin_frame_address(0);
87//unsigned *StubStackPtr = (unsigned*)__builtin_frame_address(1);
Chris Lattner73278082004-11-24 21:01:46 +000088 unsigned *OrigStackPtr = (unsigned*)__builtin_frame_address(2+1);
Chris Lattnere61198b2004-11-23 06:55:05 +000089
Chris Lattnerd9d06b32004-11-23 18:49:46 +000090 // Adjust pointer to the branch, not the return address.
91 --CameFromStub;
Chris Lattnere61198b2004-11-23 06:55:05 +000092
93 void *Target = JITCompilerFunction(CameFromStub);
94
95 // Check to see if CameFromOrig[-1] is a 'bl' instruction, and if we can
96 // rewrite it to branch directly to the destination. If so, rewrite it so it
97 // does not need to go through the stub anymore.
Chris Lattnerd9d06b32004-11-23 18:49:46 +000098 unsigned CameFromOrigInst = CameFromOrig[-1];
Chris Lattnere61198b2004-11-23 06:55:05 +000099 if ((CameFromOrigInst >> 26) == 18) { // Direct call.
Chris Lattner892afa92004-11-24 18:00:02 +0000100 intptr_t Offset = ((intptr_t)Target-(intptr_t)CameFromOrig+4) >> 2;
Chris Lattnere61198b2004-11-23 06:55:05 +0000101 if (Offset >= -(1 << 23) && Offset < (1 << 23)) { // In range?
Chris Lattner892afa92004-11-24 18:00:02 +0000102 // Clear the original target out.
Chris Lattnere61198b2004-11-23 06:55:05 +0000103 CameFromOrigInst &= (63 << 26) | 3;
Chris Lattner892afa92004-11-24 18:00:02 +0000104 // Fill in the new target.
105 CameFromOrigInst |= (Offset & ((1 << 24)-1)) << 2;
106 // Replace the call.
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000107 CameFromOrig[-1] = CameFromOrigInst;
Chris Lattnere61198b2004-11-23 06:55:05 +0000108 }
109 }
110
111 // Locate the start of the stub. If this is a short call, adjust backwards
112 // the short amount, otherwise the full amount.
113 bool isShortStub = (*CameFromStub >> 26) == 18;
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000114 CameFromStub -= isShortStub ? 2 : 6;
Chris Lattnere61198b2004-11-23 06:55:05 +0000115
116 // Rewrite the stub with an unconditional branch to the target, for any users
117 // who took the address of the stub.
118 EmitBranchToAt(CameFromStub, Target, false);
119
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000120 // Change the SP so that we pop two stack frames off when we return.
121 *CCStackPtr = (intptr_t)OrigStackPtr;
122
123 // Put the address of the stub and the LR value that originally came into the
124 // stub in a place that is easy to get on the stack after we restore all regs.
Chris Lattnerfb887e02004-11-24 17:42:55 +0000125 CCStackPtr[2] = (intptr_t)Target;
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000126 CCStackPtr[1] = (intptr_t)CameFromOrig;
Chris Lattnere61198b2004-11-23 06:55:05 +0000127
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000128 // Note, this is not a standard epilog!
129#if defined(__POWERPC__) || defined (__ppc__) || defined(_POWER)
Chris Lattnerfb887e02004-11-24 17:42:55 +0000130 register unsigned *IRR asm ("r2") = IntRegs;
131 register double *FRR asm ("r3") = FPRegs;
Nate Begemanca6d0f52004-11-23 21:34:18 +0000132 __asm__ __volatile__ (
133 "lfd f1, 0(%0)\n" "lfd f2, 8(%0)\n" "lfd f3, 16(%0)\n"
134 "lfd f4, 24(%0)\n" "lfd f5, 32(%0)\n" "lfd f6, 40(%0)\n"
135 "lfd f7, 48(%0)\n" "lfd f8, 56(%0)\n" "lfd f9, 64(%0)\n"
136 "lfd f10, 72(%0)\n" "lfd f11, 80(%0)\n" "lfd f12, 88(%0)\n"
Chris Lattnerfb887e02004-11-24 17:42:55 +0000137 "lfd f13, 96(%0)\n"
138 "lmw r3, 0(%1)\n" // Load all integer regs
Nate Begemanca6d0f52004-11-23 21:34:18 +0000139 "lwz r0,4(r1)\n" // Get CameFromOrig (LR into stub)
140 "mtlr r0\n" // Put it in the LR register
Chris Lattnerfb887e02004-11-24 17:42:55 +0000141 "lwz r0,8(r1)\n" // Get target function pointer
Nate Begemanca6d0f52004-11-23 21:34:18 +0000142 "mtctr r0\n" // Put it into the CTR register
143 "lwz r1,0(r1)\n" // Pop two frames off
144 "bctr\n" :: // Return to stub!
Chris Lattnerfb887e02004-11-24 17:42:55 +0000145 "b" (FRR), "b" (IRR));
Chris Lattnerd9d06b32004-11-23 18:49:46 +0000146#endif
Chris Lattnere61198b2004-11-23 06:55:05 +0000147}
148
149
150
151TargetJITInfo::LazyResolverFn
152PPC32JITInfo::getLazyResolverFunction(JITCompilerFn Fn) {
153 JITCompilerFunction = Fn;
Chris Lattner73278082004-11-24 21:01:46 +0000154 return PPC32CompilationCallback;
Chris Lattnere61198b2004-11-23 06:55:05 +0000155}
156
Chris Lattner9b3d9892004-11-23 06:02:06 +0000157void *PPC32JITInfo::emitFunctionStub(void *Fn, MachineCodeEmitter &MCE) {
158 // If this is just a call to an external function, emit a branch instead of a
159 // call. The code is the same except for one bit of the last instruction.
Chris Lattner73278082004-11-24 21:01:46 +0000160 if (Fn != PPC32CompilationCallback) {
Chris Lattner9b3d9892004-11-23 06:02:06 +0000161 MCE.startFunctionStub(4*4);
162 void *Addr = (void*)(intptr_t)MCE.getCurrentPCValue();
163 MCE.emitWord(0);
164 MCE.emitWord(0);
165 MCE.emitWord(0);
166 MCE.emitWord(0);
Chris Lattner7c83dc22004-11-23 06:27:02 +0000167 EmitBranchToAt(Addr, Fn, false);
Chris Lattner9b3d9892004-11-23 06:02:06 +0000168 return MCE.finishFunctionStub(0);
169 }
170
Chris Lattner7c83dc22004-11-23 06:27:02 +0000171 MCE.startFunctionStub(4*7);
172 MCE.emitWord(0x9421ffe0); // stwu r1,-32(r1)
173 MCE.emitWord(0x7d6802a6); // mflr r11
174 MCE.emitWord(0x91610028); // stw r11, 40(r1)
175 void *Addr = (void*)(intptr_t)MCE.getCurrentPCValue();
176 MCE.emitWord(0);
177 MCE.emitWord(0);
178 MCE.emitWord(0);
179 MCE.emitWord(0);
180 EmitBranchToAt(Addr, Fn, true/*is call*/);
Chris Lattner9b3d9892004-11-23 06:02:06 +0000181 return MCE.finishFunctionStub(0);
182}
183
184
185void PPC32JITInfo::relocate(void *Function, MachineRelocation *MR,
186 unsigned NumRelocs) {
187 for (unsigned i = 0; i != NumRelocs; ++i, ++MR) {
188 unsigned *RelocPos = (unsigned*)Function + MR->getMachineCodeOffset()/4;
189 intptr_t ResultPtr = (intptr_t)MR->getResultPointer();
190 switch ((PPC::RelocationType)MR->getRelocationType()) {
191 default: assert(0 && "Unknown relocation type!");
192 case PPC::reloc_pcrel_bx:
193 // PC-relative relocation for b and bl instructions.
194 ResultPtr = (ResultPtr-(intptr_t)RelocPos) >> 2;
195 assert(ResultPtr >= -(1 << 23) && ResultPtr < (1 << 23) &&
196 "Relocation out of range!");
197 *RelocPos |= (ResultPtr & ((1 << 24)-1)) << 2;
198 break;
Chris Lattner5efb75d2004-11-24 22:30:08 +0000199
200 case PPC::reloc_absolute_ptr_high: // Pointer relocations.
201 case PPC::reloc_absolute_ptr_low: {
202 // Pointer relocations are used for the PPC external stubs and lazy
203 // resolver pointers that the Darwin ABI likes to use. Basically, the
204 // address of the global is actually stored in memory, and the address of
205 // the pointer is relocated into instructions instead of the pointer
206 // itself. Because we have to keep the mapping anyway, we just return
207 // pointers to the values in the map as our new location.
208 static std::map<void*,void*> Pointers;
209 void *&Ptr = Pointers[(void*)ResultPtr];
210 Ptr = (void*)ResultPtr;
211 ResultPtr = (intptr_t)&Ptr;
212 }
213 // FALL THROUGH
214 case PPC::reloc_absolute_high: // high bits of ref -> low 16 of instr
215 case PPC::reloc_absolute_low: // low bits of ref -> low 16 of instr
Chris Lattner9b3d9892004-11-23 06:02:06 +0000216 ResultPtr += MR->getConstantVal();
217
Chris Lattner5efb75d2004-11-24 22:30:08 +0000218 // If this is a high-part access, get the high-part.
219 if (MR->getRelocationType() == PPC::reloc_absolute_high ||
220 MR->getRelocationType() == PPC::reloc_absolute_ptr_high) {
Chris Lattner9b3d9892004-11-23 06:02:06 +0000221 // If the low part will have a carry (really a borrow) from the low
222 // 16-bits into the high 16, add a bit to borrow from.
223 if (((int)ResultPtr << 16) < 0)
224 ResultPtr += 1 << 16;
225 ResultPtr >>= 16;
226 }
227
228 // Do the addition then mask, so the addition does not overflow the 16-bit
229 // immediate section of the instruction.
230 unsigned LowBits = (*RelocPos + ResultPtr) & 65535;
231 unsigned HighBits = *RelocPos & ~65535;
232 *RelocPos = LowBits | HighBits; // Slam into low 16-bits
233 break;
234 }
235 }
236}
237
238void PPC32JITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
Chris Lattner7c83dc22004-11-23 06:27:02 +0000239 EmitBranchToAt(Old, New, false);
Chris Lattner9b3d9892004-11-23 06:02:06 +0000240}