|
|
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 */
1014: tcg_out_ld32_12(s, COND_AL, data_reg, addr_reg, 0);
1015: tcg_out_ld32_12(s, COND_AL, data_reg2, addr_reg, 4);
1016: break;
1017: }
1018: #endif
1019: }
1020:
1021: static inline void tcg_out_qemu_st(TCGContext *s, int cond,
1022: const TCGArg *args, int opc)
1023: {
1024: int addr_reg, data_reg, data_reg2;
1025: #ifdef CONFIG_SOFTMMU
1026: int mem_index, s_bits;
1027: # if TARGET_LONG_BITS == 64
1028: int addr_reg2;
1029: # endif
1030: uint32_t *label_ptr;
1031: #endif
1032:
1033: data_reg = *args++;
1034: if (opc == 3)
1035: data_reg2 = *args++;
1036: else
1037: data_reg2 = 0; /* surpress warning */
1038: addr_reg = *args++;
1039: #ifdef CONFIG_SOFTMMU
1040: # if TARGET_LONG_BITS == 64
1041: addr_reg2 = *args++;
1042: # endif
1043: mem_index = *args;
1044: s_bits = opc & 3;
1045:
1046: /* Should generate something like the following:
1047: * shr r8, addr_reg, #TARGET_PAGE_BITS
1048: * and r0, r8, #(CPU_TLB_SIZE - 1) @ Assumption: CPU_TLB_BITS <= 8
1049: * add r0, env, r0 lsl #CPU_TLB_ENTRY_BITS
1050: */
1051: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1052: 8, 0, addr_reg, SHIFT_IMM_LSR(TARGET_PAGE_BITS));
1053: tcg_out_dat_imm(s, COND_AL, ARITH_AND,
1054: 0, 8, CPU_TLB_SIZE - 1);
1055: tcg_out_dat_reg(s, COND_AL, ARITH_ADD,
1056: 0, TCG_AREG0, 0, SHIFT_IMM_LSL(CPU_TLB_ENTRY_BITS));
1057: /* In the
1058: * ldr r1 [r0, #(offsetof(CPUState, tlb_table[mem_index][0].addr_write))]
1059: * below, the offset is likely to exceed 12 bits if mem_index != 0 and
1060: * not exceed otherwise, so use an
1061: * add r0, r0, #(mem_index * sizeof *CPUState.tlb_table)
1062: * before.
1063: */
1064: if (mem_index)
1065: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, 0, 0,
1066: (mem_index << (TLB_SHIFT & 1)) |
1067: ((16 - (TLB_SHIFT >> 1)) << 8));
1068: tcg_out_ld32_12(s, COND_AL, 1, 0,
1069: offsetof(CPUState, tlb_table[0][0].addr_write));
1070: tcg_out_dat_reg(s, COND_AL, ARITH_CMP,
1071: 0, 1, 8, SHIFT_IMM_LSL(TARGET_PAGE_BITS));
1072: /* Check alignment. */
1073: if (s_bits)
1074: tcg_out_dat_imm(s, COND_EQ, ARITH_TST,
1075: 0, addr_reg, (1 << s_bits) - 1);
1076: # if TARGET_LONG_BITS == 64
1077: /* XXX: possibly we could use a block data load or writeback in
1078: * the first access. */
1079: tcg_out_ld32_12(s, COND_EQ, 1, 0,
1080: offsetof(CPUState, tlb_table[0][0].addr_write)
1081: + 4);
1082: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP,
1083: 0, 1, addr_reg2, SHIFT_IMM_LSL(0));
1084: # endif
1085: tcg_out_ld32_12(s, COND_EQ, 1, 0,
1086: offsetof(CPUState, tlb_table[0][0].addend));
1087:
1088: switch (opc) {
1089: case 0:
1090: tcg_out_st8_r(s, COND_EQ, data_reg, addr_reg, 1);
1091: break;
1092: case 0 | 4:
1093: tcg_out_st8s_r(s, COND_EQ, data_reg, addr_reg, 1);
1094: break;
1095: case 1:
1096: tcg_out_st16u_r(s, COND_EQ, data_reg, addr_reg, 1);
1097: break;
1098: case 1 | 4:
1099: tcg_out_st16s_r(s, COND_EQ, data_reg, addr_reg, 1);
1100: break;
1101: case 2:
1102: default:
1103: tcg_out_st32_r(s, COND_EQ, data_reg, addr_reg, 1);
1104: break;
1105: case 3:
1106: tcg_out_st32_rwb(s, COND_EQ, data_reg, 1, addr_reg);
1107: tcg_out_st32_12(s, COND_EQ, data_reg2, 1, 4);
1108: break;
1109: }
1110:
1111: label_ptr = (void *) s->code_ptr;
1112: tcg_out_b(s, COND_EQ, 8);
1113:
1114: /* TODO: move this code to where the constants pool will be */
1115: if (addr_reg)
1116: tcg_out_dat_reg(s, cond, ARITH_MOV,
1117: 0, 0, addr_reg, SHIFT_IMM_LSL(0));
1118: # if TARGET_LONG_BITS == 32
1119: switch (opc) {
1120: case 0:
1121: tcg_out_dat_imm(s, cond, ARITH_AND, 1, data_reg, 0xff);
1122: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1123: break;
1124: case 1:
1125: tcg_out_dat_reg(s, cond, ARITH_MOV,
1126: 1, 0, data_reg, SHIFT_IMM_LSL(16));
1127: tcg_out_dat_reg(s, cond, ARITH_MOV,
1128: 1, 0, 1, SHIFT_IMM_LSR(16));
1129: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1130: break;
1131: case 2:
1132: if (data_reg != 1)
1133: tcg_out_dat_reg(s, cond, ARITH_MOV,
1134: 1, 0, data_reg, SHIFT_IMM_LSL(0));
1135: tcg_out_dat_imm(s, cond, ARITH_MOV, 2, 0, mem_index);
1136: break;
1137: case 3:
1138: if (data_reg != 1)
1139: tcg_out_dat_reg(s, cond, ARITH_MOV,
1140: 1, 0, data_reg, SHIFT_IMM_LSL(0));
1141: if (data_reg2 != 2)
1142: tcg_out_dat_reg(s, cond, ARITH_MOV,
1143: 2, 0, data_reg2, SHIFT_IMM_LSL(0));
1144: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1145: break;
1146: }
1147: # else
1148: if (addr_reg2 != 1)
1149: tcg_out_dat_reg(s, cond, ARITH_MOV,
1150: 1, 0, addr_reg2, SHIFT_IMM_LSL(0));
1151: switch (opc) {
1152: case 0:
1153: tcg_out_dat_imm(s, cond, ARITH_AND, 2, data_reg, 0xff);
1154: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1155: break;
1156: case 1:
1157: tcg_out_dat_reg(s, cond, ARITH_MOV,
1158: 2, 0, data_reg, SHIFT_IMM_LSL(16));
1159: tcg_out_dat_reg(s, cond, ARITH_MOV,
1160: 2, 0, 2, SHIFT_IMM_LSR(16));
1161: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1162: break;
1163: case 2:
1164: if (data_reg != 2)
1165: tcg_out_dat_reg(s, cond, ARITH_MOV,
1166: 2, 0, data_reg, SHIFT_IMM_LSL(0));
1167: tcg_out_dat_imm(s, cond, ARITH_MOV, 3, 0, mem_index);
1168: break;
1169: case 3:
1170: tcg_out_dat_imm(s, cond, ARITH_MOV, 8, 0, mem_index);
1171: tcg_out32(s, (cond << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
1172: if (data_reg != 2)
1173: tcg_out_dat_reg(s, cond, ARITH_MOV,
1174: 2, 0, data_reg, SHIFT_IMM_LSL(0));
1175: if (data_reg2 != 3)
1176: tcg_out_dat_reg(s, cond, ARITH_MOV,
1177: 3, 0, data_reg2, SHIFT_IMM_LSL(0));
1178: break;
1179: }
1180: # endif
1181:
1182: # ifdef SAVE_LR
1183: tcg_out_dat_reg(s, cond, ARITH_MOV, 8, 0, 14, SHIFT_IMM_LSL(0));
1184: # endif
1185:
1186: tcg_out_bl(s, cond, (tcg_target_long) qemu_st_helpers[s_bits] -
1187: (tcg_target_long) s->code_ptr);
1188: # if TARGET_LONG_BITS == 64
1189: if (opc == 3)
1190: tcg_out_dat_imm(s, cond, ARITH_ADD, 13, 13, 0x10);
1191: # endif
1192:
1193: # ifdef SAVE_LR
1194: tcg_out_dat_reg(s, cond, ARITH_MOV, 14, 0, 8, SHIFT_IMM_LSL(0));
1195: # endif
1196:
1197: *label_ptr += ((void *) s->code_ptr - (void *) label_ptr - 8) >> 2;
1198: #else
1199: switch (opc) {
1200: case 0:
1201: tcg_out_st8_12(s, COND_AL, data_reg, addr_reg, 0);
1202: break;
1203: case 0 | 4:
1204: tcg_out_st8s_8(s, COND_AL, data_reg, addr_reg, 0);
1205: break;
1206: case 1:
1207: tcg_out_st16u_8(s, COND_AL, data_reg, addr_reg, 0);
1208: break;
1209: case 1 | 4:
1210: tcg_out_st16s_8(s, COND_AL, data_reg, addr_reg, 0);
1211: break;
1212: case 2:
1213: default:
1214: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1215: break;
1216: case 3:
1217: /* TODO: use block store -
1218: * check that data_reg2 > data_reg or the other way */
1219: tcg_out_st32_12(s, COND_AL, data_reg, addr_reg, 0);
1220: tcg_out_st32_12(s, COND_AL, data_reg2, addr_reg, 4);
1221: break;
1222: }
1223: #endif
1224: }
1225:
1226: static uint8_t *tb_ret_addr;
1227:
1228: static inline void tcg_out_op(TCGContext *s, int opc,
1229: const TCGArg *args, const int *const_args)
1230: {
1231: int c;
1232:
1233: switch (opc) {
1234: case INDEX_op_exit_tb:
1235: #ifdef SAVE_LR
1236: if (args[0] >> 8)
1237: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0);
1238: else
1239: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R0, 0, args[0]);
1240: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, 15, 0, 14, SHIFT_IMM_LSL(0));
1241: if (args[0] >> 8)
1242: tcg_out32(s, args[0]);
1243: #else
1244: {
1245: uint8_t *ld_ptr = s->code_ptr;
1246: if (args[0] >> 8)
1247: tcg_out_ld32_12(s, COND_AL, 0, 15, 0);
1248: else
1249: tcg_out_dat_imm(s, COND_AL, ARITH_MOV, 0, 0, args[0]);
1250: tcg_out_goto(s, COND_AL, (tcg_target_ulong) tb_ret_addr);
1251: if (args[0] >> 8) {
1252: *ld_ptr = (uint8_t) (s->code_ptr - ld_ptr) - 8;
1253: tcg_out32(s, args[0]);
1254: }
1255: }
1256: #endif
1257: break;
1258: case INDEX_op_goto_tb:
1259: if (s->tb_jmp_offset) {
1260: /* Direct jump method */
1261: #if defined(USE_DIRECT_JUMP)
1262: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1263: tcg_out_b(s, COND_AL, 8);
1264: #else
1265: tcg_out_ld32_12(s, COND_AL, 15, 15, -4);
1266: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1267: tcg_out32(s, 0);
1268: #endif
1269: } else {
1270: /* Indirect jump method */
1271: #if 1
1272: c = (int) (s->tb_next + args[0]) - ((int) s->code_ptr + 8);
1273: if (c > 0xfff || c < -0xfff) {
1274: tcg_out_movi32(s, COND_AL, TCG_REG_R0,
1275: (tcg_target_long) (s->tb_next + args[0]));
1276: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0);
1277: } else
1278: tcg_out_ld32_12(s, COND_AL, 15, 15, c);
1279: #else
1280: tcg_out_ld32_12(s, COND_AL, TCG_REG_R0, 15, 0);
1281: tcg_out_ld32_12(s, COND_AL, 15, TCG_REG_R0, 0);
1282: tcg_out32(s, (tcg_target_long) (s->tb_next + args[0]));
1283: #endif
1284: }
1285: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
1286: break;
1287: case INDEX_op_call:
1288: if (const_args[0])
1289: tcg_out_call(s, COND_AL, args[0]);
1290: else
1291: tcg_out_callr(s, COND_AL, args[0]);
1292: break;
1293: case INDEX_op_jmp:
1294: if (const_args[0])
1295: tcg_out_goto(s, COND_AL, args[0]);
1296: else
1297: tcg_out_bx(s, COND_AL, args[0]);
1298: break;
1299: case INDEX_op_br:
1300: tcg_out_goto_label(s, COND_AL, args[0]);
1301: break;
1302:
1303: case INDEX_op_ld8u_i32:
1304: tcg_out_ld8u(s, COND_AL, args[0], args[1], args[2]);
1305: break;
1306: case INDEX_op_ld8s_i32:
1307: tcg_out_ld8s(s, COND_AL, args[0], args[1], args[2]);
1308: break;
1309: case INDEX_op_ld16u_i32:
1310: tcg_out_ld16u(s, COND_AL, args[0], args[1], args[2]);
1311: break;
1312: case INDEX_op_ld16s_i32:
1313: tcg_out_ld16s(s, COND_AL, args[0], args[1], args[2]);
1314: break;
1315: case INDEX_op_ld_i32:
1316: tcg_out_ld32u(s, COND_AL, args[0], args[1], args[2]);
1317: break;
1318: case INDEX_op_st8_i32:
1319: tcg_out_st8u(s, COND_AL, args[0], args[1], args[2]);
1320: break;
1321: case INDEX_op_st16_i32:
1322: tcg_out_st16u(s, COND_AL, args[0], args[1], args[2]);
1323: break;
1324: case INDEX_op_st_i32:
1325: tcg_out_st32(s, COND_AL, args[0], args[1], args[2]);
1326: break;
1327:
1328: case INDEX_op_mov_i32:
1329: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1330: args[0], 0, args[1], SHIFT_IMM_LSL(0));
1331: break;
1332: case INDEX_op_movi_i32:
1333: tcg_out_movi32(s, COND_AL, args[0], args[1]);
1334: break;
1335: case INDEX_op_add_i32:
1336: c = ARITH_ADD;
1337: goto gen_arith;
1338: case INDEX_op_sub_i32:
1339: c = ARITH_SUB;
1340: goto gen_arith;
1341: case INDEX_op_and_i32:
1342: c = ARITH_AND;
1343: goto gen_arith;
1344: case INDEX_op_or_i32:
1345: c = ARITH_ORR;
1346: goto gen_arith;
1347: case INDEX_op_xor_i32:
1348: c = ARITH_EOR;
1349: /* Fall through. */
1350: gen_arith:
1351: tcg_out_dat_reg(s, COND_AL, c,
1352: args[0], args[1], args[2], SHIFT_IMM_LSL(0));
1353: break;
1354: case INDEX_op_add2_i32:
1355: tcg_out_dat_reg2(s, COND_AL, ARITH_ADD, ARITH_ADC,
1356: args[0], args[1], args[2], args[3],
1357: args[4], args[5], SHIFT_IMM_LSL(0));
1358: break;
1359: case INDEX_op_sub2_i32:
1360: tcg_out_dat_reg2(s, COND_AL, ARITH_SUB, ARITH_SBC,
1361: args[0], args[1], args[2], args[3],
1362: args[4], args[5], SHIFT_IMM_LSL(0));
1363: break;
1364: case INDEX_op_neg_i32:
1365: tcg_out_dat_imm(s, COND_AL, ARITH_RSB, args[0], args[1], 0);
1366: break;
1367: case INDEX_op_mul_i32:
1368: tcg_out_mul32(s, COND_AL, args[0], args[1], args[2]);
1369: break;
1370: case INDEX_op_mulu2_i32:
1371: tcg_out_umull32(s, COND_AL, args[0], args[1], args[2], args[3]);
1372: break;
1373: case INDEX_op_div2_i32:
1374: tcg_out_div_helper(s, COND_AL, args,
1375: tcg_helper_div_i64, tcg_helper_rem_i64,
1376: SHIFT_IMM_ASR(31));
1377: break;
1378: case INDEX_op_divu2_i32:
1379: tcg_out_div_helper(s, COND_AL, args,
1380: tcg_helper_divu_i64, tcg_helper_remu_i64,
1381: SHIFT_IMM_LSR(31));
1382: break;
1383: /* XXX: Perhaps args[2] & 0x1f is wrong */
1384: case INDEX_op_shl_i32:
1385: c = const_args[2] ?
1386: SHIFT_IMM_LSL(args[2] & 0x1f) : SHIFT_REG_LSL(args[2]);
1387: goto gen_shift32;
1388: case INDEX_op_shr_i32:
1389: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_LSR(args[2] & 0x1f) :
1390: SHIFT_IMM_LSL(0) : SHIFT_REG_LSR(args[2]);
1391: goto gen_shift32;
1392: case INDEX_op_sar_i32:
1393: c = const_args[2] ? (args[2] & 0x1f) ? SHIFT_IMM_ASR(args[2] & 0x1f) :
1394: SHIFT_IMM_LSL(0) : SHIFT_REG_ASR(args[2]);
1395: /* Fall through. */
1396: gen_shift32:
1397: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, args[0], 0, args[1], c);
1398: break;
1399:
1400: case INDEX_op_brcond_i32:
1401: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1402: args[0], args[1], SHIFT_IMM_LSL(0));
1403: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[2]], args[3]);
1404: break;
1405: case INDEX_op_brcond2_i32:
1406: /* The resulting conditions are:
1407: * TCG_COND_EQ --> a0 == a2 && a1 == a3,
1408: * TCG_COND_NE --> (a0 != a2 && a1 == a3) || a1 != a3,
1409: * TCG_COND_LT(U) --> (a0 < a2 && a1 == a3) || a1 < a3,
1410: * TCG_COND_GE(U) --> (a0 >= a2 && a1 == a3) || (a1 >= a3 && a1 != a3),
1411: * TCG_COND_LE(U) --> (a0 <= a2 && a1 == a3) || (a1 <= a3 && a1 != a3),
1412: * TCG_COND_GT(U) --> (a0 > a2 && a1 == a3) || a1 > a3,
1413: */
1414: tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0,
1415: args[1], args[3], SHIFT_IMM_LSL(0));
1416: tcg_out_dat_reg(s, COND_EQ, ARITH_CMP, 0,
1417: args[0], args[2], SHIFT_IMM_LSL(0));
1418: tcg_out_goto_label(s, tcg_cond_to_arm_cond[args[4]], args[5]);
1419: break;
1420:
1421: case INDEX_op_qemu_ld8u:
1422: tcg_out_qemu_ld(s, COND_AL, args, 0);
1423: break;
1424: case INDEX_op_qemu_ld8s:
1425: tcg_out_qemu_ld(s, COND_AL, args, 0 | 4);
1426: break;
1427: case INDEX_op_qemu_ld16u:
1428: tcg_out_qemu_ld(s, COND_AL, args, 1);
1429: break;
1430: case INDEX_op_qemu_ld16s:
1431: tcg_out_qemu_ld(s, COND_AL, args, 1 | 4);
1432: break;
1433: case INDEX_op_qemu_ld32u:
1434: tcg_out_qemu_ld(s, COND_AL, args, 2);
1435: break;
1436: case INDEX_op_qemu_ld64:
1437: tcg_out_qemu_ld(s, COND_AL, args, 3);
1438: break;
1439:
1440: case INDEX_op_qemu_st8:
1441: tcg_out_qemu_st(s, COND_AL, args, 0);
1442: break;
1443: case INDEX_op_qemu_st16:
1444: tcg_out_qemu_st(s, COND_AL, args, 1);
1445: break;
1446: case INDEX_op_qemu_st32:
1447: tcg_out_qemu_st(s, COND_AL, args, 2);
1448: break;
1449: case INDEX_op_qemu_st64:
1450: tcg_out_qemu_st(s, COND_AL, args, 3);
1451: break;
1452:
1453: case INDEX_op_ext8s_i32:
1454: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1455: args[0], 0, args[1], SHIFT_IMM_LSL(24));
1456: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1457: args[0], 0, args[0], SHIFT_IMM_ASR(24));
1458: break;
1459: case INDEX_op_ext16s_i32:
1460: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1461: args[0], 0, args[1], SHIFT_IMM_LSL(16));
1462: tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
1463: args[0], 0, args[0], SHIFT_IMM_ASR(16));
1464: break;
1465:
1466: default:
1467: tcg_abort();
1468: }
1469: }
1470:
1471: static const TCGTargetOpDef arm_op_defs[] = {
1472: { INDEX_op_exit_tb, { } },
1473: { INDEX_op_goto_tb, { } },
1474: { INDEX_op_call, { "ri" } },
1475: { INDEX_op_jmp, { "ri" } },
1476: { INDEX_op_br, { } },
1477:
1478: { INDEX_op_mov_i32, { "r", "r" } },
1479: { INDEX_op_movi_i32, { "r" } },
1480:
1481: { INDEX_op_ld8u_i32, { "r", "r" } },
1482: { INDEX_op_ld8s_i32, { "r", "r" } },
1483: { INDEX_op_ld16u_i32, { "r", "r" } },
1484: { INDEX_op_ld16s_i32, { "r", "r" } },
1485: { INDEX_op_ld_i32, { "r", "r" } },
1486: { INDEX_op_st8_i32, { "r", "r" } },
1487: { INDEX_op_st16_i32, { "r", "r" } },
1488: { INDEX_op_st_i32, { "r", "r" } },
1489:
1490: /* TODO: "r", "r", "ri" */
1491: { INDEX_op_add_i32, { "r", "r", "r" } },
1492: { INDEX_op_sub_i32, { "r", "r", "r" } },
1493: { INDEX_op_mul_i32, { "r", "r", "r" } },
1494: { INDEX_op_mulu2_i32, { "r", "r", "r", "r" } },
1495: { INDEX_op_div2_i32, { "r", "r", "r", "1", "2" } },
1496: { INDEX_op_divu2_i32, { "r", "r", "r", "1", "2" } },
1497: { INDEX_op_and_i32, { "r", "r", "r" } },
1498: { INDEX_op_or_i32, { "r", "r", "r" } },
1499: { INDEX_op_xor_i32, { "r", "r", "r" } },
1500: { INDEX_op_neg_i32, { "r", "r" } },
1501:
1502: { INDEX_op_shl_i32, { "r", "r", "ri" } },
1503: { INDEX_op_shr_i32, { "r", "r", "ri" } },
1504: { INDEX_op_sar_i32, { "r", "r", "ri" } },
1505:
1506: { INDEX_op_brcond_i32, { "r", "r" } },
1507:
1508: /* TODO: "r", "r", "r", "r", "ri", "ri" */
1509: { INDEX_op_add2_i32, { "r", "r", "r", "r", "r", "r" } },
1510: { INDEX_op_sub2_i32, { "r", "r", "r", "r", "r", "r" } },
1511: { INDEX_op_brcond2_i32, { "r", "r", "r", "r" } },
1512:
1513: { INDEX_op_qemu_ld8u, { "r", "x", "X" } },
1514: { INDEX_op_qemu_ld8s, { "r", "x", "X" } },
1515: { INDEX_op_qemu_ld16u, { "r", "x", "X" } },
1516: { INDEX_op_qemu_ld16s, { "r", "x", "X" } },
1517: { INDEX_op_qemu_ld32u, { "r", "x", "X" } },
1518: { INDEX_op_qemu_ld64, { "d", "r", "x", "X" } },
1519:
1520: { INDEX_op_qemu_st8, { "x", "x", "X" } },
1521: { INDEX_op_qemu_st16, { "x", "x", "X" } },
1522: { INDEX_op_qemu_st32, { "x", "x", "X" } },
1523: { INDEX_op_qemu_st64, { "x", "D", "x", "X" } },
1524:
1525: { INDEX_op_ext8s_i32, { "r", "r" } },
1526: { INDEX_op_ext16s_i32, { "r", "r" } },
1527:
1528: { -1 },
1529: };
1530:
1531: void tcg_target_init(TCGContext *s)
1532: {
1533: /* fail safe */
1534: if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
1535: tcg_abort();
1536:
1537: tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0,
1538: ((2 << TCG_REG_R14) - 1) & ~(1 << TCG_REG_R8));
1539: tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1540: ((2 << TCG_REG_R3) - 1) |
1541: (1 << TCG_REG_R12) | (1 << TCG_REG_R14));
1542:
1543: tcg_regset_clear(s->reserved_regs);
1544: #ifdef SAVE_LR
1545: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R14);
1546: #endif
1547: tcg_regset_set_reg(s->reserved_regs, TCG_REG_CALL_STACK);
1548: tcg_regset_set_reg(s->reserved_regs, TCG_REG_R8);
1549:
1550: tcg_add_target_add_op_defs(arm_op_defs);
1551: }
1552:
1553: static inline void tcg_out_ld(TCGContext *s, TCGType type, int arg,
1554: int arg1, tcg_target_long arg2)
1555: {
1556: tcg_out_ld32u(s, COND_AL, arg, arg1, arg2);
1557: }
1558:
1559: static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
1560: int arg1, tcg_target_long arg2)
1561: {
1562: tcg_out_st32(s, COND_AL, arg, arg1, arg2);
1563: }
1564:
1565: void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
1566: {
1567: if (val > 0)
1568: if (val < 0x100)
1569: tcg_out_dat_imm(s, COND_AL, ARITH_ADD, reg, reg, val);
1570: else
1571: tcg_abort();
1572: else if (val < 0) {
1573: if (val > -0x100)
1574: tcg_out_dat_imm(s, COND_AL, ARITH_SUB, reg, reg, -val);
1575: else
1576: tcg_abort();
1577: }
1578: }
1579:
1580: static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
1581: {
1582: tcg_out_dat_reg(s, COND_AL, ARITH_MOV, ret, 0, arg, SHIFT_IMM_LSL(0));
1583: }
1584:
1585: static inline void tcg_out_movi(TCGContext *s, TCGType type,
1586: int ret, tcg_target_long arg)
1587: {
1588: tcg_out_movi32(s, COND_AL, ret, arg);
1589: }
1590:
1591: void tcg_target_qemu_prologue(TCGContext *s)
1592: {
1593: /* stmdb sp!, { r9 - r11, lr } */
1594: tcg_out32(s, (COND_AL << 28) | 0x092d4e00);
1595:
1596: tcg_out_bx(s, COND_AL, TCG_REG_R0);
1597: tb_ret_addr = s->code_ptr;
1598:
1599: /* ldmia sp!, { r9 - r11, pc } */
1600: tcg_out32(s, (COND_AL << 28) | 0x08bd8e00);
1601: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.