diff options
author | Mike Pall <mike> | 2011-10-24 16:43:51 +0200 |
---|---|---|
committer | Mike Pall <mike> | 2011-10-24 16:43:51 +0200 |
commit | 0cf8c20be8ee009e01752874186a1dea352009fb (patch) | |
tree | 28280798d8765fa4693d41a7310ccb87e6f5d02e /src/lj_emit_ppc.h | |
parent | fa9ade356b0543f11295023de3b4441a1e7d39a3 (diff) | |
download | luajit-0cf8c20be8ee009e01752874186a1dea352009fb.tar.gz luajit-0cf8c20be8ee009e01752874186a1dea352009fb.tar.bz2 luajit-0cf8c20be8ee009e01752874186a1dea352009fb.zip |
PPC: Integrate and enable JIT compiler.
Diffstat (limited to 'src/lj_emit_ppc.h')
-rw-r--r-- | src/lj_emit_ppc.h | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/lj_emit_ppc.h b/src/lj_emit_ppc.h new file mode 100644 index 00000000..e44221cd --- /dev/null +++ b/src/lj_emit_ppc.h | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | ** PPC instruction emitter. | ||
3 | ** Copyright (C) 2005-2011 Mike Pall. See Copyright Notice in luajit.h | ||
4 | */ | ||
5 | |||
6 | /* -- Emit basic instructions --------------------------------------------- */ | ||
7 | |||
8 | static void emit_tab(ASMState *as, PPCIns pi, Reg rt, Reg ra, Reg rb) | ||
9 | { | ||
10 | *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | PPCF_B(rb); | ||
11 | } | ||
12 | |||
13 | #define emit_asb(as, pi, ra, rs, rb) emit_tab(as, (pi), (rs), (ra), (rb)) | ||
14 | #define emit_as(as, pi, ra, rs) emit_tab(as, (pi), (rs), (ra), 0) | ||
15 | #define emit_ab(as, pi, ra, rb) emit_tab(as, (pi), 0, (ra), (rb)) | ||
16 | |||
17 | static void emit_tai(ASMState *as, PPCIns pi, Reg rt, Reg ra, int32_t i) | ||
18 | { | ||
19 | *--as->mcp = pi | PPCF_T(rt) | PPCF_A(ra) | (i & 0xffff); | ||
20 | } | ||
21 | |||
22 | #define emit_ti(as, pi, rt, i) emit_tai(as, (pi), (rt), 0, (i)) | ||
23 | #define emit_ai(as, pi, ra, i) emit_tai(as, (pi), 0, (ra), (i)) | ||
24 | #define emit_asi(as, pi, ra, rs, i) emit_tai(as, (pi), (rs), (ra), (i)) | ||
25 | |||
26 | #define emit_fab(as, pi, rf, ra, rb) \ | ||
27 | emit_tab(as, (pi), (rf)&31, (ra)&31, (rb)&31) | ||
28 | #define emit_fb(as, pi, rf, rb) emit_tab(as, (pi), (rf)&31, 0, (rb)&31) | ||
29 | #define emit_fac(as, pi, rf, ra, rc) \ | ||
30 | emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, 0) | ||
31 | #define emit_facb(as, pi, rf, ra, rc, rb) \ | ||
32 | emit_tab(as, (pi) | PPCF_C((rc) & 31), (rf)&31, (ra)&31, (rb)&31) | ||
33 | #define emit_fai(as, pi, rf, ra, i) emit_tai(as, (pi), (rf)&31, (ra), (i)) | ||
34 | |||
35 | static void emit_rot(ASMState *as, PPCIns pi, Reg ra, Reg rs, | ||
36 | int32_t n, int32_t b, int32_t e) | ||
37 | { | ||
38 | *--as->mcp = pi | PPCF_T(rs) | PPCF_A(ra) | PPCF_B(n) | | ||
39 | PPCF_MB(b) | PPCF_ME(e); | ||
40 | } | ||
41 | |||
42 | static void emit_slwi(ASMState *as, Reg ra, Reg rs, int32_t n) | ||
43 | { | ||
44 | lua_assert(n >= 0 && n < 32); | ||
45 | emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31-n); | ||
46 | } | ||
47 | |||
48 | static void emit_rotlwi(ASMState *as, Reg ra, Reg rs, int32_t n) | ||
49 | { | ||
50 | lua_assert(n >= 0 && n < 32); | ||
51 | emit_rot(as, PPCI_RLWINM, ra, rs, n, 0, 31); | ||
52 | } | ||
53 | |||
54 | /* -- Emit loads/stores --------------------------------------------------- */ | ||
55 | |||
56 | /* Prefer rematerialization of BASE/L from global_State over spills. */ | ||
57 | #define emit_canremat(ref) ((ref) <= REF_BASE) | ||
58 | |||
59 | /* Try to find a one step delta relative to another constant. */ | ||
60 | static int emit_kdelta1(ASMState *as, Reg t, int32_t i) | ||
61 | { | ||
62 | RegSet work = ~as->freeset & RSET_GPR; | ||
63 | while (work) { | ||
64 | Reg r = rset_picktop(work); | ||
65 | IRRef ref = regcost_ref(as->cost[r]); | ||
66 | lua_assert(r != t); | ||
67 | if (ref < ASMREF_L) { | ||
68 | int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i); | ||
69 | if (checki16(delta)) { | ||
70 | emit_tai(as, PPCI_ADDI, t, r, delta); | ||
71 | return 1; | ||
72 | } | ||
73 | } | ||
74 | rset_clear(work, r); | ||
75 | } | ||
76 | return 0; /* Failed. */ | ||
77 | } | ||
78 | |||
79 | /* Load a 32 bit constant into a GPR. */ | ||
80 | static void emit_loadi(ASMState *as, Reg r, int32_t i) | ||
81 | { | ||
82 | if (checki16(i)) { | ||
83 | emit_ti(as, PPCI_LI, r, i); | ||
84 | } else { | ||
85 | if ((i & 0xffff)) { | ||
86 | int32_t jgl = i32ptr(J2G(as->J)); | ||
87 | if ((uint32_t)(i-jgl) < 65536) { | ||
88 | emit_tai(as, PPCI_ADDI, r, RID_JGL, i-jgl-32768); | ||
89 | return; | ||
90 | } else if (emit_kdelta1(as, r, i)) { | ||
91 | return; | ||
92 | } | ||
93 | emit_asi(as, PPCI_ORI, r, r, i); | ||
94 | } | ||
95 | emit_ti(as, PPCI_LIS, r, (i >> 16)); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | #define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr))) | ||
100 | |||
101 | static Reg ra_allock(ASMState *as, int32_t k, RegSet allow); | ||
102 | |||
103 | /* Get/set from constant pointer. */ | ||
104 | static void emit_lsptr(ASMState *as, PPCIns pi, Reg r, void *p, RegSet allow) | ||
105 | { | ||
106 | int32_t jgl = i32ptr(J2G(as->J)); | ||
107 | int32_t i = i32ptr(p); | ||
108 | Reg base; | ||
109 | if ((uint32_t)(i-jgl) < 65536) { | ||
110 | i = i-jgl-32768; | ||
111 | base = RID_JGL; | ||
112 | } else { | ||
113 | base = ra_allock(as, i-(int16_t)i, allow); | ||
114 | } | ||
115 | emit_tai(as, pi, r, base, i); | ||
116 | } | ||
117 | |||
118 | #define emit_loadn(as, r, tv) \ | ||
119 | emit_lsptr(as, PPCI_LFD, ((r) & 31), (void *)(tv), RSET_GPR) | ||
120 | |||
121 | /* Get/set global_State fields. */ | ||
122 | static void emit_lsglptr(ASMState *as, PPCIns pi, Reg r, int32_t ofs) | ||
123 | { | ||
124 | emit_tai(as, pi, r, RID_JGL, ofs-32768); | ||
125 | } | ||
126 | |||
127 | #define emit_getgl(as, r, field) \ | ||
128 | emit_lsglptr(as, PPCI_LWZ, (r), (int32_t)offsetof(global_State, field)) | ||
129 | #define emit_setgl(as, r, field) \ | ||
130 | emit_lsglptr(as, PPCI_STW, (r), (int32_t)offsetof(global_State, field)) | ||
131 | |||
132 | /* Trace number is determined from per-trace exit stubs. */ | ||
133 | #define emit_setvmstate(as, i) UNUSED(i) | ||
134 | |||
135 | /* -- Emit control-flow instructions -------------------------------------- */ | ||
136 | |||
137 | /* Label for internal jumps. */ | ||
138 | typedef MCode *MCLabel; | ||
139 | |||
140 | /* Return label pointing to current PC. */ | ||
141 | #define emit_label(as) ((as)->mcp) | ||
142 | |||
143 | static void emit_condbranch(ASMState *as, PPCIns pi, PPCCC cc, MCode *target) | ||
144 | { | ||
145 | MCode *p = as->mcp; | ||
146 | ptrdiff_t delta = ((char *)target - (char *)p) + 4; | ||
147 | lua_assert(((delta + 0x8000) >> 16) == 0); | ||
148 | pi ^= (delta & 0x8000) * (PPCF_Y/0x8000); | ||
149 | *--p = pi | PPCF_CC(cc) | ((uint32_t)delta & 0xffffu); | ||
150 | as->mcp = p; | ||
151 | } | ||
152 | |||
153 | static void emit_call(ASMState *as, void *target) | ||
154 | { | ||
155 | MCode *p = --as->mcp; | ||
156 | ptrdiff_t delta = (char *)target - (char *)p; | ||
157 | if ((((delta>>2) + 0x00800000) >> 24) == 0) { | ||
158 | *p = PPCI_BL | (delta & 0x03fffffcu); | ||
159 | } else { /* Target out of range: need indirect call. Don't use arg reg. */ | ||
160 | RegSet allow = RSET_GPR & ~RSET_RANGE(RID_R0, REGARG_LASTGPR+1); | ||
161 | Reg r = ra_allock(as, i32ptr(target), allow); | ||
162 | *p = PPCI_BCTRL; | ||
163 | p[-1] = PPCI_MTCTR | PPCF_T(r); | ||
164 | as->mcp = p-1; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | /* -- Emit generic operations --------------------------------------------- */ | ||
169 | |||
170 | #define emit_mr(as, dst, src) \ | ||
171 | emit_asb(as, PPCI_MR, (dst), (src), (src)) | ||
172 | |||
173 | /* Generic move between two regs. */ | ||
174 | static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src) | ||
175 | { | ||
176 | UNUSED(ir); | ||
177 | if (dst < RID_MAX_GPR) | ||
178 | emit_mr(as, dst, src); | ||
179 | else | ||
180 | emit_fb(as, PPCI_FMR, dst, src); | ||
181 | } | ||
182 | |||
183 | /* Generic load of register from stack slot. */ | ||
184 | static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs) | ||
185 | { | ||
186 | if (r < RID_MAX_GPR) | ||
187 | emit_tai(as, PPCI_LWZ, r, RID_SP, ofs); | ||
188 | else | ||
189 | emit_fai(as, irt_isnum(ir->t) ? PPCI_LFD : PPCI_LFS, r, RID_SP, ofs); | ||
190 | } | ||
191 | |||
192 | /* Generic store of register to stack slot. */ | ||
193 | static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs) | ||
194 | { | ||
195 | if (r < RID_MAX_GPR) | ||
196 | emit_tai(as, PPCI_STW, r, RID_SP, ofs); | ||
197 | else | ||
198 | emit_fai(as, irt_isnum(ir->t) ? PPCI_STFD : PPCI_STFS, r, RID_SP, ofs); | ||
199 | } | ||
200 | |||
201 | /* Emit a compare (for equality) with a constant operand. */ | ||
202 | static void emit_cmpi(ASMState *as, Reg r, int32_t k) | ||
203 | { | ||
204 | if (checki16(k)) { | ||
205 | emit_ai(as, PPCI_CMPWI, r, k); | ||
206 | } else if (checku16(k)) { | ||
207 | emit_ai(as, PPCI_CMPLWI, r, k); | ||
208 | } else { | ||
209 | emit_ai(as, PPCI_CMPLWI, RID_TMP, k); | ||
210 | emit_asi(as, PPCI_XORIS, RID_TMP, r, (k >> 16)); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | /* Add offset to pointer. */ | ||
215 | static void emit_addptr(ASMState *as, Reg r, int32_t ofs) | ||
216 | { | ||
217 | if (ofs) { | ||
218 | emit_tai(as, PPCI_ADDI, r, r, ofs); | ||
219 | if (!checki16(ofs)) | ||
220 | emit_tai(as, PPCI_ADDIS, r, r, (ofs + 32768) >> 16); | ||
221 | } | ||
222 | } | ||
223 | |||
224 | static void emit_spsub(ASMState *as, int32_t ofs) | ||
225 | { | ||
226 | if (ofs) { | ||
227 | emit_tai(as, PPCI_STWU, RID_TMP, RID_SP, -ofs); | ||
228 | emit_tai(as, PPCI_ADDI, RID_TMP, RID_SP, | ||
229 | CFRAME_SIZE + (as->parent ? as->parent->spadjust : 0)); | ||
230 | } | ||
231 | } | ||
232 | |||