|
1 /* |
|
2 * Tiny Code Generator for QEMU |
|
3 * |
|
4 * Copyright (c) 2008 Fabrice Bellard |
|
5 * |
|
6 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
7 * of this software and associated documentation files (the "Software"), to deal |
|
8 * in the Software without restriction, including without limitation the rights |
|
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
10 * copies of the Software, and to permit persons to whom the Software is |
|
11 * furnished to do so, subject to the following conditions: |
|
12 * |
|
13 * The above copyright notice and this permission notice shall be included in |
|
14 * all copies or substantial portions of the Software. |
|
15 * |
|
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
22 * THE SOFTWARE. |
|
23 */ |
|
24 |
|
25 static uint8_t *tb_ret_addr; |
|
26 |
|
27 #ifdef __APPLE__ |
|
28 #define LINKAGE_AREA_SIZE 24 |
|
29 #define LR_OFFSET 8 |
|
30 #elif defined _AIX |
|
31 #define LINKAGE_AREA_SIZE 52 |
|
32 #define LR_OFFSET 8 |
|
33 #else |
|
34 #define LINKAGE_AREA_SIZE 8 |
|
35 #define LR_OFFSET 4 |
|
36 #endif |
|
37 |
|
38 #define FAST_PATH |
|
39 #if TARGET_PHYS_ADDR_BITS <= 32 |
|
40 #define ADDEND_OFFSET 0 |
|
41 #else |
|
42 #define ADDEND_OFFSET 4 |
|
43 #endif |
|
44 |
|
45 #ifndef NDEBUG |
|
46 static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { |
|
47 "r0", |
|
48 "r1", |
|
49 "rp", |
|
50 "r3", |
|
51 "r4", |
|
52 "r5", |
|
53 "r6", |
|
54 "r7", |
|
55 "r8", |
|
56 "r9", |
|
57 "r10", |
|
58 "r11", |
|
59 "r12", |
|
60 "r13", |
|
61 "r14", |
|
62 "r15", |
|
63 "r16", |
|
64 "r17", |
|
65 "r18", |
|
66 "r19", |
|
67 "r20", |
|
68 "r21", |
|
69 "r22", |
|
70 "r23", |
|
71 "r24", |
|
72 "r25", |
|
73 "r26", |
|
74 "r27", |
|
75 "r28", |
|
76 "r29", |
|
77 "r30", |
|
78 "r31" |
|
79 }; |
|
80 #endif |
|
81 |
|
82 static const int tcg_target_reg_alloc_order[] = { |
|
83 TCG_REG_R14, |
|
84 TCG_REG_R15, |
|
85 TCG_REG_R16, |
|
86 TCG_REG_R17, |
|
87 TCG_REG_R18, |
|
88 TCG_REG_R19, |
|
89 TCG_REG_R20, |
|
90 TCG_REG_R21, |
|
91 TCG_REG_R22, |
|
92 TCG_REG_R23, |
|
93 TCG_REG_R28, |
|
94 TCG_REG_R29, |
|
95 TCG_REG_R30, |
|
96 TCG_REG_R31, |
|
97 #ifdef __APPLE__ |
|
98 TCG_REG_R2, |
|
99 #endif |
|
100 TCG_REG_R3, |
|
101 TCG_REG_R4, |
|
102 TCG_REG_R5, |
|
103 TCG_REG_R6, |
|
104 TCG_REG_R7, |
|
105 TCG_REG_R8, |
|
106 TCG_REG_R9, |
|
107 TCG_REG_R10, |
|
108 #ifndef __APPLE__ |
|
109 TCG_REG_R11, |
|
110 #endif |
|
111 TCG_REG_R12, |
|
112 TCG_REG_R13, |
|
113 TCG_REG_R0, |
|
114 TCG_REG_R1, |
|
115 TCG_REG_R2, |
|
116 TCG_REG_R24, |
|
117 TCG_REG_R25, |
|
118 TCG_REG_R26, |
|
119 TCG_REG_R27 |
|
120 }; |
|
121 |
|
122 static const int tcg_target_call_iarg_regs[] = { |
|
123 TCG_REG_R3, |
|
124 TCG_REG_R4, |
|
125 TCG_REG_R5, |
|
126 TCG_REG_R6, |
|
127 TCG_REG_R7, |
|
128 TCG_REG_R8, |
|
129 TCG_REG_R9, |
|
130 TCG_REG_R10 |
|
131 }; |
|
132 |
|
133 static const int tcg_target_call_oarg_regs[2] = { |
|
134 TCG_REG_R3, |
|
135 TCG_REG_R4 |
|
136 }; |
|
137 |
|
138 static const int tcg_target_callee_save_regs[] = { |
|
139 #ifdef __APPLE__ |
|
140 TCG_REG_R11, |
|
141 TCG_REG_R13, |
|
142 #endif |
|
143 #ifdef _AIX |
|
144 TCG_REG_R13, |
|
145 #endif |
|
146 TCG_REG_R14, |
|
147 TCG_REG_R15, |
|
148 TCG_REG_R16, |
|
149 TCG_REG_R17, |
|
150 TCG_REG_R18, |
|
151 TCG_REG_R19, |
|
152 TCG_REG_R20, |
|
153 TCG_REG_R21, |
|
154 TCG_REG_R22, |
|
155 TCG_REG_R23, |
|
156 TCG_REG_R28, |
|
157 TCG_REG_R29, |
|
158 TCG_REG_R30, |
|
159 TCG_REG_R31 |
|
160 }; |
|
161 |
|
162 static uint32_t reloc_pc24_val (void *pc, tcg_target_long target) |
|
163 { |
|
164 tcg_target_long disp; |
|
165 |
|
166 disp = target - (tcg_target_long) pc; |
|
167 if ((disp << 6) >> 6 != disp) |
|
168 tcg_abort (); |
|
169 |
|
170 return disp & 0x3fffffc; |
|
171 } |
|
172 |
|
173 static void reloc_pc24 (void *pc, tcg_target_long target) |
|
174 { |
|
175 *(uint32_t *) pc = (*(uint32_t *) pc & ~0x3fffffc) |
|
176 | reloc_pc24_val (pc, target); |
|
177 } |
|
178 |
|
179 static uint16_t reloc_pc14_val (void *pc, tcg_target_long target) |
|
180 { |
|
181 tcg_target_long disp; |
|
182 |
|
183 disp = target - (tcg_target_long) pc; |
|
184 if (disp != (int16_t) disp) |
|
185 tcg_abort (); |
|
186 |
|
187 return disp & 0xfffc; |
|
188 } |
|
189 |
|
190 static void reloc_pc14 (void *pc, tcg_target_long target) |
|
191 { |
|
192 *(uint32_t *) pc = (*(uint32_t *) pc & ~0xfffc) |
|
193 | reloc_pc14_val (pc, target); |
|
194 } |
|
195 |
|
196 static void patch_reloc(uint8_t *code_ptr, int type, |
|
197 tcg_target_long value, tcg_target_long addend) |
|
198 { |
|
199 value += addend; |
|
200 switch (type) { |
|
201 case R_PPC_REL14: |
|
202 reloc_pc14 (code_ptr, value); |
|
203 break; |
|
204 case R_PPC_REL24: |
|
205 reloc_pc24 (code_ptr, value); |
|
206 break; |
|
207 default: |
|
208 tcg_abort(); |
|
209 } |
|
210 } |
|
211 |
|
212 /* maximum number of register used for input function arguments */ |
|
213 static int tcg_target_get_call_iarg_regs_count(int flags) |
|
214 { |
|
215 return ARRAY_SIZE (tcg_target_call_iarg_regs); |
|
216 } |
|
217 |
|
218 /* parse target specific constraints */ |
|
219 static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) |
|
220 { |
|
221 const char *ct_str; |
|
222 |
|
223 ct_str = *pct_str; |
|
224 switch (ct_str[0]) { |
|
225 case 'A': case 'B': case 'C': case 'D': |
|
226 ct->ct |= TCG_CT_REG; |
|
227 tcg_regset_set_reg(ct->u.regs, 3 + ct_str[0] - 'A'); |
|
228 break; |
|
229 case 'r': |
|
230 ct->ct |= TCG_CT_REG; |
|
231 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
232 break; |
|
233 #ifdef CONFIG_SOFTMMU |
|
234 case 'L': /* qemu_ld constraint */ |
|
235 ct->ct |= TCG_CT_REG; |
|
236 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
237 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); |
|
238 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); |
|
239 break; |
|
240 case 'K': /* qemu_st[8..32] constraint */ |
|
241 ct->ct |= TCG_CT_REG; |
|
242 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
243 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); |
|
244 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); |
|
245 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); |
|
246 #if TARGET_LONG_BITS == 64 |
|
247 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); |
|
248 #endif |
|
249 break; |
|
250 case 'M': /* qemu_st64 constraint */ |
|
251 ct->ct |= TCG_CT_REG; |
|
252 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
253 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); |
|
254 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); |
|
255 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); |
|
256 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); |
|
257 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); |
|
258 break; |
|
259 #else |
|
260 case 'L': |
|
261 case 'K': |
|
262 ct->ct |= TCG_CT_REG; |
|
263 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
264 break; |
|
265 case 'M': |
|
266 ct->ct |= TCG_CT_REG; |
|
267 tcg_regset_set32(ct->u.regs, 0, 0xffffffff); |
|
268 tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); |
|
269 break; |
|
270 #endif |
|
271 default: |
|
272 return -1; |
|
273 } |
|
274 ct_str++; |
|
275 *pct_str = ct_str; |
|
276 return 0; |
|
277 } |
|
278 |
|
279 /* test if a constant matches the constraint */ |
|
280 static int tcg_target_const_match(tcg_target_long val, |
|
281 const TCGArgConstraint *arg_ct) |
|
282 { |
|
283 int ct; |
|
284 |
|
285 ct = arg_ct->ct; |
|
286 if (ct & TCG_CT_CONST) |
|
287 return 1; |
|
288 return 0; |
|
289 } |
|
290 |
|
291 #define OPCD(opc) ((opc)<<26) |
|
292 #define XO31(opc) (OPCD(31)|((opc)<<1)) |
|
293 #define XO19(opc) (OPCD(19)|((opc)<<1)) |
|
294 |
|
295 #define B OPCD(18) |
|
296 #define BC OPCD(16) |
|
297 #define LBZ OPCD(34) |
|
298 #define LHZ OPCD(40) |
|
299 #define LHA OPCD(42) |
|
300 #define LWZ OPCD(32) |
|
301 #define STB OPCD(38) |
|
302 #define STH OPCD(44) |
|
303 #define STW OPCD(36) |
|
304 |
|
305 #define ADDI OPCD(14) |
|
306 #define ADDIS OPCD(15) |
|
307 #define ORI OPCD(24) |
|
308 #define ORIS OPCD(25) |
|
309 #define XORI OPCD(26) |
|
310 #define XORIS OPCD(27) |
|
311 #define ANDI OPCD(28) |
|
312 #define ANDIS OPCD(29) |
|
313 #define MULLI OPCD( 7) |
|
314 #define CMPLI OPCD(10) |
|
315 #define CMPI OPCD(11) |
|
316 |
|
317 #define LWZU OPCD(33) |
|
318 #define STWU OPCD(37) |
|
319 |
|
320 #define RLWINM OPCD(21) |
|
321 |
|
322 #define BCLR XO19( 16) |
|
323 #define BCCTR XO19(528) |
|
324 #define CRAND XO19(257) |
|
325 #define CRANDC XO19(129) |
|
326 #define CRNAND XO19(225) |
|
327 #define CROR XO19(449) |
|
328 |
|
329 #define EXTSB XO31(954) |
|
330 #define EXTSH XO31(922) |
|
331 #define ADD XO31(266) |
|
332 #define ADDE XO31(138) |
|
333 #define ADDC XO31( 10) |
|
334 #define AND XO31( 28) |
|
335 #define SUBF XO31( 40) |
|
336 #define SUBFC XO31( 8) |
|
337 #define SUBFE XO31(136) |
|
338 #define OR XO31(444) |
|
339 #define XOR XO31(316) |
|
340 #define MULLW XO31(235) |
|
341 #define MULHWU XO31( 11) |
|
342 #define DIVW XO31(491) |
|
343 #define DIVWU XO31(459) |
|
344 #define CMP XO31( 0) |
|
345 #define CMPL XO31( 32) |
|
346 #define LHBRX XO31(790) |
|
347 #define LWBRX XO31(534) |
|
348 #define STHBRX XO31(918) |
|
349 #define STWBRX XO31(662) |
|
350 #define MFSPR XO31(339) |
|
351 #define MTSPR XO31(467) |
|
352 #define SRAWI XO31(824) |
|
353 #define NEG XO31(104) |
|
354 |
|
355 #define LBZX XO31( 87) |
|
356 #define LHZX XO31(276) |
|
357 #define LHAX XO31(343) |
|
358 #define LWZX XO31( 23) |
|
359 #define STBX XO31(215) |
|
360 #define STHX XO31(407) |
|
361 #define STWX XO31(151) |
|
362 |
|
363 #define SPR(a,b) ((((a)<<5)|(b))<<11) |
|
364 #define LR SPR(8, 0) |
|
365 #define CTR SPR(9, 0) |
|
366 |
|
367 #define SLW XO31( 24) |
|
368 #define SRW XO31(536) |
|
369 #define SRAW XO31(792) |
|
370 |
|
371 #define LMW OPCD(46) |
|
372 #define STMW OPCD(47) |
|
373 |
|
374 #define TW XO31(4) |
|
375 #define TRAP (TW | TO (31)) |
|
376 |
|
377 #define RT(r) ((r)<<21) |
|
378 #define RS(r) ((r)<<21) |
|
379 #define RA(r) ((r)<<16) |
|
380 #define RB(r) ((r)<<11) |
|
381 #define TO(t) ((t)<<21) |
|
382 #define SH(s) ((s)<<11) |
|
383 #define MB(b) ((b)<<6) |
|
384 #define ME(e) ((e)<<1) |
|
385 #define BO(o) ((o)<<21) |
|
386 |
|
387 #define LK 1 |
|
388 |
|
389 #define TAB(t,a,b) (RT(t) | RA(a) | RB(b)) |
|
390 #define SAB(s,a,b) (RS(s) | RA(a) | RB(b)) |
|
391 |
|
392 #define BF(n) ((n)<<23) |
|
393 #define BI(n, c) (((c)+((n)*4))<<16) |
|
394 #define BT(n, c) (((c)+((n)*4))<<21) |
|
395 #define BA(n, c) (((c)+((n)*4))<<16) |
|
396 #define BB(n, c) (((c)+((n)*4))<<11) |
|
397 |
|
398 #define BO_COND_TRUE BO (12) |
|
399 #define BO_COND_FALSE BO (4) |
|
400 #define BO_ALWAYS BO (20) |
|
401 |
|
402 enum { |
|
403 CR_LT, |
|
404 CR_GT, |
|
405 CR_EQ, |
|
406 CR_SO |
|
407 }; |
|
408 |
|
409 static const uint32_t tcg_to_bc[10] = { |
|
410 [TCG_COND_EQ] = BC | BI (7, CR_EQ) | BO_COND_TRUE, |
|
411 [TCG_COND_NE] = BC | BI (7, CR_EQ) | BO_COND_FALSE, |
|
412 [TCG_COND_LT] = BC | BI (7, CR_LT) | BO_COND_TRUE, |
|
413 [TCG_COND_GE] = BC | BI (7, CR_LT) | BO_COND_FALSE, |
|
414 [TCG_COND_LE] = BC | BI (7, CR_GT) | BO_COND_FALSE, |
|
415 [TCG_COND_GT] = BC | BI (7, CR_GT) | BO_COND_TRUE, |
|
416 [TCG_COND_LTU] = BC | BI (7, CR_LT) | BO_COND_TRUE, |
|
417 [TCG_COND_GEU] = BC | BI (7, CR_LT) | BO_COND_FALSE, |
|
418 [TCG_COND_LEU] = BC | BI (7, CR_GT) | BO_COND_FALSE, |
|
419 [TCG_COND_GTU] = BC | BI (7, CR_GT) | BO_COND_TRUE, |
|
420 }; |
|
421 |
|
422 static void tcg_out_mov(TCGContext *s, int ret, int arg) |
|
423 { |
|
424 tcg_out32 (s, OR | SAB (arg, ret, arg)); |
|
425 } |
|
426 |
|
427 static void tcg_out_movi(TCGContext *s, TCGType type, |
|
428 int ret, tcg_target_long arg) |
|
429 { |
|
430 if (arg == (int16_t) arg) |
|
431 tcg_out32 (s, ADDI | RT (ret) | RA (0) | (arg & 0xffff)); |
|
432 else { |
|
433 tcg_out32 (s, ADDIS | RT (ret) | RA (0) | ((arg >> 16) & 0xffff)); |
|
434 if (arg & 0xffff) |
|
435 tcg_out32 (s, ORI | RS (ret) | RA (ret) | (arg & 0xffff)); |
|
436 } |
|
437 } |
|
438 |
|
439 static void tcg_out_ldst (TCGContext *s, int ret, int addr, |
|
440 int offset, int op1, int op2) |
|
441 { |
|
442 if (offset == (int16_t) offset) |
|
443 tcg_out32 (s, op1 | RT (ret) | RA (addr) | (offset & 0xffff)); |
|
444 else { |
|
445 tcg_out_movi (s, TCG_TYPE_I32, 0, offset); |
|
446 tcg_out32 (s, op2 | RT (ret) | RA (addr) | RB (0)); |
|
447 } |
|
448 } |
|
449 |
|
450 static void tcg_out_b (TCGContext *s, int mask, tcg_target_long target) |
|
451 { |
|
452 tcg_target_long disp; |
|
453 |
|
454 disp = target - (tcg_target_long) s->code_ptr; |
|
455 if ((disp << 6) >> 6 == disp) |
|
456 tcg_out32 (s, B | (disp & 0x3fffffc) | mask); |
|
457 else { |
|
458 tcg_out_movi (s, TCG_TYPE_I32, 0, (tcg_target_long) target); |
|
459 tcg_out32 (s, MTSPR | RS (0) | CTR); |
|
460 tcg_out32 (s, BCCTR | BO_ALWAYS | mask); |
|
461 } |
|
462 } |
|
463 |
|
464 #ifdef _AIX |
|
465 static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) |
|
466 { |
|
467 int reg; |
|
468 |
|
469 if (const_arg) { |
|
470 reg = 2; |
|
471 tcg_out_movi (s, TCG_TYPE_I32, reg, arg); |
|
472 } |
|
473 else reg = arg; |
|
474 |
|
475 tcg_out32 (s, LWZ | RT (0) | RA (reg)); |
|
476 tcg_out32 (s, MTSPR | RA (0) | CTR); |
|
477 tcg_out32 (s, LWZ | RT (2) | RA (reg) | 4); |
|
478 tcg_out32 (s, BCCTR | BO_ALWAYS | LK); |
|
479 } |
|
480 #endif |
|
481 |
|
482 #if defined(CONFIG_SOFTMMU) |
|
483 |
|
484 #include "../../softmmu_defs.h" |
|
485 |
|
486 static void *qemu_ld_helpers[4] = { |
|
487 __ldb_mmu, |
|
488 __ldw_mmu, |
|
489 __ldl_mmu, |
|
490 __ldq_mmu, |
|
491 }; |
|
492 |
|
493 static void *qemu_st_helpers[4] = { |
|
494 __stb_mmu, |
|
495 __stw_mmu, |
|
496 __stl_mmu, |
|
497 __stq_mmu, |
|
498 }; |
|
499 #endif |
|
500 |
|
501 static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) |
|
502 { |
|
503 int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap; |
|
504 #ifdef CONFIG_SOFTMMU |
|
505 int r2; |
|
506 void *label1_ptr, *label2_ptr; |
|
507 #endif |
|
508 #if TARGET_LONG_BITS == 64 |
|
509 int addr_reg2; |
|
510 #endif |
|
511 |
|
512 data_reg = *args++; |
|
513 if (opc == 3) |
|
514 data_reg2 = *args++; |
|
515 else |
|
516 data_reg2 = 0; |
|
517 addr_reg = *args++; |
|
518 #if TARGET_LONG_BITS == 64 |
|
519 addr_reg2 = *args++; |
|
520 #endif |
|
521 mem_index = *args; |
|
522 s_bits = opc & 3; |
|
523 |
|
524 #ifdef CONFIG_SOFTMMU |
|
525 r0 = 3; |
|
526 r1 = 4; |
|
527 r2 = 0; |
|
528 |
|
529 tcg_out32 (s, (RLWINM |
|
530 | RA (r0) |
|
531 | RS (addr_reg) |
|
532 | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) |
|
533 | MB (32 - (CPU_TLB_BITS + CPU_TLB_ENTRY_BITS)) |
|
534 | ME (31 - CPU_TLB_ENTRY_BITS) |
|
535 ) |
|
536 ); |
|
537 tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); |
|
538 tcg_out32 (s, (LWZU |
|
539 | RT (r1) |
|
540 | RA (r0) |
|
541 | offsetof (CPUState, tlb_table[mem_index][0].addr_read) |
|
542 ) |
|
543 ); |
|
544 tcg_out32 (s, (RLWINM |
|
545 | RA (r2) |
|
546 | RS (addr_reg) |
|
547 | SH (0) |
|
548 | MB ((32 - s_bits) & 31) |
|
549 | ME (31 - TARGET_PAGE_BITS) |
|
550 ) |
|
551 ); |
|
552 |
|
553 tcg_out32 (s, CMP | BF (7) | RA (r2) | RB (r1)); |
|
554 #if TARGET_LONG_BITS == 64 |
|
555 tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); |
|
556 tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); |
|
557 tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); |
|
558 #endif |
|
559 |
|
560 label1_ptr = s->code_ptr; |
|
561 #ifdef FAST_PATH |
|
562 tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); |
|
563 #endif |
|
564 |
|
565 /* slow path */ |
|
566 #if TARGET_LONG_BITS == 32 |
|
567 tcg_out_mov (s, 3, addr_reg); |
|
568 tcg_out_movi (s, TCG_TYPE_I32, 4, mem_index); |
|
569 #else |
|
570 tcg_out_mov (s, 3, addr_reg2); |
|
571 tcg_out_mov (s, 4, addr_reg); |
|
572 tcg_out_movi (s, TCG_TYPE_I32, 5, mem_index); |
|
573 #endif |
|
574 |
|
575 #ifdef _AIX |
|
576 tcg_out_call (s, (tcg_target_long) qemu_ld_helpers[s_bits], 1); |
|
577 #else |
|
578 tcg_out_b (s, LK, (tcg_target_long) qemu_ld_helpers[s_bits]); |
|
579 #endif |
|
580 switch (opc) { |
|
581 case 0|4: |
|
582 tcg_out32 (s, EXTSB | RA (data_reg) | RS (3)); |
|
583 break; |
|
584 case 1|4: |
|
585 tcg_out32 (s, EXTSH | RA (data_reg) | RS (3)); |
|
586 break; |
|
587 case 0: |
|
588 case 1: |
|
589 case 2: |
|
590 if (data_reg != 3) |
|
591 tcg_out_mov (s, data_reg, 3); |
|
592 break; |
|
593 case 3: |
|
594 if (data_reg == 3) { |
|
595 if (data_reg2 == 4) { |
|
596 tcg_out_mov (s, 0, 4); |
|
597 tcg_out_mov (s, 4, 3); |
|
598 tcg_out_mov (s, 3, 0); |
|
599 } |
|
600 else { |
|
601 tcg_out_mov (s, data_reg2, 3); |
|
602 tcg_out_mov (s, 3, 4); |
|
603 } |
|
604 } |
|
605 else { |
|
606 if (data_reg != 4) tcg_out_mov (s, data_reg, 4); |
|
607 if (data_reg2 != 3) tcg_out_mov (s, data_reg2, 3); |
|
608 } |
|
609 break; |
|
610 } |
|
611 label2_ptr = s->code_ptr; |
|
612 tcg_out32 (s, B); |
|
613 |
|
614 /* label1: fast path */ |
|
615 #ifdef FAST_PATH |
|
616 reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); |
|
617 #endif |
|
618 |
|
619 /* r0 now contains &env->tlb_table[mem_index][index].addr_read */ |
|
620 tcg_out32 (s, (LWZ |
|
621 | RT (r0) |
|
622 | RA (r0) |
|
623 | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) |
|
624 - offsetof (CPUTLBEntry, addr_read)) |
|
625 )); |
|
626 /* r0 = env->tlb_table[mem_index][index].addend */ |
|
627 tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); |
|
628 /* r0 = env->tlb_table[mem_index][index].addend + addr */ |
|
629 |
|
630 #else /* !CONFIG_SOFTMMU */ |
|
631 r0 = addr_reg; |
|
632 r1 = 3; |
|
633 #endif |
|
634 |
|
635 #ifdef TARGET_WORDS_BIGENDIAN |
|
636 bswap = 0; |
|
637 #else |
|
638 bswap = 1; |
|
639 #endif |
|
640 switch (opc) { |
|
641 default: |
|
642 case 0: |
|
643 tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); |
|
644 break; |
|
645 case 0|4: |
|
646 tcg_out32 (s, LBZ | RT (data_reg) | RA (r0)); |
|
647 tcg_out32 (s, EXTSB | RA (data_reg) | RS (data_reg)); |
|
648 break; |
|
649 case 1: |
|
650 if (bswap) tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); |
|
651 else tcg_out32 (s, LHZ | RT (data_reg) | RA (r0)); |
|
652 break; |
|
653 case 1|4: |
|
654 if (bswap) { |
|
655 tcg_out32 (s, LHBRX | RT (data_reg) | RB (r0)); |
|
656 tcg_out32 (s, EXTSH | RA (data_reg) | RS (data_reg)); |
|
657 } |
|
658 else tcg_out32 (s, LHA | RT (data_reg) | RA (r0)); |
|
659 break; |
|
660 case 2: |
|
661 if (bswap) tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); |
|
662 else tcg_out32 (s, LWZ | RT (data_reg)| RA (r0)); |
|
663 break; |
|
664 case 3: |
|
665 if (bswap) { |
|
666 tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); |
|
667 tcg_out32 (s, LWBRX | RT (data_reg) | RB (r0)); |
|
668 tcg_out32 (s, LWBRX | RT (data_reg2) | RB (r1)); |
|
669 } |
|
670 else { |
|
671 if (r0 == data_reg2) { |
|
672 tcg_out32 (s, LWZ | RT (0) | RA (r0)); |
|
673 tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); |
|
674 tcg_out_mov (s, data_reg2, 0); |
|
675 } |
|
676 else { |
|
677 tcg_out32 (s, LWZ | RT (data_reg2) | RA (r0)); |
|
678 tcg_out32 (s, LWZ | RT (data_reg) | RA (r0) | 4); |
|
679 } |
|
680 } |
|
681 break; |
|
682 } |
|
683 |
|
684 #ifdef CONFIG_SOFTMMU |
|
685 reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); |
|
686 #endif |
|
687 } |
|
688 |
|
689 static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) |
|
690 { |
|
691 int addr_reg, r0, r1, data_reg, data_reg2, mem_index, bswap; |
|
692 #ifdef CONFIG_SOFTMMU |
|
693 int r2, ir; |
|
694 void *label1_ptr, *label2_ptr; |
|
695 #endif |
|
696 #if TARGET_LONG_BITS == 64 |
|
697 int addr_reg2; |
|
698 #endif |
|
699 |
|
700 data_reg = *args++; |
|
701 if (opc == 3) |
|
702 data_reg2 = *args++; |
|
703 else |
|
704 data_reg2 = 0; |
|
705 addr_reg = *args++; |
|
706 #if TARGET_LONG_BITS == 64 |
|
707 addr_reg2 = *args++; |
|
708 #endif |
|
709 mem_index = *args; |
|
710 |
|
711 #ifdef CONFIG_SOFTMMU |
|
712 r0 = 3; |
|
713 r1 = 4; |
|
714 r2 = 0; |
|
715 |
|
716 tcg_out32 (s, (RLWINM |
|
717 | RA (r0) |
|
718 | RS (addr_reg) |
|
719 | SH (32 - (TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS)) |
|
720 | MB (32 - (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)) |
|
721 | ME (31 - CPU_TLB_ENTRY_BITS) |
|
722 ) |
|
723 ); |
|
724 tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (TCG_AREG0)); |
|
725 tcg_out32 (s, (LWZU |
|
726 | RT (r1) |
|
727 | RA (r0) |
|
728 | offsetof (CPUState, tlb_table[mem_index][0].addr_write) |
|
729 ) |
|
730 ); |
|
731 tcg_out32 (s, (RLWINM |
|
732 | RA (r2) |
|
733 | RS (addr_reg) |
|
734 | SH (0) |
|
735 | MB ((32 - opc) & 31) |
|
736 | ME (31 - TARGET_PAGE_BITS) |
|
737 ) |
|
738 ); |
|
739 |
|
740 tcg_out32 (s, CMP | (7 << 23) | RA (r2) | RB (r1)); |
|
741 #if TARGET_LONG_BITS == 64 |
|
742 tcg_out32 (s, LWZ | RT (r1) | RA (r0) | 4); |
|
743 tcg_out32 (s, CMP | BF (6) | RA (addr_reg2) | RB (r1)); |
|
744 tcg_out32 (s, CRAND | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); |
|
745 #endif |
|
746 |
|
747 label1_ptr = s->code_ptr; |
|
748 #ifdef FAST_PATH |
|
749 tcg_out32 (s, BC | BI (7, CR_EQ) | BO_COND_TRUE); |
|
750 #endif |
|
751 |
|
752 /* slow path */ |
|
753 #if TARGET_LONG_BITS == 32 |
|
754 tcg_out_mov (s, 3, addr_reg); |
|
755 ir = 4; |
|
756 #else |
|
757 tcg_out_mov (s, 3, addr_reg2); |
|
758 tcg_out_mov (s, 4, addr_reg); |
|
759 #ifdef TCG_TARGET_CALL_ALIGN_ARGS |
|
760 ir = 5; |
|
761 #else |
|
762 ir = 4; |
|
763 #endif |
|
764 #endif |
|
765 |
|
766 switch (opc) { |
|
767 case 0: |
|
768 tcg_out32 (s, (RLWINM |
|
769 | RA (ir) |
|
770 | RS (data_reg) |
|
771 | SH (0) |
|
772 | MB (24) |
|
773 | ME (31))); |
|
774 break; |
|
775 case 1: |
|
776 tcg_out32 (s, (RLWINM |
|
777 | RA (ir) |
|
778 | RS (data_reg) |
|
779 | SH (0) |
|
780 | MB (16) |
|
781 | ME (31))); |
|
782 break; |
|
783 case 2: |
|
784 tcg_out_mov (s, ir, data_reg); |
|
785 break; |
|
786 case 3: |
|
787 #ifdef TCG_TARGET_CALL_ALIGN_ARGS |
|
788 ir = 5; |
|
789 #endif |
|
790 tcg_out_mov (s, ir++, data_reg2); |
|
791 tcg_out_mov (s, ir, data_reg); |
|
792 break; |
|
793 } |
|
794 ir++; |
|
795 |
|
796 tcg_out_movi (s, TCG_TYPE_I32, ir, mem_index); |
|
797 #ifdef _AIX |
|
798 tcg_out_call (s, (tcg_target_long) qemu_st_helpers[opc], 1); |
|
799 #else |
|
800 tcg_out_b (s, LK, (tcg_target_long) qemu_st_helpers[opc]); |
|
801 #endif |
|
802 label2_ptr = s->code_ptr; |
|
803 tcg_out32 (s, B); |
|
804 |
|
805 /* label1: fast path */ |
|
806 #ifdef FAST_PATH |
|
807 reloc_pc14 (label1_ptr, (tcg_target_long) s->code_ptr); |
|
808 #endif |
|
809 |
|
810 tcg_out32 (s, (LWZ |
|
811 | RT (r0) |
|
812 | RA (r0) |
|
813 | (ADDEND_OFFSET + offsetof (CPUTLBEntry, addend) |
|
814 - offsetof (CPUTLBEntry, addr_write)) |
|
815 )); |
|
816 /* r0 = env->tlb_table[mem_index][index].addend */ |
|
817 tcg_out32 (s, ADD | RT (r0) | RA (r0) | RB (addr_reg)); |
|
818 /* r0 = env->tlb_table[mem_index][index].addend + addr */ |
|
819 |
|
820 #else /* !CONFIG_SOFTMMU */ |
|
821 r1 = 3; |
|
822 r0 = addr_reg; |
|
823 #endif |
|
824 |
|
825 #ifdef TARGET_WORDS_BIGENDIAN |
|
826 bswap = 0; |
|
827 #else |
|
828 bswap = 1; |
|
829 #endif |
|
830 switch (opc) { |
|
831 case 0: |
|
832 tcg_out32 (s, STB | RS (data_reg) | RA (r0)); |
|
833 break; |
|
834 case 1: |
|
835 if (bswap) tcg_out32 (s, STHBRX | RS (data_reg) | RA (0) | RB (r0)); |
|
836 else tcg_out32 (s, STH | RS (data_reg) | RA (r0)); |
|
837 break; |
|
838 case 2: |
|
839 if (bswap) tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); |
|
840 else tcg_out32 (s, STW | RS (data_reg) | RA (r0)); |
|
841 break; |
|
842 case 3: |
|
843 if (bswap) { |
|
844 tcg_out32 (s, ADDI | RT (r1) | RA (r0) | 4); |
|
845 tcg_out32 (s, STWBRX | RS (data_reg) | RA (0) | RB (r0)); |
|
846 tcg_out32 (s, STWBRX | RS (data_reg2) | RA (0) | RB (r1)); |
|
847 } |
|
848 else { |
|
849 tcg_out32 (s, STW | RS (data_reg2) | RA (r0)); |
|
850 tcg_out32 (s, STW | RS (data_reg) | RA (r0) | 4); |
|
851 } |
|
852 break; |
|
853 } |
|
854 |
|
855 #ifdef CONFIG_SOFTMMU |
|
856 reloc_pc24 (label2_ptr, (tcg_target_long) s->code_ptr); |
|
857 #endif |
|
858 } |
|
859 |
|
860 void tcg_target_qemu_prologue (TCGContext *s) |
|
861 { |
|
862 int i, frame_size; |
|
863 |
|
864 frame_size = 0 |
|
865 + LINKAGE_AREA_SIZE |
|
866 + TCG_STATIC_CALL_ARGS_SIZE |
|
867 + ARRAY_SIZE (tcg_target_callee_save_regs) * 4 |
|
868 ; |
|
869 frame_size = (frame_size + 15) & ~15; |
|
870 |
|
871 #ifdef _AIX |
|
872 { |
|
873 uint32_t addr; |
|
874 |
|
875 /* First emit adhoc function descriptor */ |
|
876 addr = (uint32_t) s->code_ptr + 12; |
|
877 tcg_out32 (s, addr); /* entry point */ |
|
878 s->code_ptr += 8; /* skip TOC and environment pointer */ |
|
879 } |
|
880 #endif |
|
881 tcg_out32 (s, MFSPR | RT (0) | LR); |
|
882 tcg_out32 (s, STWU | RS (1) | RA (1) | (-frame_size & 0xffff)); |
|
883 for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) |
|
884 tcg_out32 (s, (STW |
|
885 | RS (tcg_target_callee_save_regs[i]) |
|
886 | RA (1) |
|
887 | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) |
|
888 ) |
|
889 ); |
|
890 tcg_out32 (s, STW | RS (0) | RA (1) | (frame_size + LR_OFFSET)); |
|
891 |
|
892 tcg_out32 (s, MTSPR | RS (3) | CTR); |
|
893 tcg_out32 (s, BCCTR | BO_ALWAYS); |
|
894 tb_ret_addr = s->code_ptr; |
|
895 |
|
896 for (i = 0; i < ARRAY_SIZE (tcg_target_callee_save_regs); ++i) |
|
897 tcg_out32 (s, (LWZ |
|
898 | RT (tcg_target_callee_save_regs[i]) |
|
899 | RA (1) |
|
900 | (i * 4 + LINKAGE_AREA_SIZE + TCG_STATIC_CALL_ARGS_SIZE) |
|
901 ) |
|
902 ); |
|
903 tcg_out32 (s, LWZ | RT (0) | RA (1) | (frame_size + LR_OFFSET)); |
|
904 tcg_out32 (s, MTSPR | RS (0) | LR); |
|
905 tcg_out32 (s, ADDI | RT (1) | RA (1) | frame_size); |
|
906 tcg_out32 (s, BCLR | BO_ALWAYS); |
|
907 } |
|
908 |
|
909 static void tcg_out_ld (TCGContext *s, TCGType type, int ret, int arg1, |
|
910 tcg_target_long arg2) |
|
911 { |
|
912 tcg_out_ldst (s, ret, arg1, arg2, LWZ, LWZX); |
|
913 } |
|
914 |
|
915 static void tcg_out_st (TCGContext *s, TCGType type, int arg, int arg1, |
|
916 tcg_target_long arg2) |
|
917 { |
|
918 tcg_out_ldst (s, arg, arg1, arg2, STW, STWX); |
|
919 } |
|
920 |
|
921 static void ppc_addi (TCGContext *s, int rt, int ra, tcg_target_long si) |
|
922 { |
|
923 if (!si && rt == ra) |
|
924 return; |
|
925 |
|
926 if (si == (int16_t) si) |
|
927 tcg_out32 (s, ADDI | RT (rt) | RA (ra) | (si & 0xffff)); |
|
928 else { |
|
929 uint16_t h = ((si >> 16) & 0xffff) + ((uint16_t) si >> 15); |
|
930 tcg_out32 (s, ADDIS | RT (rt) | RA (ra) | h); |
|
931 tcg_out32 (s, ADDI | RT (rt) | RA (rt) | (si & 0xffff)); |
|
932 } |
|
933 } |
|
934 |
|
935 static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) |
|
936 { |
|
937 ppc_addi (s, reg, reg, val); |
|
938 } |
|
939 |
|
940 static void tcg_out_cmp (TCGContext *s, int cond, TCGArg arg1, TCGArg arg2, |
|
941 int const_arg2, int cr) |
|
942 { |
|
943 int imm; |
|
944 uint32_t op; |
|
945 |
|
946 switch (cond) { |
|
947 case TCG_COND_EQ: |
|
948 case TCG_COND_NE: |
|
949 if (const_arg2) { |
|
950 if ((int16_t) arg2 == arg2) { |
|
951 op = CMPI; |
|
952 imm = 1; |
|
953 break; |
|
954 } |
|
955 else if ((uint16_t) arg2 == arg2) { |
|
956 op = CMPLI; |
|
957 imm = 1; |
|
958 break; |
|
959 } |
|
960 } |
|
961 op = CMPL; |
|
962 imm = 0; |
|
963 break; |
|
964 |
|
965 case TCG_COND_LT: |
|
966 case TCG_COND_GE: |
|
967 case TCG_COND_LE: |
|
968 case TCG_COND_GT: |
|
969 if (const_arg2) { |
|
970 if ((int16_t) arg2 == arg2) { |
|
971 op = CMPI; |
|
972 imm = 1; |
|
973 break; |
|
974 } |
|
975 } |
|
976 op = CMP; |
|
977 imm = 0; |
|
978 break; |
|
979 |
|
980 case TCG_COND_LTU: |
|
981 case TCG_COND_GEU: |
|
982 case TCG_COND_LEU: |
|
983 case TCG_COND_GTU: |
|
984 if (const_arg2) { |
|
985 if ((uint16_t) arg2 == arg2) { |
|
986 op = CMPLI; |
|
987 imm = 1; |
|
988 break; |
|
989 } |
|
990 } |
|
991 op = CMPL; |
|
992 imm = 0; |
|
993 break; |
|
994 |
|
995 default: |
|
996 tcg_abort (); |
|
997 } |
|
998 op |= BF (cr); |
|
999 |
|
1000 if (imm) |
|
1001 tcg_out32 (s, op | RA (arg1) | (arg2 & 0xffff)); |
|
1002 else { |
|
1003 if (const_arg2) { |
|
1004 tcg_out_movi (s, TCG_TYPE_I32, 0, arg2); |
|
1005 tcg_out32 (s, op | RA (arg1) | RB (0)); |
|
1006 } |
|
1007 else |
|
1008 tcg_out32 (s, op | RA (arg1) | RB (arg2)); |
|
1009 } |
|
1010 |
|
1011 } |
|
1012 |
|
1013 static void tcg_out_bc (TCGContext *s, int bc, int label_index) |
|
1014 { |
|
1015 TCGLabel *l = &s->labels[label_index]; |
|
1016 |
|
1017 if (l->has_value) |
|
1018 tcg_out32 (s, bc | reloc_pc14_val (s->code_ptr, l->u.value)); |
|
1019 else { |
|
1020 uint16_t val = *(uint16_t *) &s->code_ptr[2]; |
|
1021 |
|
1022 /* Thanks to Andrzej Zaborowski */ |
|
1023 tcg_out32 (s, bc | (val & 0xfffc)); |
|
1024 tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL14, label_index, 0); |
|
1025 } |
|
1026 } |
|
1027 |
|
1028 static void tcg_out_brcond (TCGContext *s, int cond, |
|
1029 TCGArg arg1, TCGArg arg2, int const_arg2, |
|
1030 int label_index) |
|
1031 { |
|
1032 tcg_out_cmp (s, cond, arg1, arg2, const_arg2, 7); |
|
1033 tcg_out_bc (s, tcg_to_bc[cond], label_index); |
|
1034 } |
|
1035 |
|
1036 /* XXX: we implement it at the target level to avoid having to |
|
1037 handle cross basic blocks temporaries */ |
|
1038 static void tcg_out_brcond2 (TCGContext *s, const TCGArg *args, |
|
1039 const int *const_args) |
|
1040 { |
|
1041 int cond = args[4], label_index = args[5], op; |
|
1042 struct { int bit1; int bit2; int cond2; } bits[] = { |
|
1043 [TCG_COND_LT ] = { CR_LT, CR_LT, TCG_COND_LT }, |
|
1044 [TCG_COND_LE ] = { CR_LT, CR_GT, TCG_COND_LT }, |
|
1045 [TCG_COND_GT ] = { CR_GT, CR_GT, TCG_COND_GT }, |
|
1046 [TCG_COND_GE ] = { CR_GT, CR_LT, TCG_COND_GT }, |
|
1047 [TCG_COND_LTU] = { CR_LT, CR_LT, TCG_COND_LTU }, |
|
1048 [TCG_COND_LEU] = { CR_LT, CR_GT, TCG_COND_LTU }, |
|
1049 [TCG_COND_GTU] = { CR_GT, CR_GT, TCG_COND_GTU }, |
|
1050 [TCG_COND_GEU] = { CR_GT, CR_LT, TCG_COND_GTU }, |
|
1051 }, *b = &bits[cond]; |
|
1052 |
|
1053 switch (cond) { |
|
1054 case TCG_COND_EQ: |
|
1055 case TCG_COND_NE: |
|
1056 op = (cond == TCG_COND_EQ) ? CRAND : CRNAND; |
|
1057 tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 6); |
|
1058 tcg_out_cmp (s, cond, args[1], args[3], const_args[3], 7); |
|
1059 tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, CR_EQ)); |
|
1060 break; |
|
1061 case TCG_COND_LT: |
|
1062 case TCG_COND_LE: |
|
1063 case TCG_COND_GT: |
|
1064 case TCG_COND_GE: |
|
1065 case TCG_COND_LTU: |
|
1066 case TCG_COND_LEU: |
|
1067 case TCG_COND_GTU: |
|
1068 case TCG_COND_GEU: |
|
1069 op = (b->bit1 != b->bit2) ? CRANDC : CRAND; |
|
1070 tcg_out_cmp (s, b->cond2, args[1], args[3], const_args[3], 5); |
|
1071 tcg_out_cmp (s, TCG_COND_EQ, args[1], args[3], const_args[3], 6); |
|
1072 tcg_out_cmp (s, cond, args[0], args[2], const_args[2], 7); |
|
1073 tcg_out32 (s, op | BT (7, CR_EQ) | BA (6, CR_EQ) | BB (7, b->bit2)); |
|
1074 tcg_out32 (s, CROR | BT (7, CR_EQ) | BA (5, b->bit1) | BB (7, CR_EQ)); |
|
1075 break; |
|
1076 default: |
|
1077 tcg_abort(); |
|
1078 } |
|
1079 |
|
1080 tcg_out_bc (s, (BC | BI (7, CR_EQ) | BO_COND_TRUE), label_index); |
|
1081 } |
|
1082 |
|
1083 void ppc_tb_set_jmp_target (unsigned long jmp_addr, unsigned long addr) |
|
1084 { |
|
1085 uint32_t *ptr; |
|
1086 long disp = addr - jmp_addr; |
|
1087 unsigned long patch_size; |
|
1088 |
|
1089 ptr = (uint32_t *)jmp_addr; |
|
1090 |
|
1091 if ((disp << 6) >> 6 != disp) { |
|
1092 ptr[0] = 0x3c000000 | (addr >> 16); /* lis 0,addr@ha */ |
|
1093 ptr[1] = 0x60000000 | (addr & 0xffff); /* la 0,addr@l(0) */ |
|
1094 ptr[2] = 0x7c0903a6; /* mtctr 0 */ |
|
1095 ptr[3] = 0x4e800420; /* brctr */ |
|
1096 patch_size = 16; |
|
1097 } else { |
|
1098 /* patch the branch destination */ |
|
1099 if (disp != 16) { |
|
1100 *ptr = 0x48000000 | (disp & 0x03fffffc); /* b disp */ |
|
1101 patch_size = 4; |
|
1102 } else { |
|
1103 ptr[0] = 0x60000000; /* nop */ |
|
1104 ptr[1] = 0x60000000; |
|
1105 ptr[2] = 0x60000000; |
|
1106 ptr[3] = 0x60000000; |
|
1107 patch_size = 16; |
|
1108 } |
|
1109 } |
|
1110 /* flush icache */ |
|
1111 flush_icache_range(jmp_addr, jmp_addr + patch_size); |
|
1112 } |
|
1113 |
|
1114 static void tcg_out_op(TCGContext *s, int opc, const TCGArg *args, |
|
1115 const int *const_args) |
|
1116 { |
|
1117 switch (opc) { |
|
1118 case INDEX_op_exit_tb: |
|
1119 tcg_out_movi (s, TCG_TYPE_I32, TCG_REG_R3, args[0]); |
|
1120 tcg_out_b (s, 0, (tcg_target_long) tb_ret_addr); |
|
1121 break; |
|
1122 case INDEX_op_goto_tb: |
|
1123 if (s->tb_jmp_offset) { |
|
1124 /* direct jump method */ |
|
1125 |
|
1126 s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; |
|
1127 s->code_ptr += 16; |
|
1128 } |
|
1129 else { |
|
1130 tcg_abort (); |
|
1131 } |
|
1132 s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; |
|
1133 break; |
|
1134 case INDEX_op_br: |
|
1135 { |
|
1136 TCGLabel *l = &s->labels[args[0]]; |
|
1137 |
|
1138 if (l->has_value) { |
|
1139 tcg_out_b (s, 0, l->u.value); |
|
1140 } |
|
1141 else { |
|
1142 uint32_t val = *(uint32_t *) s->code_ptr; |
|
1143 |
|
1144 /* Thanks to Andrzej Zaborowski */ |
|
1145 tcg_out32 (s, B | (val & 0x3fffffc)); |
|
1146 tcg_out_reloc (s, s->code_ptr - 4, R_PPC_REL24, args[0], 0); |
|
1147 } |
|
1148 } |
|
1149 break; |
|
1150 case INDEX_op_call: |
|
1151 #ifdef _AIX |
|
1152 tcg_out_call (s, args[0], const_args[0]); |
|
1153 #else |
|
1154 if (const_args[0]) { |
|
1155 tcg_out_b (s, LK, args[0]); |
|
1156 } |
|
1157 else { |
|
1158 tcg_out32 (s, MTSPR | RS (args[0]) | LR); |
|
1159 tcg_out32 (s, BCLR | BO_ALWAYS | LK); |
|
1160 } |
|
1161 #endif |
|
1162 break; |
|
1163 case INDEX_op_jmp: |
|
1164 if (const_args[0]) { |
|
1165 tcg_out_b (s, 0, args[0]); |
|
1166 } |
|
1167 else { |
|
1168 tcg_out32 (s, MTSPR | RS (args[0]) | CTR); |
|
1169 tcg_out32 (s, BCCTR | BO_ALWAYS); |
|
1170 } |
|
1171 break; |
|
1172 case INDEX_op_movi_i32: |
|
1173 tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]); |
|
1174 break; |
|
1175 case INDEX_op_ld8u_i32: |
|
1176 tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); |
|
1177 break; |
|
1178 case INDEX_op_ld8s_i32: |
|
1179 tcg_out_ldst (s, args[0], args[1], args[2], LBZ, LBZX); |
|
1180 tcg_out32 (s, EXTSB | RS (args[0]) | RA (args[0])); |
|
1181 break; |
|
1182 case INDEX_op_ld16u_i32: |
|
1183 tcg_out_ldst (s, args[0], args[1], args[2], LHZ, LHZX); |
|
1184 break; |
|
1185 case INDEX_op_ld16s_i32: |
|
1186 tcg_out_ldst (s, args[0], args[1], args[2], LHA, LHAX); |
|
1187 break; |
|
1188 case INDEX_op_ld_i32: |
|
1189 tcg_out_ldst (s, args[0], args[1], args[2], LWZ, LWZX); |
|
1190 break; |
|
1191 case INDEX_op_st8_i32: |
|
1192 tcg_out_ldst (s, args[0], args[1], args[2], STB, STBX); |
|
1193 break; |
|
1194 case INDEX_op_st16_i32: |
|
1195 tcg_out_ldst (s, args[0], args[1], args[2], STH, STHX); |
|
1196 break; |
|
1197 case INDEX_op_st_i32: |
|
1198 tcg_out_ldst (s, args[0], args[1], args[2], STW, STWX); |
|
1199 break; |
|
1200 |
|
1201 case INDEX_op_add_i32: |
|
1202 if (const_args[2]) |
|
1203 ppc_addi (s, args[0], args[1], args[2]); |
|
1204 else |
|
1205 tcg_out32 (s, ADD | TAB (args[0], args[1], args[2])); |
|
1206 break; |
|
1207 case INDEX_op_sub_i32: |
|
1208 if (const_args[2]) |
|
1209 ppc_addi (s, args[0], args[1], -args[2]); |
|
1210 else |
|
1211 tcg_out32 (s, SUBF | TAB (args[0], args[2], args[1])); |
|
1212 break; |
|
1213 |
|
1214 case INDEX_op_and_i32: |
|
1215 if (const_args[2]) { |
|
1216 if ((args[2] & 0xffff) == args[2]) |
|
1217 tcg_out32 (s, ANDI | RS (args[1]) | RA (args[0]) | args[2]); |
|
1218 else if ((args[2] & 0xffff0000) == args[2]) |
|
1219 tcg_out32 (s, ANDIS | RS (args[1]) | RA (args[0]) |
|
1220 | ((args[2] >> 16) & 0xffff)); |
|
1221 else { |
|
1222 tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); |
|
1223 tcg_out32 (s, AND | SAB (args[1], args[0], 0)); |
|
1224 } |
|
1225 } |
|
1226 else |
|
1227 tcg_out32 (s, AND | SAB (args[1], args[0], args[2])); |
|
1228 break; |
|
1229 case INDEX_op_or_i32: |
|
1230 if (const_args[2]) { |
|
1231 if (args[2] & 0xffff) { |
|
1232 tcg_out32 (s, ORI | RS (args[1]) | RA (args[0]) |
|
1233 | (args[2] & 0xffff)); |
|
1234 if (args[2] >> 16) |
|
1235 tcg_out32 (s, ORIS | RS (args[0]) | RA (args[0]) |
|
1236 | ((args[2] >> 16) & 0xffff)); |
|
1237 } |
|
1238 else { |
|
1239 tcg_out32 (s, ORIS | RS (args[1]) | RA (args[0]) |
|
1240 | ((args[2] >> 16) & 0xffff)); |
|
1241 } |
|
1242 } |
|
1243 else |
|
1244 tcg_out32 (s, OR | SAB (args[1], args[0], args[2])); |
|
1245 break; |
|
1246 case INDEX_op_xor_i32: |
|
1247 if (const_args[2]) { |
|
1248 if ((args[2] & 0xffff) == args[2]) |
|
1249 tcg_out32 (s, XORI | RS (args[1]) | RA (args[0]) |
|
1250 | (args[2] & 0xffff)); |
|
1251 else if ((args[2] & 0xffff0000) == args[2]) |
|
1252 tcg_out32 (s, XORIS | RS (args[1]) | RA (args[0]) |
|
1253 | ((args[2] >> 16) & 0xffff)); |
|
1254 else { |
|
1255 tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); |
|
1256 tcg_out32 (s, XOR | SAB (args[1], args[0], 0)); |
|
1257 } |
|
1258 } |
|
1259 else |
|
1260 tcg_out32 (s, XOR | SAB (args[1], args[0], args[2])); |
|
1261 break; |
|
1262 |
|
1263 case INDEX_op_mul_i32: |
|
1264 if (const_args[2]) { |
|
1265 if (args[2] == (int16_t) args[2]) |
|
1266 tcg_out32 (s, MULLI | RT (args[0]) | RA (args[1]) |
|
1267 | (args[2] & 0xffff)); |
|
1268 else { |
|
1269 tcg_out_movi (s, TCG_TYPE_I32, 0, args[2]); |
|
1270 tcg_out32 (s, MULLW | TAB (args[0], args[1], 0)); |
|
1271 } |
|
1272 } |
|
1273 else |
|
1274 tcg_out32 (s, MULLW | TAB (args[0], args[1], args[2])); |
|
1275 break; |
|
1276 |
|
1277 case INDEX_op_div_i32: |
|
1278 tcg_out32 (s, DIVW | TAB (args[0], args[1], args[2])); |
|
1279 break; |
|
1280 |
|
1281 case INDEX_op_divu_i32: |
|
1282 tcg_out32 (s, DIVWU | TAB (args[0], args[1], args[2])); |
|
1283 break; |
|
1284 |
|
1285 case INDEX_op_rem_i32: |
|
1286 tcg_out32 (s, DIVW | TAB (0, args[1], args[2])); |
|
1287 tcg_out32 (s, MULLW | TAB (0, 0, args[2])); |
|
1288 tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); |
|
1289 break; |
|
1290 |
|
1291 case INDEX_op_remu_i32: |
|
1292 tcg_out32 (s, DIVWU | TAB (0, args[1], args[2])); |
|
1293 tcg_out32 (s, MULLW | TAB (0, 0, args[2])); |
|
1294 tcg_out32 (s, SUBF | TAB (args[0], 0, args[1])); |
|
1295 break; |
|
1296 |
|
1297 case INDEX_op_mulu2_i32: |
|
1298 if (args[0] == args[2] || args[0] == args[3]) { |
|
1299 tcg_out32 (s, MULLW | TAB (0, args[2], args[3])); |
|
1300 tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); |
|
1301 tcg_out_mov (s, args[0], 0); |
|
1302 } |
|
1303 else { |
|
1304 tcg_out32 (s, MULLW | TAB (args[0], args[2], args[3])); |
|
1305 tcg_out32 (s, MULHWU | TAB (args[1], args[2], args[3])); |
|
1306 } |
|
1307 break; |
|
1308 |
|
1309 case INDEX_op_shl_i32: |
|
1310 if (const_args[2]) { |
|
1311 tcg_out32 (s, (RLWINM |
|
1312 | RA (args[0]) |
|
1313 | RS (args[1]) |
|
1314 | SH (args[2]) |
|
1315 | MB (0) |
|
1316 | ME (31 - args[2]) |
|
1317 ) |
|
1318 ); |
|
1319 } |
|
1320 else |
|
1321 tcg_out32 (s, SLW | SAB (args[1], args[0], args[2])); |
|
1322 break; |
|
1323 case INDEX_op_shr_i32: |
|
1324 if (const_args[2]) { |
|
1325 tcg_out32 (s, (RLWINM |
|
1326 | RA (args[0]) |
|
1327 | RS (args[1]) |
|
1328 | SH (32 - args[2]) |
|
1329 | MB (args[2]) |
|
1330 | ME (31) |
|
1331 ) |
|
1332 ); |
|
1333 } |
|
1334 else |
|
1335 tcg_out32 (s, SRW | SAB (args[1], args[0], args[2])); |
|
1336 break; |
|
1337 case INDEX_op_sar_i32: |
|
1338 if (const_args[2]) |
|
1339 tcg_out32 (s, SRAWI | RS (args[1]) | RA (args[0]) | SH (args[2])); |
|
1340 else |
|
1341 tcg_out32 (s, SRAW | SAB (args[1], args[0], args[2])); |
|
1342 break; |
|
1343 |
|
1344 case INDEX_op_add2_i32: |
|
1345 if (args[0] == args[3] || args[0] == args[5]) { |
|
1346 tcg_out32 (s, ADDC | TAB (0, args[2], args[4])); |
|
1347 tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); |
|
1348 tcg_out_mov (s, args[0], 0); |
|
1349 } |
|
1350 else { |
|
1351 tcg_out32 (s, ADDC | TAB (args[0], args[2], args[4])); |
|
1352 tcg_out32 (s, ADDE | TAB (args[1], args[3], args[5])); |
|
1353 } |
|
1354 break; |
|
1355 case INDEX_op_sub2_i32: |
|
1356 if (args[0] == args[3] || args[0] == args[5]) { |
|
1357 tcg_out32 (s, SUBFC | TAB (0, args[4], args[2])); |
|
1358 tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); |
|
1359 tcg_out_mov (s, args[0], 0); |
|
1360 } |
|
1361 else { |
|
1362 tcg_out32 (s, SUBFC | TAB (args[0], args[4], args[2])); |
|
1363 tcg_out32 (s, SUBFE | TAB (args[1], args[5], args[3])); |
|
1364 } |
|
1365 break; |
|
1366 |
|
1367 case INDEX_op_brcond_i32: |
|
1368 /* |
|
1369 args[0] = r0 |
|
1370 args[1] = r1 |
|
1371 args[2] = cond |
|
1372 args[3] = r1 is const |
|
1373 args[4] = label_index |
|
1374 */ |
|
1375 tcg_out_brcond (s, args[2], args[0], args[1], const_args[1], args[3]); |
|
1376 break; |
|
1377 case INDEX_op_brcond2_i32: |
|
1378 tcg_out_brcond2(s, args, const_args); |
|
1379 break; |
|
1380 |
|
1381 case INDEX_op_neg_i32: |
|
1382 tcg_out32 (s, NEG | RT (args[0]) | RA (args[1])); |
|
1383 break; |
|
1384 |
|
1385 case INDEX_op_qemu_ld8u: |
|
1386 tcg_out_qemu_ld(s, args, 0); |
|
1387 break; |
|
1388 case INDEX_op_qemu_ld8s: |
|
1389 tcg_out_qemu_ld(s, args, 0 | 4); |
|
1390 break; |
|
1391 case INDEX_op_qemu_ld16u: |
|
1392 tcg_out_qemu_ld(s, args, 1); |
|
1393 break; |
|
1394 case INDEX_op_qemu_ld16s: |
|
1395 tcg_out_qemu_ld(s, args, 1 | 4); |
|
1396 break; |
|
1397 case INDEX_op_qemu_ld32u: |
|
1398 tcg_out_qemu_ld(s, args, 2); |
|
1399 break; |
|
1400 case INDEX_op_qemu_ld64: |
|
1401 tcg_out_qemu_ld(s, args, 3); |
|
1402 break; |
|
1403 case INDEX_op_qemu_st8: |
|
1404 tcg_out_qemu_st(s, args, 0); |
|
1405 break; |
|
1406 case INDEX_op_qemu_st16: |
|
1407 tcg_out_qemu_st(s, args, 1); |
|
1408 break; |
|
1409 case INDEX_op_qemu_st32: |
|
1410 tcg_out_qemu_st(s, args, 2); |
|
1411 break; |
|
1412 case INDEX_op_qemu_st64: |
|
1413 tcg_out_qemu_st(s, args, 3); |
|
1414 break; |
|
1415 |
|
1416 case INDEX_op_ext8s_i32: |
|
1417 tcg_out32 (s, EXTSB | RS (args[1]) | RA (args[0])); |
|
1418 break; |
|
1419 case INDEX_op_ext16s_i32: |
|
1420 tcg_out32 (s, EXTSH | RS (args[1]) | RA (args[0])); |
|
1421 break; |
|
1422 |
|
1423 default: |
|
1424 tcg_dump_ops (s, stderr); |
|
1425 tcg_abort (); |
|
1426 } |
|
1427 } |
|
1428 |
|
1429 static const TCGTargetOpDef ppc_op_defs[] = { |
|
1430 { INDEX_op_exit_tb, { } }, |
|
1431 { INDEX_op_goto_tb, { } }, |
|
1432 { INDEX_op_call, { "ri" } }, |
|
1433 { INDEX_op_jmp, { "ri" } }, |
|
1434 { INDEX_op_br, { } }, |
|
1435 |
|
1436 { INDEX_op_mov_i32, { "r", "r" } }, |
|
1437 { INDEX_op_movi_i32, { "r" } }, |
|
1438 { INDEX_op_ld8u_i32, { "r", "r" } }, |
|
1439 { INDEX_op_ld8s_i32, { "r", "r" } }, |
|
1440 { INDEX_op_ld16u_i32, { "r", "r" } }, |
|
1441 { INDEX_op_ld16s_i32, { "r", "r" } }, |
|
1442 { INDEX_op_ld_i32, { "r", "r" } }, |
|
1443 { INDEX_op_st8_i32, { "r", "r" } }, |
|
1444 { INDEX_op_st16_i32, { "r", "r" } }, |
|
1445 { INDEX_op_st_i32, { "r", "r" } }, |
|
1446 |
|
1447 { INDEX_op_add_i32, { "r", "r", "ri" } }, |
|
1448 { INDEX_op_mul_i32, { "r", "r", "ri" } }, |
|
1449 { INDEX_op_div_i32, { "r", "r", "r" } }, |
|
1450 { INDEX_op_divu_i32, { "r", "r", "r" } }, |
|
1451 { INDEX_op_rem_i32, { "r", "r", "r" } }, |
|
1452 { INDEX_op_remu_i32, { "r", "r", "r" } }, |
|
1453 { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } }, |
|
1454 { INDEX_op_sub_i32, { "r", "r", "ri" } }, |
|
1455 { INDEX_op_and_i32, { "r", "r", "ri" } }, |
|
1456 { INDEX_op_or_i32, { "r", "r", "ri" } }, |
|
1457 { INDEX_op_xor_i32, { "r", "r", "ri" } }, |
|
1458 |
|
1459 { INDEX_op_shl_i32, { "r", "r", "ri" } }, |
|
1460 { INDEX_op_shr_i32, { "r", "r", "ri" } }, |
|
1461 { INDEX_op_sar_i32, { "r", "r", "ri" } }, |
|
1462 |
|
1463 { INDEX_op_brcond_i32, { "r", "ri" } }, |
|
1464 |
|
1465 { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } }, |
|
1466 { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } }, |
|
1467 { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } }, |
|
1468 |
|
1469 { INDEX_op_neg_i32, { "r", "r" } }, |
|
1470 |
|
1471 #if TARGET_LONG_BITS == 32 |
|
1472 { INDEX_op_qemu_ld8u, { "r", "L" } }, |
|
1473 { INDEX_op_qemu_ld8s, { "r", "L" } }, |
|
1474 { INDEX_op_qemu_ld16u, { "r", "L" } }, |
|
1475 { INDEX_op_qemu_ld16s, { "r", "L" } }, |
|
1476 { INDEX_op_qemu_ld32u, { "r", "L" } }, |
|
1477 { INDEX_op_qemu_ld32s, { "r", "L" } }, |
|
1478 { INDEX_op_qemu_ld64, { "r", "r", "L" } }, |
|
1479 |
|
1480 { INDEX_op_qemu_st8, { "K", "K" } }, |
|
1481 { INDEX_op_qemu_st16, { "K", "K" } }, |
|
1482 { INDEX_op_qemu_st32, { "K", "K" } }, |
|
1483 { INDEX_op_qemu_st64, { "M", "M", "M" } }, |
|
1484 #else |
|
1485 { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, |
|
1486 { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, |
|
1487 { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, |
|
1488 { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, |
|
1489 { INDEX_op_qemu_ld32u, { "r", "L", "L" } }, |
|
1490 { INDEX_op_qemu_ld32s, { "r", "L", "L" } }, |
|
1491 { INDEX_op_qemu_ld64, { "r", "L", "L", "L" } }, |
|
1492 |
|
1493 { INDEX_op_qemu_st8, { "K", "K", "K" } }, |
|
1494 { INDEX_op_qemu_st16, { "K", "K", "K" } }, |
|
1495 { INDEX_op_qemu_st32, { "K", "K", "K" } }, |
|
1496 { INDEX_op_qemu_st64, { "M", "M", "M", "M" } }, |
|
1497 #endif |
|
1498 |
|
1499 { INDEX_op_ext8s_i32, { "r", "r" } }, |
|
1500 { INDEX_op_ext16s_i32, { "r", "r" } }, |
|
1501 |
|
1502 { -1 }, |
|
1503 }; |
|
1504 |
|
1505 void tcg_target_init(TCGContext *s) |
|
1506 { |
|
1507 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xffffffff); |
|
1508 tcg_regset_set32(tcg_target_call_clobber_regs, 0, |
|
1509 (1 << TCG_REG_R0) | |
|
1510 #ifdef __APPLE__ |
|
1511 (1 << TCG_REG_R2) | |
|
1512 #endif |
|
1513 (1 << TCG_REG_R3) | |
|
1514 (1 << TCG_REG_R4) | |
|
1515 (1 << TCG_REG_R5) | |
|
1516 (1 << TCG_REG_R6) | |
|
1517 (1 << TCG_REG_R7) | |
|
1518 (1 << TCG_REG_R8) | |
|
1519 (1 << TCG_REG_R9) | |
|
1520 (1 << TCG_REG_R10) | |
|
1521 (1 << TCG_REG_R11) | |
|
1522 (1 << TCG_REG_R12) |
|
1523 ); |
|
1524 |
|
1525 tcg_regset_clear(s->reserved_regs); |
|
1526 tcg_regset_set_reg(s->reserved_regs, TCG_REG_R0); |
|
1527 tcg_regset_set_reg(s->reserved_regs, TCG_REG_R1); |
|
1528 #ifndef __APPLE__ |
|
1529 tcg_regset_set_reg(s->reserved_regs, TCG_REG_R2); |
|
1530 #endif |
|
1531 |
|
1532 tcg_add_target_add_op_defs(ppc_op_defs); |
|
1533 } |