|
|
1.1 root 1: /*
2: * Tiny Code Generator for QEMU
3: *
4: * Copyright (c) 2008 Andrzej Zaborowski
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: #ifndef NDEBUG
26: static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
27: "%r0",
28: "%r1",
29: "%r2",
30: "%r3",
31: "%r4",
32: "%r5",
33: "%r6",
34: "%r7",
35: "%r8",
36: "%r9",
37: "%r10",
38: "%r11",
39: "%r12",
40: "%r13",
41: "%r14",
42: };
43: #endif
44:
45: static const int tcg_target_reg_alloc_order[] = {
46: TCG_REG_R0,
47: TCG_REG_R1,
48: TCG_REG_R2,
49: TCG_REG_R3,
50: TCG_REG_R4,
51: TCG_REG_R5,
52: TCG_REG_R6,
53: TCG_REG_R7,
54: TCG_REG_R8,
55: TCG_REG_R9,
56: TCG_REG_R10,
57: TCG_REG_R11,
58: TCG_REG_R12,
59: TCG_REG_R13,
60: TCG_REG_R14,
61: };
62:
63: static const int tcg_target_call_iarg_regs[4] = {
64: TCG_REG_R0, TCG_REG_R1, TCG_REG_R2, TCG_REG_R3
65: };
66: static const int tcg_target_call_oarg_regs[2] = {
67: TCG_REG_R0, TCG_REG_R1
68: };
69:
70: static void patch_reloc(uint8_t *code_ptr, int type,
71: tcg_target_long value, tcg_target_long addend)
72: {
73: switch (type) {
74: case R_ARM_ABS32:
75: *(uint32_t *) code_ptr = value;
76: break;
77:
78: case R_ARM_CALL:
79: case R_ARM_JUMP24:
80: default:
81: tcg_abort();
82:
83: case R_ARM_PC24:
84: *(uint32_t *) code_ptr = ((*(uint32_t *) code_ptr) & 0xff000000) |
85: (((value - ((tcg_target_long) code_ptr + 8)) >> 2) & 0xffffff);
86: break;
87: }
88: }
89:
90: /* maximum number of register used for input function arguments */
91: static inline int tcg_target_get_call_iarg_regs_count(int flags)
92: {
93: return 4;
94: }
95:
96: /* parse target specific constraints */
97: static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
98: {
99: const char *ct_str;
100:
101: ct_str = *pct_str;
102: switch (ct_str[0]) {
103: case 'r':
104: #ifndef CONFIG_SOFTMMU
105: case 'd':
106: case 'D':
107: case 'x':
108: case 'X':
109: #endif
110: ct->ct |= TCG_CT_REG;
111: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
112: break;
113:
114: #ifdef CONFIG_SOFTMMU
115: /* qemu_ld/st inputs (unless 'X', 'd' or 'D') */
116: case 'x':
117: ct->ct |= TCG_CT_REG;
118: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
119: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
120: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
121: break;
122:
123: /* qemu_ld64 data_reg */
124: case 'd':
125: ct->ct |= TCG_CT_REG;
126: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
127: /* r1 is still needed to load data_reg2, so don't use it. */
128: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
129: break;
130:
131: /* qemu_ld/st64 data_reg2 */
132: case 'D':
133: ct->ct |= TCG_CT_REG;
134: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
135: /* r0, r1 and optionally r2 will be overwritten by the address
136: * and the low word of data, so don't use these. */
137: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
138: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
139: # if TARGET_LONG_BITS == 64
140: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
141: # endif
142: break;
143:
144: # if TARGET_LONG_BITS == 64
145: /* qemu_ld/st addr_reg2 */
146: case 'X':
147: ct->ct |= TCG_CT_REG;
148: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
149: /* r0 will be overwritten by the low word of base, so don't use it. */
150: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
151: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
152: break;
153: # endif
154: #endif
155:
156: case '1':
157: ct->ct |= TCG_CT_REG;
158: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
159: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
160: break;
161:
162: case '2':
163: ct->ct |= TCG_CT_REG;
164: tcg_regset_set32(ct->u.regs, 0, (1 << TCG_TARGET_NB_REGS) - 1);
165: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
166: tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
167: break;
168:
169: default:
170: return -1;
171: }
172: ct_str++;
173: *pct_str = ct_str;
174:
175: return 0;
176: }
177:
178: /* Test if a constant matches the constraint.
179: * TODO: define constraints for:
180: *
181: * ldr/str offset: between -0xfff and 0xfff
182: * ldrh/strh offset: between -0xff and 0xff
183: * mov operand2: values represented with x << (2 * y), x < 0x100
184: * add, sub, eor...: ditto
185: */
186: static inline int tcg_target_const_match(tcg_target_long val,
187: const TCGArgConstraint *arg_ct)
188: {
189: int ct;
190: ct = arg_ct->ct;
191: if (ct & TCG_CT_CONST)
192: return 1;
193: else
194: return 0;
195: }
196:
197: enum arm_data_opc_e {
198: ARITH_AND = 0x0,
199: ARITH_EOR = 0x1,
200: ARITH_SUB = 0x2,
201: ARITH_RSB = 0x3,
202: ARITH_ADD = 0x4,
203: ARITH_ADC = 0x5,
204: ARITH_SBC = 0x6,
205: ARITH_RSC = 0x7,
206: ARITH_TST = 0x8,
207: ARITH_CMP = 0xa,
208: ARITH_CMN = 0xb,
209: ARITH_ORR = 0xc,
210: ARITH_MOV = 0xd,
211: ARITH_BIC = 0xe,
212: ARITH_MVN = 0xf,
213: };
214:
215: #define TO_CPSR(opc) \
216: ((opc == ARITH_CMP || opc == ARITH_CMN || opc == ARITH_TST) << 20)
217:
218: #define SHIFT_IMM_LSL(im) (((im) << 7) | 0x00)
219: #define SHIFT_IMM_LSR(im) (((im) << 7) | 0x20)
220: #define SHIFT_IMM_ASR(im) (((im) << 7) | 0x40)
221: #define SHIFT_IMM_ROR(im) (((im) << 7) | 0x60)
222: #define SHIFT_REG_LSL(rs) (((rs) << 8) | 0x10)
223: #define SHIFT_REG_LSR(rs) (((rs) << 8) | 0x30)
224: #define SHIFT_REG_ASR(rs) (((rs) << 8) | 0x50)
225: #define SHIFT_REG_ROR(rs) (((rs) << 8) | 0x70)
226:
227: enum arm_cond_code_e {
228: COND_EQ = 0x0,
229: COND_NE = 0x1,
230: COND_CS = 0x2, /* Unsigned greater or equal */
231: COND_CC = 0x3, /* Unsigned less than */
232: COND_MI = 0x4, /* Negative */
233: COND_PL = 0x5, /* Zero or greater */
234: COND_VS = 0x6, /* Overflow */
235: COND_VC = 0x7, /* No overflow */
236: COND_HI = 0x8, /* Unsigned greater than */
237: COND_LS = 0x9, /* Unsigned less or equal */
238: COND_GE = 0xa,
239: COND_LT = 0xb,
240: COND_GT = 0xc,
241: COND_LE = 0xd,
242: COND_AL = 0xe,
243: };
244:
245: static const uint8_t tcg_cond_to_arm_cond[10] = {
246: [TCG_COND_EQ] = COND_EQ,
247: [TCG_COND_NE] = COND_NE,
248: [TCG_COND_LT] = COND_LT,
249: [TCG_COND_GE] = COND_GE,
250: [TCG_COND_LE] = COND_LE,
251: [TCG_COND_GT] = COND_GT,
252: /* unsigned */
253: [TCG_COND_LTU] = COND_CC,
254: [TCG_COND_GEU] = COND_CS,
255: [TCG_COND_LEU] = COND_LS,
256: [TCG_COND_GTU] = COND_HI,
257: };
258:
259: static inline void tcg_out_bx(TCGContext *s, int cond, int rn)
260: {
261: tcg_out32(s, (cond << 28) | 0x012fff10 | rn);
262: }
263:
264: static inline void tcg_out_b(TCGContext *s, int cond, int32_t offset)
265: {
266: tcg_out32(s, (cond << 28) | 0x0a000000 |
267: (((offset - 8) >> 2) & 0x00ffffff));
268: }
269:
270: static inline void tcg_out_b_noaddr(TCGContext *s, int cond)
271: {
272: #ifdef WORDS_BIGENDIAN
273: tcg_out8(s, (cond << 4) | 0x0a);
274: s->code_ptr += 3;
275: #else
276: s->code_ptr += 3;
277: tcg_out8(s, (cond << 4) | 0x0a);
278: #endif
279: }
280:
281: static inline void tcg_out_bl(TCGContext *s, int cond, int32_t offset)
282: {
283: tcg_out32(s, (cond << 28) | 0x0b000000 |
284: (((offset - 8) >> 2) & 0x00ffffff));
285: }
286:
287: static inline void tcg_out_dat_reg(TCGContext *s,
288: int cond, int opc, int rd, int rn, int rm, int shift)
289: {
290: tcg_out32(s, (cond << 28) | (0 << 25) | (opc << 21) | TO_CPSR(opc) |
291: (rn << 16) | (rd << 12) | shift | rm);
292: }
293:
294: static inline void tcg_out_dat_reg2(TCGContext *s,
295: int cond, int opc0, int opc1, int rd0, int rd1,
296: int rn0, int rn1, int rm0, int rm1, int shift)
297: {
298: if (rd0 == rn1 || rd0 == rm1) {
299: tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
300: (rn0 << 16) | (8 << 12) | shift | rm0);
301: tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
302: (rn1 << 16) | (rd1 << 12) | shift | rm1);
303: tcg_out_dat_reg(s, cond, ARITH_MOV,
304: rd0, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
305: } else {
306: tcg_out32(s, (cond << 28) | (0 << 25) | (opc0 << 21) | (1 << 20) |
307: (rn0 << 16) | (rd0 << 12) | shift | rm0);
308: tcg_out32(s, (cond << 28) | (0 << 25) | (opc1 << 21) |
309: (rn1 << 16) | (rd1 << 12) | shift | rm1);
310: }
311: }
312:
313: static inline void tcg_out_dat_imm(TCGContext *s,
314: int cond, int opc, int rd, int rn, int im)
315: {
316: tcg_out32(s, (cond << 28) | (1 << 25) | (opc << 21) | TO_CPSR(opc) |
317: (rn << 16) | (rd << 12) | im);
318: }
319:
320: static inline void tcg_out_movi32(TCGContext *s,
321: int cond, int rd, int32_t arg)
322: {
323: int offset = (uint32_t) arg - ((uint32_t) s->code_ptr + 8);
324:
325: /* TODO: This is very suboptimal, we can easily have a constant
326: * pool somewhere after all the instructions. */
327:
328: if (arg < 0 && arg > -0x100)
329: return tcg_out_dat_imm(s, cond, ARITH_MVN, rd, 0, (~arg) & 0xff);
330:
331: if (offset < 0x100 && offset > -0x100)
332: return offset >= 0 ?
333: tcg_out_dat_imm(s, cond, ARITH_ADD, rd, 15, offset) :
334: tcg_out_dat_imm(s, cond, ARITH_SUB, rd, 15, -offset);
335:
336: tcg_out_dat_imm(s, cond, ARITH_MOV, rd, 0, arg & 0xff);
337: if (arg & 0x0000ff00)
338: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
339: ((arg >> 8) & 0xff) | 0xc00);
340: if (arg & 0x00ff0000)
341: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
342: ((arg >> 16) & 0xff) | 0x800);
343: if (arg & 0xff000000)
344: tcg_out_dat_imm(s, cond, ARITH_ORR, rd, rd,
345: ((arg >> 24) & 0xff) | 0x400);
346: }
347:
348: static inline void tcg_out_mul32(TCGContext *s,
349: int cond, int rd, int rs, int rm)
350: {
351: if (rd != rm)
352: tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
353: (rs << 8) | 0x90 | rm);
354: else if (rd != rs)
355: tcg_out32(s, (cond << 28) | (rd << 16) | (0 << 12) |
356: (rm << 8) | 0x90 | rs);
357: else {
358: tcg_out32(s, (cond << 28) | ( 8 << 16) | (0 << 12) |
359: (rs << 8) | 0x90 | rm);
360: tcg_out_dat_reg(s, cond, ARITH_MOV,
361: rd, 0, 8, SHIFT_IMM_LSL(0));
362: }
363: }
364:
365: static inline void tcg_out_umull32(TCGContext *s,
366: int cond, int rd0, int rd1, int rs, int rm)
367: {
368: if (rd0 != rm && rd1 != rm)
369: tcg_out32(s, (cond << 28) | 0x800090 |
370: (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
371: else if (rd0 != rs && rd1 != rs)
372: tcg_out32(s, (cond << 28) | 0x800090 |
373: (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
374: else {
375: tcg_out_dat_reg(s, cond, ARITH_MOV,
376: TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
377: tcg_out32(s, (cond << 28) | 0x800098 |
378: (rd1 << 16) | (rd0 << 12) | (rs << 8));
379: }
380: }
381:
382: static inline void tcg_out_smull32(TCGContext *s,
383: int cond, int rd0, int rd1, int rs, int rm)
384: {
385: if (rd0 != rm && rd1 != rm)
386: tcg_out32(s, (cond << 28) | 0xc00090 |
387: (rd1 << 16) | (rd0 << 12) | (rs << 8) | rm);
388: else if (rd0 != rs && rd1 != rs)
389: tcg_out32(s, (cond << 28) | 0xc00090 |
390: (rd1 << 16) | (rd0 << 12) | (rm << 8) | rs);
391: else {
392: tcg_out_dat_reg(s, cond, ARITH_MOV,
393: TCG_REG_R8, 0, rm, SHIFT_IMM_LSL(0));
394: tcg_out32(s, (cond << 28) | 0xc00098 |
395: (rd1 << 16) | (rd0 << 12) | (rs << 8));
396: }
397: }
398:
399: static inline void tcg_out_ld32_12(TCGContext *s, int cond,
400: int rd, int rn, tcg_target_long im)
401: {
402: if (im >= 0)
403: tcg_out32(s, (cond << 28) | 0x05900000 |
404: (rn << 16) | (rd << 12) | (im & 0xfff));
405: else
406: tcg_out32(s, (cond << 28) | 0x05100000 |
407: (rn << 16) | (rd << 12) | ((-im) & 0xfff));
408: }
409:
410: static inline void tcg_out_st32_12(TCGContext *s, int cond,
411: int rd, int rn, tcg_target_long im)
412: {
413: if (im >= 0)
414: tcg_out32(s, (cond << 28) | 0x05800000 |
415: (rn << 16) | (rd << 12) | (im & 0xfff));
416: else
417: tcg_out32(s, (cond << 28) | 0x05000000 |
418: (rn << 16) | (rd << 12) | ((-im) & 0xfff));
419: }
420:
421: static inline void tcg_out_ld32_r(TCGContext *s, int cond,
422: int rd, int rn, int rm)
423: {
424: tcg_out32(s, (cond << 28) | 0x07900000 |
425: (rn << 16) | (rd << 12) | rm);
426: }
427:
428: static inline void tcg_out_st32_r(TCGContext *s, int cond,
429: int rd, int rn, int rm)
430: {
431: tcg_out32(s, (cond << 28) | 0x07800000 |
432: (rn << 16) | (rd << 12) | rm);
433: }
434:
435: /* Register pre-increment with base writeback. */
436: static inline void tcg_out_ld32_rwb(TCGContext *s, int cond,
437: int rd, int rn, int rm)
438: {
439: tcg_out32(s, (cond << 28) | 0x07b00000 |
440: (rn << 16) | (rd << 12) | rm);
441: }
442:
443: static inline void tcg_out_st32_rwb(TCGContext *s, int cond,
444: int rd, int rn, int rm)
445: {
446: tcg_out32(s, (cond << 28) | 0x07a00000 |
447: (rn << 16) | (rd << 12) | rm);
448: }
449:
450: static inline void tcg_out_ld16u_8(TCGContext *s, int cond,
451: int rd, int rn, tcg_target_long im)
452: {
453: if (im >= 0)
454: tcg_out32(s, (cond << 28) | 0x01d000b0 |
455: (rn << 16) | (rd << 12) |
456: ((im & 0xf0) << 4) | (im & 0xf));
457: else
458: tcg_out32(s, (cond << 28) | 0x015000b0 |
459: (rn << 16) | (rd << 12) |
460: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
461: }
462:
463: static inline void tcg_out_st16u_8(TCGContext *s, int cond,
464: int rd, int rn, tcg_target_long im)
465: {
466: if (im >= 0)
467: tcg_out32(s, (cond << 28) | 0x01c000b0 |
468: (rn << 16) | (rd << 12) |
469: ((im & 0xf0) << 4) | (im & 0xf));
470: else
471: tcg_out32(s, (cond << 28) | 0x014000b0 |
472: (rn << 16) | (rd << 12) |
473: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
474: }
475:
476: static inline void tcg_out_ld16u_r(TCGContext *s, int cond,
477: int rd, int rn, int rm)
478: {
479: tcg_out32(s, (cond << 28) | 0x019000b0 |
480: (rn << 16) | (rd << 12) | rm);
481: }
482:
483: static inline void tcg_out_st16u_r(TCGContext *s, int cond,
484: int rd, int rn, int rm)
485: {
486: tcg_out32(s, (cond << 28) | 0x018000b0 |
487: (rn << 16) | (rd << 12) | rm);
488: }
489:
490: static inline void tcg_out_ld16s_8(TCGContext *s, int cond,
491: int rd, int rn, tcg_target_long im)
492: {
493: if (im >= 0)
494: tcg_out32(s, (cond << 28) | 0x01d000f0 |
495: (rn << 16) | (rd << 12) |
496: ((im & 0xf0) << 4) | (im & 0xf));
497: else
498: tcg_out32(s, (cond << 28) | 0x015000f0 |
499: (rn << 16) | (rd << 12) |
500: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
501: }
502:
503: static inline void tcg_out_st16s_8(TCGContext *s, int cond,
504: int rd, int rn, tcg_target_long im)
505: {
506: if (im >= 0)
507: tcg_out32(s, (cond << 28) | 0x01c000f0 |
508: (rn << 16) | (rd << 12) |
509: ((im & 0xf0) << 4) | (im & 0xf));
510: else
511: tcg_out32(s, (cond << 28) | 0x014000f0 |
512: (rn << 16) | (rd << 12) |
513: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
514: }
515:
516: static inline void tcg_out_ld16s_r(TCGContext *s, int cond,
517: int rd, int rn, int rm)
518: {
519: tcg_out32(s, (cond << 28) | 0x019000f0 |
520: (rn << 16) | (rd << 12) | rm);
521: }
522:
523: static inline void tcg_out_st16s_r(TCGContext *s, int cond,
524: int rd, int rn, int rm)
525: {
526: tcg_out32(s, (cond << 28) | 0x018000f0 |
527: (rn << 16) | (rd << 12) | rm);
528: }
529:
530: static inline void tcg_out_ld8_12(TCGContext *s, int cond,
531: int rd, int rn, tcg_target_long im)
532: {
533: if (im >= 0)
534: tcg_out32(s, (cond << 28) | 0x05d00000 |
535: (rn << 16) | (rd << 12) | (im & 0xfff));
536: else
537: tcg_out32(s, (cond << 28) | 0x05500000 |
538: (rn << 16) | (rd << 12) | ((-im) & 0xfff));
539: }
540:
541: static inline void tcg_out_st8_12(TCGContext *s, int cond,
542: int rd, int rn, tcg_target_long im)
543: {
544: if (im >= 0)
545: tcg_out32(s, (cond << 28) | 0x05c00000 |
546: (rn << 16) | (rd << 12) | (im & 0xfff));
547: else
548: tcg_out32(s, (cond << 28) | 0x05400000 |
549: (rn << 16) | (rd << 12) | ((-im) & 0xfff));
550: }
551:
552: static inline void tcg_out_ld8_r(TCGContext *s, int cond,
553: int rd, int rn, int rm)
554: {
555: tcg_out32(s, (cond << 28) | 0x07d00000 |
556: (rn << 16) | (rd << 12) | rm);
557: }
558:
559: static inline void tcg_out_st8_r(TCGContext *s, int cond,
560: int rd, int rn, int rm)
561: {
562: tcg_out32(s, (cond << 28) | 0x07c00000 |
563: (rn << 16) | (rd << 12) | rm);
564: }
565:
566: static inline void tcg_out_ld8s_8(TCGContext *s, int cond,
567: int rd, int rn, tcg_target_long im)
568: {
569: if (im >= 0)
570: tcg_out32(s, (cond << 28) | 0x01d000d0 |
571: (rn << 16) | (rd << 12) |
572: ((im & 0xf0) << 4) | (im & 0xf));
573: else
574: tcg_out32(s, (cond << 28) | 0x015000d0 |
575: (rn << 16) | (rd << 12) |
576: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
577: }
578:
579: static inline void tcg_out_st8s_8(TCGContext *s, int cond,
580: int rd, int rn, tcg_target_long im)
581: {
582: if (im >= 0)
583: tcg_out32(s, (cond << 28) | 0x01c000d0 |
584: (rn << 16) | (rd << 12) |
585: ((im & 0xf0) << 4) | (im & 0xf));
586: else
587: tcg_out32(s, (cond << 28) | 0x014000d0 |
588: (rn << 16) | (rd << 12) |
589: (((-im) & 0xf0) << 4) | ((-im) & 0xf));
590: }
591:
592: static inline void tcg_out_ld8s_r(TCGContext *s, int cond,
593: int rd, int rn, int rm)
594: {
595: tcg_out32(s, (cond << 28) | 0x019000d0 |
596: (rn << 16) | (rd << 12) | rm);
597: }
598:
599: static inline void tcg_out_st8s_r(TCGContext *s, int cond,
600: int rd, int rn, int rm)
601: {
602: tcg_out32(s, (cond << 28) | 0x018000d0 |
603: (rn << 16) | (rd << 12) | rm);
604: }
605:
606: static inline void tcg_out_ld32u(TCGContext *s, int cond,
607: int rd, int rn, int32_t offset)
608: {
609: if (offset > 0xfff || offset < -0xfff) {
610: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
611: tcg_out_ld32_r(s, cond, rd, rn, TCG_REG_R8);
612: } else
613: tcg_out_ld32_12(s, cond, rd, rn, offset);
614: }
615:
616: static inline void tcg_out_st32(TCGContext *s, int cond,
617: int rd, int rn, int32_t offset)
618: {
619: if (offset > 0xfff || offset < -0xfff) {
620: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
621: tcg_out_st32_r(s, cond, rd, rn, TCG_REG_R8);
622: } else
623: tcg_out_st32_12(s, cond, rd, rn, offset);
624: }
625:
626: static inline void tcg_out_ld16u(TCGContext *s, int cond,
627: int rd, int rn, int32_t offset)
628: {
629: if (offset > 0xff || offset < -0xff) {
630: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
631: tcg_out_ld16u_r(s, cond, rd, rn, TCG_REG_R8);
632: } else
633: tcg_out_ld16u_8(s, cond, rd, rn, offset);
634: }
635:
636: static inline void tcg_out_ld16s(TCGContext *s, int cond,
637: int rd, int rn, int32_t offset)
638: {
639: if (offset > 0xff || offset < -0xff) {
640: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
641: tcg_out_ld16s_r(s, cond, rd, rn, TCG_REG_R8);
642: } else
643: tcg_out_ld16s_8(s, cond, rd, rn, offset);
644: }
645:
646: static inline void tcg_out_st16u(TCGContext *s, int cond,
647: int rd, int rn, int32_t offset)
648: {
649: if (offset > 0xff || offset < -0xff) {
650: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
651: tcg_out_st16u_r(s, cond, rd, rn, TCG_REG_R8);
652: } else
653: tcg_out_st16u_8(s, cond, rd, rn, offset);
654: }
655:
656: static inline void tcg_out_ld8u(TCGContext *s, int cond,
657: int rd, int rn, int32_t offset)
658: {
659: if (offset > 0xfff || offset < -0xfff) {
660: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
661: tcg_out_ld8_r(s, cond, rd, rn, TCG_REG_R8);
662: } else
663: tcg_out_ld8_12(s, cond, rd, rn, offset);
664: }
665:
666: static inline void tcg_out_ld8s(TCGContext *s, int cond,
667: int rd, int rn, int32_t offset)
668: {
669: if (offset > 0xff || offset < -0xff) {
670: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
671: tcg_out_ld8s_r(s, cond, rd, rn, TCG_REG_R8);
672: } else
673: tcg_out_ld8s_8(s, cond, rd, rn, offset);
674: }
675:
676: static inline void tcg_out_st8u(TCGContext *s, int cond,
677: int rd, int rn, int32_t offset)
678: {
679: if (offset > 0xfff || offset < -0xfff) {
680: tcg_out_movi32(s, cond, TCG_REG_R8, offset);
681: tcg_out_st8_r(s, cond, rd, rn, TCG_REG_R8);
682: } else
683: tcg_out_st8_12(s, cond, rd, rn, offset);
684: }
685:
686: static inline void tcg_out_goto(TCGContext *s, int cond, uint32_t addr)
687: {
688: int32_t val;
689:
690: val = addr - (tcg_target_long) s->code_ptr;
691: if (val - 8 < 0x01fffffd && val - 8 > -0x01fffffd)
692: tcg_out_b(s, cond, val);
693: else {
694: #if 1
695: tcg_abort();
696: #else
697: if (cond == COND_AL) {
698: tcg_out_ld32_12(s, COND_AL, 15, 15, -4);
699: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
700: } else {
701: tcg_out_movi32(s, cond, TCG_REG_R8, val - 8);
702: tcg_out_dat_reg(s, cond, ARITH_ADD,
703: 15, 15, TCG_REG_R8, SHIFT_IMM_LSL(0));
704: }
705: #endif
706: }
707: }
708:
709: static inline void tcg_out_call(TCGContext *s, int cond, uint32_t addr)
710: {
711: int32_t val;
712:
713: #ifdef SAVE_LR
714: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0));
715: #endif
716:
717: val = addr - (tcg_target_long) s->code_ptr;
718: if (val < 0x01fffffd && val > -0x01fffffd)
719: tcg_out_bl(s, cond, val);
720: else {
721: #if 1
722: tcg_abort();
723: #else
724: if (cond == COND_AL) {
725: tcg_out_dat_imm(s, cond, ARITH_ADD, 14, 15, 4);
726: tcg_out_ld32_12(s, COND_AL, 15, 15, -4);
727: tcg_out32(s, addr); /* XXX: This is l->u.value, can we use it? */
728: } else {
729: tcg_out_movi32(s, cond, TCG_REG_R9, addr);
730: tcg_out_dat_imm(s, cond, ARITH_MOV, 14, 0, 15);
731: tcg_out_bx(s, cond, TCG_REG_R9);
732: }
733: #endif
734: }
735:
736: #ifdef SAVE_LR
737: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
738: #endif
739: }
740:
741: static inline void tcg_out_callr(TCGContext *s, int cond, int arg)
742: {
743: #ifdef SAVE_LR
744: tcg_out_dat_reg(s, cond, ARITH_MOV, TCG_REG_R8, 0, 14, SHIFT_IMM_LSL(0));
745: #endif
746: /* TODO: on ARMv5 and ARMv6 replace with tcg_out_blx(s, cond, arg); */
747: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 15, SHIFT_IMM_LSL(0));
748: tcg_out_bx(s, cond, arg);
749: #ifdef SAVE_LR
750: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, TCG_REG_R8, SHIFT_IMM_LSL(0));
751: #endif
752: }
753:
754: static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index)
755: {
756: TCGLabel *l = &s->labels[label_index];
757:
758: if (l->has_value)
759: tcg_out_goto(s, cond, l->u.value);
760: else if (cond == COND_AL) {
761: tcg_out_ld32_12(s, COND_AL, 15, 15, -4);
762: tcg_out_reloc(s, s->code_ptr, R_ARM_ABS32, label_index, 31337);
763: s->code_ptr += 4;
764: } else {
765: /* Probably this should be preferred even for COND_AL... */
766: tcg_out_reloc(s, s->code_ptr, R_ARM_PC24, label_index, 31337);
767: tcg_out_b_noaddr(s, cond);
768: }
769: }
770:
771: static void tcg_out_div_helper(TCGContext *s, int cond, const TCGArg *args,
772: void *helper_div, void *helper_rem, int shift)
773: {
774: int div_reg = args[0];
775: int rem_reg = args[1];
776:
777: /* stmdb sp!, { r0 - r3, ip, lr } */
778: /* (Note that we need an even number of registers as per EABI) */
779: tcg_out32(s, (cond << 28) | 0x092d500f);
780:
781: tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0));
782: tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0));
783: tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0));
784: tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift);
785:
786: tcg_out_call(s, cond, (uint32_t) helper_div);
787: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 0, SHIFT_IMM_LSL(0));
788:
789: /* ldmia sp, { r0 - r3, fp, lr } */
790: tcg_out32(s, (cond << 28) | 0x089d500f);
791:
792: tcg_out_dat_reg(s, cond, ARITH_MOV, 0, 0, args[2], SHIFT_IMM_LSL(0));
793: tcg_out_dat_reg(s, cond, ARITH_MOV, 1, 0, args[3], SHIFT_IMM_LSL(0));
794: tcg_out_dat_reg(s, cond, ARITH_MOV, 2, 0, args[4], SHIFT_IMM_LSL(0));
795: tcg_out_dat_reg(s, cond, ARITH_MOV, 3, 0, 2, shift);
796:
797: tcg_out_call(s, cond, (uint32_t) helper_rem);
798:
799: tcg_out_dat_reg(s, cond, ARITH_MOV, rem_reg, 0, 0, SHIFT_IMM_LSL(0));
800: tcg_out_dat_reg(s, cond, ARITH_MOV, div_reg, 0, 8, SHIFT_IMM_LSL(0));
801:
802: /* ldr r0, [sp], #4 */
803: if (rem_reg != 0 && div_reg != 0)
804: tcg_out32(s, (cond << 28) | 0x04bd0004);
805: /* ldr r1, [sp], #4 */
806: if (rem_reg != 1 && div_reg != 1)
807: tcg_out32(s, (cond << 28) | 0x04bd1004);
808: /* ldr r2, [sp], #4 */
809: if (rem_reg != 2 && div_reg != 2)
810: tcg_out32(s, (cond << 28) | 0x04bd2004);
811: /* ldr r3, [sp], #4 */
812: if (rem_reg != 3 && div_reg != 3)
813: tcg_out32(s, (cond << 28) | 0x04bd3004);
814: /* ldr ip, [sp], #4 */
815: if (rem_reg != 12 && div_reg != 12)
816: tcg_out32(s, (cond << 28) | 0x04bdc004);
817: /* ldr lr, [sp], #4 */
818: if (rem_reg != 14 && div_reg != 14)
819: tcg_out32(s, (cond << 28) | 0x04bde004);
820: }
821:
822: #ifdef CONFIG_SOFTMMU
823:
824: #include "../../softmmu_defs.h"
825:
826: static void *qemu_ld_helpers[4] = {
827: __ldb_mmu,
828: __ldw_mmu,
829: __ldl_mmu,
830: __ldq_mmu,
831: };
832:
833: static void *qemu_st_helpers[4] = {
834: __stb_mmu,
835: __stw_mmu,
836: __stl_mmu,
837: __stq_mmu,
838: };
839: #endif
840:
841: #define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
842:
843: static inline void tcg_out_qemu_ld(TCGContext *s, int cond,
844: const TCGArg *args, int opc)
845: {
846: int addr_reg, data_reg, data_reg2;
847: #ifdef CONFIG_SOFTMMU
848: int mem_index, s_bits;
849: # if TARGET_LONG_BITS == 64
850: int addr_reg2;
851: # endif
852: uint32_t *label_ptr;
853: #endif
854:
855: data_reg = *args++;
856: if (opc == 3)
857: data_reg2 = *args++;
858: else
859: data_reg2 = 0; /* surpress warning */
860: addr_reg = *args++;
861: #ifdef CONFIG_SOFTMMU
862: # if TARGET_LONG_BITS == 64
863: addr_reg2 = *args++;
864: # endif
865: mem_index = *args;
866: s_bits = opc & 3;
867:
868: /* Should generate something like the following:
869: * shr r8, addr_reg, #TARGET_PAGE_BITS
870: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
871: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
872: */
873: # if CPU_TLB_BITS > 8
874: # error
875: # endif
876: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
877: 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
878: tcg_out_dat_imm(s, COND_AL, ARITH_AND,
879: 0, 8, CPU_TLB_SIZE - 1);
880: tcg_out_dat_reg(s, COND_AL, ARITH_ADD,
881: 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
882: /* In the
883: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_read))]
884: * below, the offset is likely to exceed 12 bits if mem_index != 0 and
885: * not exceed otherwise, so use an
886: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
887: * before.
888: */
889: if (mem_index)
890: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0,
891: (mem_index << (TLB_SHIFT & 1)) |
892: ((16 - (TLB_SHIFT >> 1)) << 8));
893: tcg_out_ld32_12(s, COND_AL, 1, 0,
894: offsetof(CPUState, tlb_table[0][0].addr_read));
895: tcg_out_dat_reg(s, COND_AL, ARITH_CMP,
896: 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
897: /* Check alignment. */
898: if (s_bits)
899: tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
900: 0, addr_reg, (1 << s_bits) - 1);
901: # if TARGET_LONG_BITS == 64
902: /* XXX: possibly we could use a block data load or writeback in
903: * the first access. */
904: tcg_out_ld32_12(s, COND_EQ, 1, 0,
905: offsetof(CPUState, tlb_table[0][0].addr_read) + 4);
906: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP,
907: 0, 1, addr_reg2, SHIFT_IMM_LSL(0));
908: # endif
909: tcg_out_ld32_12(s, COND_EQ, 1, 0,
910: offsetof(CPUState, tlb_table[0][0].addend));
911:
912: switch (opc) {
913: case 0:
914: tcg_out_ld8_r(s, COND_EQ, data_reg, addr_reg, 1);
915: break;
916: case 0 | 4:
917: tcg_out_ld8s_r(s, COND_EQ, data_reg, addr_reg, 1);
918: break;
919: case 1:
920: tcg_out_ld16u_r(s, COND_EQ, data_reg, addr_reg, 1);
921: break;
922: case 1 | 4:
923: tcg_out_ld16s_r(s, COND_EQ, data_reg, addr_reg, 1);
924: break;
925: case 2:
926: default:
927: tcg_out_ld32_r(s, COND_EQ, data_reg, addr_reg, 1);
928: break;
929: case 3:
930: tcg_out_ld32_rwb(s, COND_EQ, data_reg, 1, addr_reg);
931: tcg_out_ld32_12(s, COND_EQ, data_reg2, 1, 4);
932: break;
933: }
934:
935: label_ptr = (void *) s->code_ptr;
936: tcg_out_b(s, COND_EQ, 8);
937:
938: # ifdef SAVE_LR
939: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0));
940: # endif
941:
942: /* TODO: move this code to where the constants pool will be */
943: if (addr_reg)
944: tcg_out_dat_reg(s, cond, ARITH_MOV,
945: 0, 0, addr_reg, SHIFT_IMM_LSL(0));
946: # if TARGET_LONG_BITS == 32
947: tcg_out_dat_imm(s, cond, ARITH_MOV, 1, 0, mem_index);
948: # else
949: if (addr_reg2 != 1)
950: tcg_out_dat_reg(s, cond, ARITH_MOV,
951: 1, 0, addr_reg2, SHIFT_IMM_LSL(0));
952: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
953: # endif
954: tcg_out_bl(s, cond, (tcg_target_long) qemu_ld_helpers[s_bits] -
955: (tcg_target_long) s->code_ptr);
956:
957: switch (opc) {
958: case 0 | 4:
959: tcg_out_dat_reg(s, cond, ARITH_MOV,
960: 0, 0, 0, SHIFT_IMM_LSL(24));
961: tcg_out_dat_reg(s, cond, ARITH_MOV,
962: data_reg, 0, 0, SHIFT_IMM_ASR(24));
963: break;
964: case 1 | 4:
965: tcg_out_dat_reg(s, cond, ARITH_MOV,
966: 0, 0, 0, SHIFT_IMM_LSL(16));
967: tcg_out_dat_reg(s, cond, ARITH_MOV,
968: data_reg, 0, 0, SHIFT_IMM_ASR(16));
969: break;
970: case 0:
971: case 1:
972: case 2:
973: default:
974: if (data_reg)
975: tcg_out_dat_reg(s, cond, ARITH_MOV,
976: data_reg, 0, 0, SHIFT_IMM_LSL(0));
977: break;
978: case 3:
979: if (data_reg != 0)
980: tcg_out_dat_reg(s, cond, ARITH_MOV,
981: data_reg, 0, 0, SHIFT_IMM_LSL(0));
982: if (data_reg2 != 1)
983: tcg_out_dat_reg(s, cond, ARITH_MOV,
984: data_reg2, 0, 1, SHIFT_IMM_LSL(0));
985: break;
986: }
987:
988: # ifdef SAVE_LR
989: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0));
990: # endif
991:
992: *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
993: #else
994: switch (opc) {
995: case 0:
996: tcg_out_ld8_12(s, COND_AL, data_reg, addr_reg, 0);
997: break;
998: case 0 | 4:
999: tcg_out_ld8s_8(s, COND_AL, data_reg, addr_reg, 0);
1000: break;
1001: case 1:
1002: tcg_out_ld16u_8(s, COND_AL, data_reg, addr_reg, 0);
1003: break;
1004: case 1 | 4:
1005: tcg_out_ld16s_8(s, COND_AL, data_reg, addr_reg, 0);
1006: break;
1007: case 2:
1008: default:
1009: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
1010: break;
1011: case 3:
1012: /* TODO: use block load -
1013: * check that data_reg2 > data_reg or the other way */
1.1.1.2 ! root 1014: if (data_reg == addr_reg) {
! 1015: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
! 1016: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
! 1017: } else {
! 1018: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
! 1019: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
! 1020: }
1.1 root 1021: break;
1022: }
1023: #endif
1024: }
1025:
1026: static inline void tcg_out_qemu_st(TCGContext *s, int cond,
1027: const TCGArg *args, int opc)
1028: {
1029: int addr_reg, data_reg, data_reg2;
1030: #ifdef CONFIG_SOFTMMU
1031: int mem_index, s_bits;
1032: # if TARGET_LONG_BITS == 64
1033: int addr_reg2;
1034: # endif
1035: uint32_t *label_ptr;
1036: #endif
1037:
1038: data_reg = *args++;
1039: if (opc == 3)
1040: data_reg2 = *args++;
1041: else
1042: data_reg2 = 0; /* surpress warning */
1043: addr_reg = *args++;
1044: #ifdef CONFIG_SOFTMMU
1045: # if TARGET_LONG_BITS == 64
1046: addr_reg2 = *args++;
1047: # endif
1048: mem_index = *args;
1049: s_bits = opc & 3;
1050:
1051: /* Should generate something like the following:
1052: * shr r8, addr_reg, #TARGET_PAGE_BITS
1053: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
1054: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
1055: */
1056: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1057: 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
1058: tcg_out_dat_imm(s, COND_AL, ARITH_AND,
1059: 0, 8, CPU_TLB_SIZE - 1);
1060: tcg_out_dat_reg(s, COND_AL, ARITH_ADD,
1061: 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
1062: /* In the
1063: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))]
1064: * below, the offset is likely to exceed 12 bits if mem_index != 0 and
1065: * not exceed otherwise, so use an
1066: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
1067: * before.
1068: */
1069: if (mem_index)
1070: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0,
1071: (mem_index << (TLB_SHIFT & 1)) |
1072: ((16 - (TLB_SHIFT >> 1)) << 8));
1073: tcg_out_ld32_12(s, COND_AL, 1, 0,
1074: offsetof(CPUState, tlb_table[0][0].addr_write));
1075: tcg_out_dat_reg(s, COND_AL, ARITH_CMP,
1076: 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
1077: /* Check alignment. */
1078: if (s_bits)
1079: tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
1080: 0, addr_reg, (1 << s_bits) - 1);
1081: # if TARGET_LONG_BITS == 64
1082: /* XXX: possibly we could use a block data load or writeback in
1083: * the first access. */
1084: tcg_out_ld32_12(s, COND_EQ, 1, 0,
1085: offsetof(CPUState, tlb_table[0][0].addr_write)
1086: + 4);
1087: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP,
1088: 0, 1, addr_reg2, SHIFT_IMM_LSL(0));
1089: # endif
1090: tcg_out_ld32_12(s, COND_EQ, 1, 0,
1091: offsetof(CPUState, tlb_table[0][0].addend));
1092:
1093: switch (opc) {
1094: case 0:
1095: tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1);
1096: break;
1097: case 0 | 4:
1098: tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1);
1099: break;
1100: case 1:
1101: tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1);
1102: break;
1103: case 1 | 4:
1104: tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1);
1105: break;
1106: case 2:
1107: default:
1108: tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1);
1109: break;
1110: case 3:
1111: tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg);
1112: tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4);
1113: break;
1114: }
1115:
1116: label_ptr = (void *) s->code_ptr;
1117: tcg_out_b(s, COND_EQ, 8);
1118:
1119: /* TODO: move this code to where the constants pool will be */
1120: if (addr_reg)
1121: tcg_out_dat_reg(s, cond, ARITH_MOV,
1122: 0, 0, addr_reg, SHIFT_IMM_LSL(0));
1123: # if TARGET_LONG_BITS == 32
1124: switch (opc) {
1125: case 0:
1126: tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff);
1127: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1128: break;
1129: case 1:
1130: tcg_out_dat_reg(s, cond, ARITH_MOV,
1131: 1, 0, data_reg, SHIFT_IMM_LSL(16));
1132: tcg_out_dat_reg(s, cond, ARITH_MOV,
1133: 1, 0, 1, SHIFT_IMM_LSR(16));
1134: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1135: break;
1136: case 2:
1137: if (data_reg != 1)
1138: tcg_out_dat_reg(s, cond, ARITH_MOV,
1139: 1, 0, data_reg, SHIFT_IMM_LSL(0));
1140: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1141: break;
1142: case 3:
1143: if (data_reg != 1)
1144: tcg_out_dat_reg(s, cond, ARITH_MOV,
1145: 1, 0, data_reg, SHIFT_IMM_LSL(0));
1146: if (data_reg2 != 2)
1147: tcg_out_dat_reg(s, cond, ARITH_MOV,
1148: 2, 0, data_reg2, SHIFT_IMM_LSL(0));
1149: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1150: break;
1151: }
1152: # else
1153: if (addr_reg2 != 1)
1154: tcg_out_dat_reg(s, cond, ARITH_MOV,
1155: 1, 0, addr_reg2, SHIFT_IMM_LSL(0));
1156: switch (opc) {
1157: case 0:
1158: tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff);
1159: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1160: break;
1161: case 1:
1162: tcg_out_dat_reg(s, cond, ARITH_MOV,
1163: 2, 0, data_reg, SHIFT_IMM_LSL(16));
1164: tcg_out_dat_reg(s, cond, ARITH_MOV,
1165: 2, 0, 2, SHIFT_IMM_LSR(16));
1166: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1167: break;
1168: case 2:
1169: if (data_reg != 2)
1170: tcg_out_dat_reg(s, cond, ARITH_MOV,
1171: 2, 0, data_reg, SHIFT_IMM_LSL(0));
1172: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1173: break;
1174: case 3:
1175: tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index);
1176: tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
1177: if (data_reg != 2)
1178: tcg_out_dat_reg(s, cond, ARITH_MOV,
1179: 2, 0, data_reg, SHIFT_IMM_LSL(0));
1180: if (data_reg2 != 3)
1181: tcg_out_dat_reg(s, cond, ARITH_MOV,
1182: 3, 0, data_reg2, SHIFT_IMM_LSL(0));
1183: break;
1184: }
1185: # endif
1186:
1187: # ifdef SAVE_LR
1188: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0));
1189: # endif
1190:
1191: tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] -
1192: (tcg_target_long) s->code_ptr);
1193: # if TARGET_LONG_BITS == 64
1194: if (opc == 3)
1195: tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10);
1196: # endif
1197:
1198: # ifdef SAVE_LR
1199: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0));
1200: # endif
1201:
1202: *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
1203: #else
1204: switch (opc) {
1205: case 0:
1206: tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
1207: break;
1208: case 0 | 4:
1209: tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0);
1210: break;
1211: case 1:
1212: tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0);
1213: break;
1214: case 1 | 4:
1215: tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0);
1216: break;
1217: case 2:
1218: default:
1219: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1220: break;
1221: case 3:
1222: /* TODO: use block store -
1223: * check that data_reg2 > data_reg or the other way */
1224: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1225: tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4);
1226: break;
1227: }
1228: #endif
1229: }
1230:
1231: static uint8_t *tb_ret_addr;
1232:
1233: static inline void tcg_out_op(TCGContext *s, int opc,
1234: const TCGArg *args, const int *const_args)
1235: {
1236: int c;
1237:
1238: switch (opc) {
1239: case INDEX_op_exit_tb:
1240: #ifdef SAVE_LR
1241: if (args[0] >> 8)
1242: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0);
1243: else
1244: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]);
1245: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0));
1246: if (args[0] >> 8)
1247: tcg_out32(s, args[0]);
1248: #else
1249: {
1250: uint8_t *ld_ptr = s->code_ptr;
1251: if (args[0] >> 8)
1252: tcg_out_ld32_12(s, COND_AL, 0, 15, 0);
1253: else
1254: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]);
1255: tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
1256: if (args[0] >> 8) {
1257: *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
1258: tcg_out32(s, args[0]);
1259: }
1260: }
1261: #endif
1262: break;
1263: case INDEX_op_goto_tb:
1264: if (s->tb_jmp_offset) {
1265: /* Direct jump method */
1266: #if defined(USE_DIRECT_JUMP)
1267: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1268: tcg_out_b(s, COND_AL, 8);
1269: #else
1270: tcg_out_ld32_12(s, COND_AL, 15, 15, -4);
1271: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1272: tcg_out32(s, 0);
1273: #endif
1274: } else {
1275: /* Indirect jump method */
1276: #if 1
1277: c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8);
1278: if (c > 0xfff || c < -0xfff) {
1279: tcg_out_movi32(s, COND_AL, TCG_REG_R0,
1280: (tcg_target_long) (s->tb_next + args[0]));
1281: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0);
1282: } else
1283: tcg_out_ld32_12(s, COND_AL, 15, 15, c);
1284: #else
1285: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0);
1286: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0);
1287: tcg_out32(s, (tcg_target_long) (s->tb_next + args[0]));
1288: #endif
1289: }
1290: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
1291: break;
1292: case INDEX_op_call:
1293: if (const_args[0])
1294: tcg_out_call(s, COND_AL, args[0]);
1295: else
1296: tcg_out_callr(s, COND_AL, args[0]);
1297: break;
1298: case INDEX_op_jmp:
1299: if (const_args[0])
1300: tcg_out_goto(s, COND_AL, args[0]);
1301: else
1302: tcg_out_bx(s, COND_AL, args[0]);
1303: break;
1304: case INDEX_op_br:
1305: tcg_out_goto_label(s, COND_AL, args[0]);
1306: break;
1307:
1308: case INDEX_op_ld8u_i32:
1309: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
1310: break;
1311: case INDEX_op_ld8s_i32:
1312: tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
1313: break;
1314: case INDEX_op_ld16u_i32:
1315: tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
1316: break;
1317: case INDEX_op_ld16s_i32:
1318: tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
1319: break;
1320: case INDEX_op_ld_i32:
1321: tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
1322: break;
1323: case INDEX_op_st8_i32:
1324: tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]);
1325: break;
1326: case INDEX_op_st16_i32:
1327: tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]);
1328: break;
1329: case INDEX_op_st_i32:
1330: tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
1331: break;
1332:
1333: case INDEX_op_mov_i32:
1334: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1335: args[0], 0, args[1], SHIFT_IMM_LSL(0));
1336: break;
1337: case INDEX_op_movi_i32:
1338: tcg_out_movi32(s, COND_AL, args[0], args[1]);
1339: break;
1340: case INDEX_op_add_i32:
1341: c = ARITH_ADD;
1342: goto gen_arith;
1343: case INDEX_op_sub_i32:
1344: c = ARITH_SUB;
1345: goto gen_arith;
1346: case INDEX_op_and_i32:
1347: c = ARITH_AND;
1348: goto gen_arith;
1349: case INDEX_op_or_i32:
1350: c = ARITH_ORR;
1351: goto gen_arith;
1352: case INDEX_op_xor_i32:
1353: c = ARITH_EOR;
1354: /* Fall through. */
1355: gen_arith:
1356: tcg_out_dat_reg(s, COND_AL, c,
1357: args[0], args[1], args[2], SHIFT_IMM_LSL(0));
1358: break;
1359: case INDEX_op_add2_i32:
1360: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC,
1361: args[0], args[1], args[2], args[3],
1362: args[4], args[5], SHIFT_IMM_LSL(0));
1363: break;
1364: case INDEX_op_sub2_i32:
1365: tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC,
1366: args[0], args[1], args[2], args[3],
1367: args[4], args[5], SHIFT_IMM_LSL(0));
1368: break;
1369: case INDEX_op_neg_i32:
1370: tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
1371: break;
1372: case INDEX_op_mul_i32:
1373: tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
1374: break;
1375: case INDEX_op_mulu2_i32:
1376: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
1377: break;
1378: case INDEX_op_div2_i32:
1379: tcg_out_div_helper(s, COND_AL, args,
1380: tcg_helper_div_i64, tcg_helper_rem_i64,
1381: SHIFT_IMM_ASR(31));
1382: break;
1383: case INDEX_op_divu2_i32:
1384: tcg_out_div_helper(s, COND_AL, args,
1385: tcg_helper_divu_i64, tcg_helper_remu_i64,
1386: SHIFT_IMM_LSR(31));
1387: break;
1388: /* XXX: Perhaps args[2] & 0x1f is wrong */
1389: case INDEX_op_shl_i32:
1390: c = const_args[2] ?
1391: SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
1392: goto gen_shift32;
1393: case INDEX_op_shr_i32:
1394: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
1395: SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
1396: goto gen_shift32;
1397: case INDEX_op_sar_i32:
1398: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
1399: SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
1400: /* Fall through. */
1401: gen_shift32:
1402: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
1403: break;
1404:
1405: case INDEX_op_brcond_i32:
1406: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1407: args[0], args[1], SHIFT_IMM_LSL(0));
1408: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]);
1409: break;
1410: case INDEX_op_brcond2_i32:
1411: /* The resulting conditions are:
1412: * TCG_COND_EQ --> a0 == a2 && a1 == a3,
1413: * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
1414: * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
1415: * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
1416: * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
1417: * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
1418: */
1419: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1420: args[1], args[3], SHIFT_IMM_LSL(0));
1421: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1422: args[0], args[2], SHIFT_IMM_LSL(0));
1423: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]);
1424: break;
1425:
1426: case INDEX_op_qemu_ld8u:
1427: tcg_out_qemu_ld(s, COND_AL, args, 0);
1428: break;
1429: case INDEX_op_qemu_ld8s:
1430: tcg_out_qemu_ld(s, COND_AL, args, 0 | 4);
1431: break;
1432: case INDEX_op_qemu_ld16u:
1433: tcg_out_qemu_ld(s, COND_AL, args, 1);
1434: break;
1435: case INDEX_op_qemu_ld16s:
1436: tcg_out_qemu_ld(s, COND_AL, args, 1 | 4);
1437: break;
1438: case INDEX_op_qemu_ld32u:
1439: tcg_out_qemu_ld(s, COND_AL, args, 2);
1440: break;
1441: case INDEX_op_qemu_ld64:
1442: tcg_out_qemu_ld(s, COND_AL, args, 3);
1443: break;
1444:
1445: case INDEX_op_qemu_st8:
1446: tcg_out_qemu_st(s, COND_AL, args, 0);
1447: break;
1448: case INDEX_op_qemu_st16:
1449: tcg_out_qemu_st(s, COND_AL, args, 1);
1450: break;
1451: case INDEX_op_qemu_st32:
1452: tcg_out_qemu_st(s, COND_AL, args, 2);
1453: break;
1454: case INDEX_op_qemu_st64:
1455: tcg_out_qemu_st(s, COND_AL, args, 3);
1456: break;
1457:
1458: case INDEX_op_ext8s_i32:
1459: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1460: args[0], 0, args[1], SHIFT_IMM_LSL(24));
1461: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1462: args[0], 0, args[0], SHIFT_IMM_ASR(24));
1463: break;
1464: case INDEX_op_ext16s_i32:
1465: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1466: args[0], 0, args[1], SHIFT_IMM_LSL(16));
1467: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1468: args[0], 0, args[0], SHIFT_IMM_ASR(16));
1469: break;
1470:
1471: default:
1472: tcg_abort();
1473: }
1474: }
1475:
1476: static const TCGTargetOpDef arm_op_defs[] = {
1477: { INDEX_op_exit_tb, { } },
1478: { INDEX_op_goto_tb, { } },
1479: { INDEX_op_call, { "ri" } },
1480: { INDEX_op_jmp, { "ri" } },
1481: { INDEX_op_br, { } },
1482:
1483: { INDEX_op_mov_i32, { "r", "r" } },
1484: { INDEX_op_movi_i32, { "r" } },
1485:
1486: { INDEX_op_ld8u_i32, { "r", "r" } },
1487: { INDEX_op_ld8s_i32, { "r", "r" } },
1488: { INDEX_op_ld16u_i32, { "r", "r" } },
1489: { INDEX_op_ld16s_i32, { "r", "r" } },
1490: { INDEX_op_ld_i32, { "r", "r" } },
1491: { INDEX_op_st8_i32, { "r", "r" } },
1492: { INDEX_op_st16_i32, { "r", "r" } },
1493: { INDEX_op_st_i32, { "r", "r" } },
1494:
1495: /* TODO: "r", "r", "ri" */
1496: { INDEX_op_add_i32, { "r", "r", "r" } },
1497: { INDEX_op_sub_i32, { "r", "r", "r" } },
1498: { INDEX_op_mul_i32, { "r", "r", "r" } },
1499: { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
1500: { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } },
1501: { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } },
1502: { INDEX_op_and_i32, { "r", "r", "r" } },
1503: { INDEX_op_or_i32, { "r", "r", "r" } },
1504: { INDEX_op_xor_i32, { "r", "r", "r" } },
1505: { INDEX_op_neg_i32, { "r", "r" } },
1506:
1507: { INDEX_op_shl_i32, { "r", "r", "ri" } },
1508: { INDEX_op_shr_i32, { "r", "r", "ri" } },
1509: { INDEX_op_sar_i32, { "r", "r", "ri" } },
1510:
1511: { INDEX_op_brcond_i32, { "r", "r" } },
1512:
1513: /* TODO: "r", "r", "r", "r", "ri", "ri" */
1514: { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
1515: { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
1516: { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
1517:
1518: { INDEX_op_qemu_ld8u, { "r", "x", "X" } },
1519: { INDEX_op_qemu_ld8s, { "r", "x", "X" } },
1520: { INDEX_op_qemu_ld16u, { "r", "x", "X" } },
1521: { INDEX_op_qemu_ld16s, { "r", "x", "X" } },
1522: { INDEX_op_qemu_ld32u, { "r", "x", "X" } },
1523: { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } },
1524:
1525: { INDEX_op_qemu_st8, { "x", "x", "X" } },
1526: { INDEX_op_qemu_st16, { "x", "x", "X" } },
1527: { INDEX_op_qemu_st32, { "x", "x", "X" } },
1528: { INDEX_op_qemu_st64, { "x", "D", "x", "X" } },
1529:
1530: { INDEX_op_ext8s_i32, { "r", "r" } },
1531: { INDEX_op_ext16s_i32, { "r", "r" } },
1532:
1533: { -1 },
1534: };
1535:
1536: void tcg_target_init(TCGContext *s)
1537: {
1538: /* fail safe */
1539: if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
1540: tcg_abort();
1541:
1542: tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0,
1543: ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8));
1544: tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1545: ((2 << TCG_REG_R3) - 1) |
1546: (1 << TCG_REG_R12) | (1 << TCG_REG_R14));
1547:
1548: tcg_regset_clear(s->reserved_regs);
1549: #ifdef SAVE_LR
1550: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14);
1551: #endif
1552: tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
1553: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8);
1554:
1555: tcg_add_target_add_op_defs(arm_op_defs);
1556: }
1557:
1558: static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
1559: int arg1, tcg_target_long arg2)
1560: {
1561: tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
1562: }
1563:
1564: static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
1565: int arg1, tcg_target_long arg2)
1566: {
1567: tcg_out_st32(s, COND_AL, arg, arg1, arg2);
1568: }
1569:
1.1.1.2 ! root 1570: static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
1.1 root 1571: {
1572: if (val > 0)
1573: if (val < 0x100)
1574: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
1575: else
1576: tcg_abort();
1577: else if (val < 0) {
1578: if (val > -0x100)
1579: tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
1580: else
1581: tcg_abort();
1582: }
1583: }
1584:
1585: static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
1586: {
1587: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
1588: }
1589:
1590: static inline void tcg_out_movi(TCGContext *s, TCGType type,
1591: int ret, tcg_target_long arg)
1592: {
1593: tcg_out_movi32(s, COND_AL, ret, arg);
1594: }
1595:
1596: void tcg_target_qemu_prologue(TCGContext *s)
1597: {
1598: /* stmdb sp!, { r9 - r11, lr } */
1599: tcg_out32(s, (COND_AL << 28) | 0x092d4e00);
1600:
1601: tcg_out_bx(s, COND_AL, TCG_REG_R0);
1602: tb_ret_addr = s->code_ptr;
1603:
1604: /* ldmia sp!, { r9 - r11, pc } */
1605: tcg_out32(s, (COND_AL << 28) | 0x08bd8e00);
1606: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.