|
|
1.1 root 1: /*
2: * Tiny Code Generator for QEMU
3: *
4: * Copyright (c) 2008 Fabrice Bellard
5: *
6: * Permission is hereby granted, free of charge, to any person obtaining a copy
7: * of this software and associated documentation files (the "Software"), to deal
8: * in the Software without restriction, including without limitation the rights
9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10: * copies of the Software, and to permit persons to whom the Software is
11: * furnished to do so, subject to the following conditions:
12: *
13: * The above copyright notice and this permission notice shall be included in
14: * all copies or substantial portions of the Software.
15: *
16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22: * THE SOFTWARE.
23: */
24:
25: #ifndef NDEBUG
26: static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
27: "%eax",
28: "%ecx",
29: "%edx",
30: "%ebx",
31: "%esp",
32: "%ebp",
33: "%esi",
34: "%edi",
35: };
36: #endif
37:
38: static const int tcg_target_reg_alloc_order[] = {
39: TCG_REG_EAX,
40: TCG_REG_EDX,
41: TCG_REG_ECX,
42: TCG_REG_EBX,
43: TCG_REG_ESI,
44: TCG_REG_EDI,
45: TCG_REG_EBP,
46: };
47:
48: static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
49: static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
50:
51: static uint8_t *tb_ret_addr;
52:
53: static void patch_reloc(uint8_t *code_ptr, int type,
54: tcg_target_long value, tcg_target_long addend)
55: {
56: value += addend;
57: switch(type) {
58: case R_386_32:
59: *(uint32_t *)code_ptr = value;
60: break;
61: case R_386_PC32:
62: *(uint32_t *)code_ptr = value - (long)code_ptr;
63: break;
64: default:
65: tcg_abort();
66: }
67: }
68:
69: /* maximum number of register used for input function arguments */
70: static inline int tcg_target_get_call_iarg_regs_count(int flags)
71: {
72: flags &= TCG_CALL_TYPE_MASK;
73: switch(flags) {
74: case TCG_CALL_TYPE_STD:
75: return 0;
76: case TCG_CALL_TYPE_REGPARM_1:
77: case TCG_CALL_TYPE_REGPARM_2:
78: case TCG_CALL_TYPE_REGPARM:
79: return flags - TCG_CALL_TYPE_REGPARM_1 + 1;
80: default:
81: tcg_abort();
82: }
83: }
84:
85: /* parse target specific constraints */
86: static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
87: {
88: const char *ct_str;
89:
90: ct_str = *pct_str;
91: switch(ct_str[0]) {
92: case 'a':
93: ct->ct |= TCG_CT_REG;
94: tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX);
95: break;
96: case 'b':
97: ct->ct |= TCG_CT_REG;
98: tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX);
99: break;
100: case 'c':
101: ct->ct |= TCG_CT_REG;
102: tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX);
103: break;
104: case 'd':
105: ct->ct |= TCG_CT_REG;
106: tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX);
107: break;
108: case 'S':
109: ct->ct |= TCG_CT_REG;
110: tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI);
111: break;
112: case 'D':
113: ct->ct |= TCG_CT_REG;
114: tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI);
115: break;
116: case 'q':
117: ct->ct |= TCG_CT_REG;
118: tcg_regset_set32(ct->u.regs, 0, 0xf);
119: break;
120: case 'r':
121: ct->ct |= TCG_CT_REG;
122: tcg_regset_set32(ct->u.regs, 0, 0xff);
123: break;
124:
125: /* qemu_ld/st address constraint */
126: case 'L':
127: ct->ct |= TCG_CT_REG;
128: tcg_regset_set32(ct->u.regs, 0, 0xff);
129: tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
130: tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
131: break;
132: default:
133: return -1;
134: }
135: ct_str++;
136: *pct_str = ct_str;
137: return 0;
138: }
139:
140: /* test if a constant matches the constraint */
141: static inline int tcg_target_const_match(tcg_target_long val,
142: const TCGArgConstraint *arg_ct)
143: {
144: int ct;
145: ct = arg_ct->ct;
146: if (ct & TCG_CT_CONST)
147: return 1;
148: else
149: return 0;
150: }
151:
152: #define ARITH_ADD 0
153: #define ARITH_OR 1
154: #define ARITH_ADC 2
155: #define ARITH_SBB 3
156: #define ARITH_AND 4
157: #define ARITH_SUB 5
158: #define ARITH_XOR 6
159: #define ARITH_CMP 7
160:
161: #define SHIFT_SHL 4
162: #define SHIFT_SHR 5
163: #define SHIFT_SAR 7
164:
165: #define JCC_JMP (-1)
166: #define JCC_JO 0x0
167: #define JCC_JNO 0x1
168: #define JCC_JB 0x2
169: #define JCC_JAE 0x3
170: #define JCC_JE 0x4
171: #define JCC_JNE 0x5
172: #define JCC_JBE 0x6
173: #define JCC_JA 0x7
174: #define JCC_JS 0x8
175: #define JCC_JNS 0x9
176: #define JCC_JP 0xa
177: #define JCC_JNP 0xb
178: #define JCC_JL 0xc
179: #define JCC_JGE 0xd
180: #define JCC_JLE 0xe
181: #define JCC_JG 0xf
182:
183: #define P_EXT 0x100 /* 0x0f opcode prefix */
184:
185: static const uint8_t tcg_cond_to_jcc[10] = {
186: [TCG_COND_EQ] = JCC_JE,
187: [TCG_COND_NE] = JCC_JNE,
188: [TCG_COND_LT] = JCC_JL,
189: [TCG_COND_GE] = JCC_JGE,
190: [TCG_COND_LE] = JCC_JLE,
191: [TCG_COND_GT] = JCC_JG,
192: [TCG_COND_LTU] = JCC_JB,
193: [TCG_COND_GEU] = JCC_JAE,
194: [TCG_COND_LEU] = JCC_JBE,
195: [TCG_COND_GTU] = JCC_JA,
196: };
197:
198: static inline void tcg_out_opc(TCGContext *s, int opc)
199: {
200: if (opc & P_EXT)
201: tcg_out8(s, 0x0f);
202: tcg_out8(s, opc);
203: }
204:
205: static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
206: {
207: tcg_out_opc(s, opc);
208: tcg_out8(s, 0xc0 | (r << 3) | rm);
209: }
210:
211: /* rm == -1 means no register index */
212: static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,
213: int32_t offset)
214: {
215: tcg_out_opc(s, opc);
216: if (rm == -1) {
217: tcg_out8(s, 0x05 | (r << 3));
218: tcg_out32(s, offset);
219: } else if (offset == 0 && rm != TCG_REG_EBP) {
220: if (rm == TCG_REG_ESP) {
221: tcg_out8(s, 0x04 | (r << 3));
222: tcg_out8(s, 0x24);
223: } else {
224: tcg_out8(s, 0x00 | (r << 3) | rm);
225: }
226: } else if ((int8_t)offset == offset) {
227: if (rm == TCG_REG_ESP) {
228: tcg_out8(s, 0x44 | (r << 3));
229: tcg_out8(s, 0x24);
230: } else {
231: tcg_out8(s, 0x40 | (r << 3) | rm);
232: }
233: tcg_out8(s, offset);
234: } else {
235: if (rm == TCG_REG_ESP) {
236: tcg_out8(s, 0x84 | (r << 3));
237: tcg_out8(s, 0x24);
238: } else {
239: tcg_out8(s, 0x80 | (r << 3) | rm);
240: }
241: tcg_out32(s, offset);
242: }
243: }
244:
245: static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
246: {
247: if (arg != ret)
248: tcg_out_modrm(s, 0x8b, ret, arg);
249: }
250:
251: static inline void tcg_out_movi(TCGContext *s, TCGType type,
252: int ret, int32_t arg)
253: {
254: if (arg == 0) {
255: /* xor r0,r0 */
256: tcg_out_modrm(s, 0x01 | (ARITH_XOR << 3), ret, ret);
257: } else {
258: tcg_out8(s, 0xb8 + ret);
259: tcg_out32(s, arg);
260: }
261: }
262:
263: static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
264: int arg1, tcg_target_long arg2)
265: {
266: /* movl */
267: tcg_out_modrm_offset(s, 0x8b, ret, arg1, arg2);
268: }
269:
270: static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
271: int arg1, tcg_target_long arg2)
272: {
273: /* movl */
274: tcg_out_modrm_offset(s, 0x89, arg, arg1, arg2);
275: }
276:
277: static inline void tgen_arithi(TCGContext *s, int c, int r0, int32_t val)
278: {
279: if (val == (int8_t)val) {
280: tcg_out_modrm(s, 0x83, c, r0);
281: tcg_out8(s, val);
282: } else {
283: tcg_out_modrm(s, 0x81, c, r0);
284: tcg_out32(s, val);
285: }
286: }
287:
288: static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
289: {
290: if (val != 0)
291: tgen_arithi(s, ARITH_ADD, reg, val);
292: }
293:
294: static void tcg_out_jxx(TCGContext *s, int opc, int label_index)
295: {
296: int32_t val, val1;
297: TCGLabel *l = &s->labels[label_index];
298:
299: if (l->has_value) {
300: val = l->u.value - (tcg_target_long)s->code_ptr;
301: val1 = val - 2;
302: if ((int8_t)val1 == val1) {
303: if (opc == -1)
304: tcg_out8(s, 0xeb);
305: else
306: tcg_out8(s, 0x70 + opc);
307: tcg_out8(s, val1);
308: } else {
309: if (opc == -1) {
310: tcg_out8(s, 0xe9);
311: tcg_out32(s, val - 5);
312: } else {
313: tcg_out8(s, 0x0f);
314: tcg_out8(s, 0x80 + opc);
315: tcg_out32(s, val - 6);
316: }
317: }
318: } else {
319: if (opc == -1) {
320: tcg_out8(s, 0xe9);
321: } else {
322: tcg_out8(s, 0x0f);
323: tcg_out8(s, 0x80 + opc);
324: }
325: tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
326: s->code_ptr += 4;
327: }
328: }
329:
330: static void tcg_out_brcond(TCGContext *s, int cond,
331: TCGArg arg1, TCGArg arg2, int const_arg2,
332: int label_index)
333: {
334: if (const_arg2) {
335: if (arg2 == 0) {
336: /* test r, r */
337: tcg_out_modrm(s, 0x85, arg1, arg1);
338: } else {
339: tgen_arithi(s, ARITH_CMP, arg1, arg2);
340: }
341: } else {
342: tcg_out_modrm(s, 0x01 | (ARITH_CMP << 3), arg2, arg1);
343: }
344: tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index);
345: }
346:
347: /* XXX: we implement it at the target level to avoid having to
348: handle cross basic blocks temporaries */
349: static void tcg_out_brcond2(TCGContext *s,
350: const TCGArg *args, const int *const_args)
351: {
352: int label_next;
353: label_next = gen_new_label();
354: switch(args[4]) {
355: case TCG_COND_EQ:
356: tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], label_next);
357: tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3], args[5]);
358: break;
359: case TCG_COND_NE:
360: tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2], args[5]);
361: tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3], args[5]);
362: break;
363: case TCG_COND_LT:
364: tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
365: tcg_out_jxx(s, JCC_JNE, label_next);
366: tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]);
367: break;
368: case TCG_COND_LE:
369: tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3], args[5]);
370: tcg_out_jxx(s, JCC_JNE, label_next);
371: tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]);
372: break;
373: case TCG_COND_GT:
374: tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
375: tcg_out_jxx(s, JCC_JNE, label_next);
376: tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]);
377: break;
378: case TCG_COND_GE:
379: tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3], args[5]);
380: tcg_out_jxx(s, JCC_JNE, label_next);
381: tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]);
382: break;
383: case TCG_COND_LTU:
384: tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);
385: tcg_out_jxx(s, JCC_JNE, label_next);
386: tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2], args[5]);
387: break;
388: case TCG_COND_LEU:
389: tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3], args[5]);
390: tcg_out_jxx(s, JCC_JNE, label_next);
391: tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2], args[5]);
392: break;
393: case TCG_COND_GTU:
394: tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]);
395: tcg_out_jxx(s, JCC_JNE, label_next);
396: tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2], args[5]);
397: break;
398: case TCG_COND_GEU:
399: tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3], args[5]);
400: tcg_out_jxx(s, JCC_JNE, label_next);
401: tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2], args[5]);
402: break;
403: default:
404: tcg_abort();
405: }
406: tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
407: }
408:
409: #if defined(CONFIG_SOFTMMU)
410:
411: #include "../../softmmu_defs.h"
412:
413: static void *qemu_ld_helpers[4] = {
414: __ldb_mmu,
415: __ldw_mmu,
416: __ldl_mmu,
417: __ldq_mmu,
418: };
419:
420: static void *qemu_st_helpers[4] = {
421: __stb_mmu,
422: __stw_mmu,
423: __stl_mmu,
424: __stq_mmu,
425: };
426: #endif
427:
428: /* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
429: EAX. It will be useful once fixed registers globals are less
430: common. */
431: static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
432: int opc)
433: {
434: int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
435: #if defined(CONFIG_SOFTMMU)
436: uint8_t *label1_ptr, *label2_ptr;
437: #endif
438: #if TARGET_LONG_BITS == 64
439: #if defined(CONFIG_SOFTMMU)
440: uint8_t *label3_ptr;
441: #endif
442: int addr_reg2;
443: #endif
444:
445: data_reg = *args++;
446: if (opc == 3)
447: data_reg2 = *args++;
448: else
449: data_reg2 = 0;
450: addr_reg = *args++;
451: #if TARGET_LONG_BITS == 64
452: addr_reg2 = *args++;
453: #endif
454: mem_index = *args;
455: s_bits = opc & 3;
456:
457: r0 = TCG_REG_EAX;
458: r1 = TCG_REG_EDX;
459:
460: #if defined(CONFIG_SOFTMMU)
461: tcg_out_mov(s, r1, addr_reg);
462:
463: tcg_out_mov(s, r0, addr_reg);
464:
465: tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */
466: tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
467:
468: tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */
469: tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
470:
471: tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */
472: tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
473:
474: tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */
475: tcg_out8(s, 0x80 | (r1 << 3) | 0x04);
476: tcg_out8(s, (5 << 3) | r1);
477: tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_read));
478:
479: /* cmp 0(r1), r0 */
480: tcg_out_modrm_offset(s, 0x3b, r0, r1, 0);
481:
482: tcg_out_mov(s, r0, addr_reg);
483:
484: #if TARGET_LONG_BITS == 32
485: /* je label1 */
486: tcg_out8(s, 0x70 + JCC_JE);
487: label1_ptr = s->code_ptr;
488: s->code_ptr++;
489: #else
490: /* jne label3 */
491: tcg_out8(s, 0x70 + JCC_JNE);
492: label3_ptr = s->code_ptr;
493: s->code_ptr++;
494:
495: /* cmp 4(r1), addr_reg2 */
496: tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4);
497:
498: /* je label1 */
499: tcg_out8(s, 0x70 + JCC_JE);
500: label1_ptr = s->code_ptr;
501: s->code_ptr++;
502:
503: /* label3: */
504: *label3_ptr = s->code_ptr - label3_ptr - 1;
505: #endif
506:
507: /* XXX: move that code at the end of the TB */
508: #if TARGET_LONG_BITS == 32
509: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index);
510: #else
511: tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
512: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
513: #endif
514: tcg_out8(s, 0xe8);
515: tcg_out32(s, (tcg_target_long)qemu_ld_helpers[s_bits] -
516: (tcg_target_long)s->code_ptr - 4);
517:
518: switch(opc) {
519: case 0 | 4:
520: /* movsbl */
521: tcg_out_modrm(s, 0xbe | P_EXT, data_reg, TCG_REG_EAX);
522: break;
523: case 1 | 4:
524: /* movswl */
525: tcg_out_modrm(s, 0xbf | P_EXT, data_reg, TCG_REG_EAX);
526: break;
527: case 0:
528: /* movzbl */
529: tcg_out_modrm(s, 0xb6 | P_EXT, data_reg, TCG_REG_EAX);
530: break;
531: case 1:
532: /* movzwl */
533: tcg_out_modrm(s, 0xb7 | P_EXT, data_reg, TCG_REG_EAX);
534: break;
535: case 2:
536: default:
537: tcg_out_mov(s, data_reg, TCG_REG_EAX);
538: break;
539: case 3:
540: if (data_reg == TCG_REG_EDX) {
541: tcg_out_opc(s, 0x90 + TCG_REG_EDX); /* xchg %edx, %eax */
542: tcg_out_mov(s, data_reg2, TCG_REG_EAX);
543: } else {
544: tcg_out_mov(s, data_reg, TCG_REG_EAX);
545: tcg_out_mov(s, data_reg2, TCG_REG_EDX);
546: }
547: break;
548: }
549:
550: /* jmp label2 */
551: tcg_out8(s, 0xeb);
552: label2_ptr = s->code_ptr;
553: s->code_ptr++;
554:
555: /* label1: */
556: *label1_ptr = s->code_ptr - label1_ptr - 1;
557:
558: /* add x(r1), r0 */
559: tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) -
560: offsetof(CPUTLBEntry, addr_read));
561: #else
562: r0 = addr_reg;
563: #endif
564:
565: #ifdef TARGET_WORDS_BIGENDIAN
566: bswap = 1;
567: #else
568: bswap = 0;
569: #endif
570: switch(opc) {
571: case 0:
572: /* movzbl */
573: tcg_out_modrm_offset(s, 0xb6 | P_EXT, data_reg, r0, 0);
574: break;
575: case 0 | 4:
576: /* movsbl */
577: tcg_out_modrm_offset(s, 0xbe | P_EXT, data_reg, r0, 0);
578: break;
579: case 1:
580: /* movzwl */
581: tcg_out_modrm_offset(s, 0xb7 | P_EXT, data_reg, r0, 0);
582: if (bswap) {
583: /* rolw $8, data_reg */
584: tcg_out8(s, 0x66);
585: tcg_out_modrm(s, 0xc1, 0, data_reg);
586: tcg_out8(s, 8);
587: }
588: break;
589: case 1 | 4:
590: /* movswl */
591: tcg_out_modrm_offset(s, 0xbf | P_EXT, data_reg, r0, 0);
592: if (bswap) {
593: /* rolw $8, data_reg */
594: tcg_out8(s, 0x66);
595: tcg_out_modrm(s, 0xc1, 0, data_reg);
596: tcg_out8(s, 8);
597:
598: /* movswl data_reg, data_reg */
599: tcg_out_modrm(s, 0xbf | P_EXT, data_reg, data_reg);
600: }
601: break;
602: case 2:
603: /* movl (r0), data_reg */
604: tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
605: if (bswap) {
606: /* bswap */
607: tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
608: }
609: break;
610: case 3:
611: /* XXX: could be nicer */
612: if (r0 == data_reg) {
613: r1 = TCG_REG_EDX;
614: if (r1 == data_reg)
615: r1 = TCG_REG_EAX;
616: tcg_out_mov(s, r1, r0);
617: r0 = r1;
618: }
619: if (!bswap) {
620: tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 0);
621: tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 4);
622: } else {
623: tcg_out_modrm_offset(s, 0x8b, data_reg, r0, 4);
624: tcg_out_opc(s, (0xc8 + data_reg) | P_EXT);
625:
626: tcg_out_modrm_offset(s, 0x8b, data_reg2, r0, 0);
627: /* bswap */
628: tcg_out_opc(s, (0xc8 + data_reg2) | P_EXT);
629: }
630: break;
631: default:
632: tcg_abort();
633: }
634:
635: #if defined(CONFIG_SOFTMMU)
636: /* label2: */
637: *label2_ptr = s->code_ptr - label2_ptr - 1;
638: #endif
639: }
640:
641:
642: static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
643: int opc)
644: {
645: int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
646: #if defined(CONFIG_SOFTMMU)
647: uint8_t *label1_ptr, *label2_ptr;
648: #endif
649: #if TARGET_LONG_BITS == 64
650: #if defined(CONFIG_SOFTMMU)
651: uint8_t *label3_ptr;
652: #endif
653: int addr_reg2;
654: #endif
655:
656: data_reg = *args++;
657: if (opc == 3)
658: data_reg2 = *args++;
659: else
660: data_reg2 = 0;
661: addr_reg = *args++;
662: #if TARGET_LONG_BITS == 64
663: addr_reg2 = *args++;
664: #endif
665: mem_index = *args;
666:
667: s_bits = opc;
668:
669: r0 = TCG_REG_EAX;
670: r1 = TCG_REG_EDX;
671:
672: #if defined(CONFIG_SOFTMMU)
673: tcg_out_mov(s, r1, addr_reg);
674:
675: tcg_out_mov(s, r0, addr_reg);
676:
677: tcg_out_modrm(s, 0xc1, 5, r1); /* shr $x, r1 */
678: tcg_out8(s, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
679:
680: tcg_out_modrm(s, 0x81, 4, r0); /* andl $x, r0 */
681: tcg_out32(s, TARGET_PAGE_MASK | ((1 << s_bits) - 1));
682:
683: tcg_out_modrm(s, 0x81, 4, r1); /* andl $x, r1 */
684: tcg_out32(s, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS);
685:
686: tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */
687: tcg_out8(s, 0x80 | (r1 << 3) | 0x04);
688: tcg_out8(s, (5 << 3) | r1);
689: tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_write));
690:
691: /* cmp 0(r1), r0 */
692: tcg_out_modrm_offset(s, 0x3b, r0, r1, 0);
693:
694: tcg_out_mov(s, r0, addr_reg);
695:
696: #if TARGET_LONG_BITS == 32
697: /* je label1 */
698: tcg_out8(s, 0x70 + JCC_JE);
699: label1_ptr = s->code_ptr;
700: s->code_ptr++;
701: #else
702: /* jne label3 */
703: tcg_out8(s, 0x70 + JCC_JNE);
704: label3_ptr = s->code_ptr;
705: s->code_ptr++;
706:
707: /* cmp 4(r1), addr_reg2 */
708: tcg_out_modrm_offset(s, 0x3b, addr_reg2, r1, 4);
709:
710: /* je label1 */
711: tcg_out8(s, 0x70 + JCC_JE);
712: label1_ptr = s->code_ptr;
713: s->code_ptr++;
714:
715: /* label3: */
716: *label3_ptr = s->code_ptr - label3_ptr - 1;
717: #endif
718:
719: /* XXX: move that code at the end of the TB */
720: #if TARGET_LONG_BITS == 32
721: if (opc == 3) {
722: tcg_out_mov(s, TCG_REG_EDX, data_reg);
723: tcg_out_mov(s, TCG_REG_ECX, data_reg2);
724: tcg_out8(s, 0x6a); /* push Ib */
725: tcg_out8(s, mem_index);
726: tcg_out8(s, 0xe8);
727: tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] -
728: (tcg_target_long)s->code_ptr - 4);
729: tcg_out_addi(s, TCG_REG_ESP, 4);
730: } else {
731: switch(opc) {
732: case 0:
733: /* movzbl */
734: tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_EDX, data_reg);
735: break;
736: case 1:
737: /* movzwl */
738: tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_EDX, data_reg);
739: break;
740: case 2:
741: tcg_out_mov(s, TCG_REG_EDX, data_reg);
742: break;
743: }
744: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
745: tcg_out8(s, 0xe8);
746: tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] -
747: (tcg_target_long)s->code_ptr - 4);
748: }
749: #else
750: if (opc == 3) {
751: tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
752: tcg_out8(s, 0x6a); /* push Ib */
753: tcg_out8(s, mem_index);
754: tcg_out_opc(s, 0x50 + data_reg2); /* push */
755: tcg_out_opc(s, 0x50 + data_reg); /* push */
756: tcg_out8(s, 0xe8);
757: tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] -
758: (tcg_target_long)s->code_ptr - 4);
759: tcg_out_addi(s, TCG_REG_ESP, 12);
760: } else {
761: tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
762: switch(opc) {
763: case 0:
764: /* movzbl */
765: tcg_out_modrm(s, 0xb6 | P_EXT, TCG_REG_ECX, data_reg);
766: break;
767: case 1:
768: /* movzwl */
769: tcg_out_modrm(s, 0xb7 | P_EXT, TCG_REG_ECX, data_reg);
770: break;
771: case 2:
772: tcg_out_mov(s, TCG_REG_ECX, data_reg);
773: break;
774: }
775: tcg_out8(s, 0x6a); /* push Ib */
776: tcg_out8(s, mem_index);
777: tcg_out8(s, 0xe8);
778: tcg_out32(s, (tcg_target_long)qemu_st_helpers[s_bits] -
779: (tcg_target_long)s->code_ptr - 4);
780: tcg_out_addi(s, TCG_REG_ESP, 4);
781: }
782: #endif
783:
784: /* jmp label2 */
785: tcg_out8(s, 0xeb);
786: label2_ptr = s->code_ptr;
787: s->code_ptr++;
788:
789: /* label1: */
790: *label1_ptr = s->code_ptr - label1_ptr - 1;
791:
792: /* add x(r1), r0 */
793: tcg_out_modrm_offset(s, 0x03, r0, r1, offsetof(CPUTLBEntry, addend) -
794: offsetof(CPUTLBEntry, addr_write));
795: #else
796: r0 = addr_reg;
797: #endif
798:
799: #ifdef TARGET_WORDS_BIGENDIAN
800: bswap = 1;
801: #else
802: bswap = 0;
803: #endif
804: switch(opc) {
805: case 0:
806: /* movb */
807: tcg_out_modrm_offset(s, 0x88, data_reg, r0, 0);
808: break;
809: case 1:
810: if (bswap) {
811: tcg_out_mov(s, r1, data_reg);
812: tcg_out8(s, 0x66); /* rolw $8, %ecx */
813: tcg_out_modrm(s, 0xc1, 0, r1);
814: tcg_out8(s, 8);
815: data_reg = r1;
816: }
817: /* movw */
818: tcg_out8(s, 0x66);
819: tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
820: break;
821: case 2:
822: if (bswap) {
823: tcg_out_mov(s, r1, data_reg);
824: /* bswap data_reg */
825: tcg_out_opc(s, (0xc8 + r1) | P_EXT);
826: data_reg = r1;
827: }
828: /* movl */
829: tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
830: break;
831: case 3:
832: if (bswap) {
833: tcg_out_mov(s, r1, data_reg2);
834: /* bswap data_reg */
835: tcg_out_opc(s, (0xc8 + r1) | P_EXT);
836: tcg_out_modrm_offset(s, 0x89, r1, r0, 0);
837: tcg_out_mov(s, r1, data_reg);
838: /* bswap data_reg */
839: tcg_out_opc(s, (0xc8 + r1) | P_EXT);
840: tcg_out_modrm_offset(s, 0x89, r1, r0, 4);
841: } else {
842: tcg_out_modrm_offset(s, 0x89, data_reg, r0, 0);
843: tcg_out_modrm_offset(s, 0x89, data_reg2, r0, 4);
844: }
845: break;
846: default:
847: tcg_abort();
848: }
849:
850: #if defined(CONFIG_SOFTMMU)
851: /* label2: */
852: *label2_ptr = s->code_ptr - label2_ptr - 1;
853: #endif
854: }
855:
856: static inline void tcg_out_op(TCGContext *s, int opc,
857: const TCGArg *args, const int *const_args)
858: {
859: int c;
860:
861: switch(opc) {
862: case INDEX_op_exit_tb:
863: tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
864: tcg_out8(s, 0xe9); /* jmp tb_ret_addr */
865: tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
866: break;
867: case INDEX_op_goto_tb:
868: if (s->tb_jmp_offset) {
869: /* direct jump method */
870: tcg_out8(s, 0xe9); /* jmp im */
871: s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
872: tcg_out32(s, 0);
873: } else {
874: /* indirect jump method */
875: /* jmp Ev */
876: tcg_out_modrm_offset(s, 0xff, 4, -1,
877: (tcg_target_long)(s->tb_next + args[0]));
878: }
879: s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
880: break;
881: case INDEX_op_call:
882: if (const_args[0]) {
883: tcg_out8(s, 0xe8);
884: tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
885: } else {
886: tcg_out_modrm(s, 0xff, 2, args[0]);
887: }
888: break;
889: case INDEX_op_jmp:
890: if (const_args[0]) {
891: tcg_out8(s, 0xe9);
892: tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
893: } else {
894: tcg_out_modrm(s, 0xff, 4, args[0]);
895: }
896: break;
897: case INDEX_op_br:
898: tcg_out_jxx(s, JCC_JMP, args[0]);
899: break;
900: case INDEX_op_movi_i32:
901: tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
902: break;
903: case INDEX_op_ld8u_i32:
904: /* movzbl */
905: tcg_out_modrm_offset(s, 0xb6 | P_EXT, args[0], args[1], args[2]);
906: break;
907: case INDEX_op_ld8s_i32:
908: /* movsbl */
909: tcg_out_modrm_offset(s, 0xbe | P_EXT, args[0], args[1], args[2]);
910: break;
911: case INDEX_op_ld16u_i32:
912: /* movzwl */
913: tcg_out_modrm_offset(s, 0xb7 | P_EXT, args[0], args[1], args[2]);
914: break;
915: case INDEX_op_ld16s_i32:
916: /* movswl */
917: tcg_out_modrm_offset(s, 0xbf | P_EXT, args[0], args[1], args[2]);
918: break;
919: case INDEX_op_ld_i32:
920: /* movl */
921: tcg_out_modrm_offset(s, 0x8b, args[0], args[1], args[2]);
922: break;
923: case INDEX_op_st8_i32:
924: /* movb */
925: tcg_out_modrm_offset(s, 0x88, args[0], args[1], args[2]);
926: break;
927: case INDEX_op_st16_i32:
928: /* movw */
929: tcg_out8(s, 0x66);
930: tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]);
931: break;
932: case INDEX_op_st_i32:
933: /* movl */
934: tcg_out_modrm_offset(s, 0x89, args[0], args[1], args[2]);
935: break;
936: case INDEX_op_sub_i32:
937: c = ARITH_SUB;
938: goto gen_arith;
939: case INDEX_op_and_i32:
940: c = ARITH_AND;
941: goto gen_arith;
942: case INDEX_op_or_i32:
943: c = ARITH_OR;
944: goto gen_arith;
945: case INDEX_op_xor_i32:
946: c = ARITH_XOR;
947: goto gen_arith;
948: case INDEX_op_add_i32:
949: c = ARITH_ADD;
950: gen_arith:
951: if (const_args[2]) {
952: tgen_arithi(s, c, args[0], args[2]);
953: } else {
954: tcg_out_modrm(s, 0x01 | (c << 3), args[2], args[0]);
955: }
956: break;
957: case INDEX_op_mul_i32:
958: if (const_args[2]) {
959: int32_t val;
960: val = args[2];
961: if (val == (int8_t)val) {
962: tcg_out_modrm(s, 0x6b, args[0], args[0]);
963: tcg_out8(s, val);
964: } else {
965: tcg_out_modrm(s, 0x69, args[0], args[0]);
966: tcg_out32(s, val);
967: }
968: } else {
969: tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]);
970: }
971: break;
972: case INDEX_op_mulu2_i32:
973: tcg_out_modrm(s, 0xf7, 4, args[3]);
974: break;
975: case INDEX_op_div2_i32:
976: tcg_out_modrm(s, 0xf7, 7, args[4]);
977: break;
978: case INDEX_op_divu2_i32:
979: tcg_out_modrm(s, 0xf7, 6, args[4]);
980: break;
981: case INDEX_op_shl_i32:
982: c = SHIFT_SHL;
983: gen_shift32:
984: if (const_args[2]) {
985: if (args[2] == 1) {
986: tcg_out_modrm(s, 0xd1, c, args[0]);
987: } else {
988: tcg_out_modrm(s, 0xc1, c, args[0]);
989: tcg_out8(s, args[2]);
990: }
991: } else {
992: tcg_out_modrm(s, 0xd3, c, args[0]);
993: }
994: break;
995: case INDEX_op_shr_i32:
996: c = SHIFT_SHR;
997: goto gen_shift32;
998: case INDEX_op_sar_i32:
999: c = SHIFT_SAR;
1000: goto gen_shift32;
1001:
1002: case INDEX_op_add2_i32:
1003: if (const_args[4])
1004: tgen_arithi(s, ARITH_ADD, args[0], args[4]);
1005: else
1006: tcg_out_modrm(s, 0x01 | (ARITH_ADD << 3), args[4], args[0]);
1007: if (const_args[5])
1008: tgen_arithi(s, ARITH_ADC, args[1], args[5]);
1009: else
1010: tcg_out_modrm(s, 0x01 | (ARITH_ADC << 3), args[5], args[1]);
1011: break;
1012: case INDEX_op_sub2_i32:
1013: if (const_args[4])
1014: tgen_arithi(s, ARITH_SUB, args[0], args[4]);
1015: else
1016: tcg_out_modrm(s, 0x01 | (ARITH_SUB << 3), args[4], args[0]);
1017: if (const_args[5])
1018: tgen_arithi(s, ARITH_SBB, args[1], args[5]);
1019: else
1020: tcg_out_modrm(s, 0x01 | (ARITH_SBB << 3), args[5], args[1]);
1021: break;
1022: case INDEX_op_brcond_i32:
1023: tcg_out_brcond(s, args[2], args[0], args[1], const_args[1], args[3]);
1024: break;
1025: case INDEX_op_brcond2_i32:
1026: tcg_out_brcond2(s, args, const_args);
1027: break;
1028:
1029: case INDEX_op_qemu_ld8u:
1030: tcg_out_qemu_ld(s, args, 0);
1031: break;
1032: case INDEX_op_qemu_ld8s:
1033: tcg_out_qemu_ld(s, args, 0 | 4);
1034: break;
1035: case INDEX_op_qemu_ld16u:
1036: tcg_out_qemu_ld(s, args, 1);
1037: break;
1038: case INDEX_op_qemu_ld16s:
1039: tcg_out_qemu_ld(s, args, 1 | 4);
1040: break;
1041: case INDEX_op_qemu_ld32u:
1042: tcg_out_qemu_ld(s, args, 2);
1043: break;
1044: case INDEX_op_qemu_ld64:
1045: tcg_out_qemu_ld(s, args, 3);
1046: break;
1047:
1048: case INDEX_op_qemu_st8:
1049: tcg_out_qemu_st(s, args, 0);
1050: break;
1051: case INDEX_op_qemu_st16:
1052: tcg_out_qemu_st(s, args, 1);
1053: break;
1054: case INDEX_op_qemu_st32:
1055: tcg_out_qemu_st(s, args, 2);
1056: break;
1057: case INDEX_op_qemu_st64:
1058: tcg_out_qemu_st(s, args, 3);
1059: break;
1060:
1061: default:
1062: tcg_abort();
1063: }
1064: }
1065:
1066: static const TCGTargetOpDef x86_op_defs[] = {
1067: { INDEX_op_exit_tb, { } },
1068: { INDEX_op_goto_tb, { } },
1069: { INDEX_op_call, { "ri" } },
1070: { INDEX_op_jmp, { "ri" } },
1071: { INDEX_op_br, { } },
1072: { INDEX_op_mov_i32, { "r", "r" } },
1073: { INDEX_op_movi_i32, { "r" } },
1074: { INDEX_op_ld8u_i32, { "r", "r" } },
1075: { INDEX_op_ld8s_i32, { "r", "r" } },
1076: { INDEX_op_ld16u_i32, { "r", "r" } },
1077: { INDEX_op_ld16s_i32, { "r", "r" } },
1078: { INDEX_op_ld_i32, { "r", "r" } },
1079: { INDEX_op_st8_i32, { "q", "r" } },
1080: { INDEX_op_st16_i32, { "r", "r" } },
1081: { INDEX_op_st_i32, { "r", "r" } },
1082:
1083: { INDEX_op_add_i32, { "r", "0", "ri" } },
1084: { INDEX_op_sub_i32, { "r", "0", "ri" } },
1085: { INDEX_op_mul_i32, { "r", "0", "ri" } },
1086: { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
1087: { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
1088: { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
1089: { INDEX_op_and_i32, { "r", "0", "ri" } },
1090: { INDEX_op_or_i32, { "r", "0", "ri" } },
1091: { INDEX_op_xor_i32, { "r", "0", "ri" } },
1092:
1093: { INDEX_op_shl_i32, { "r", "0", "ci" } },
1094: { INDEX_op_shr_i32, { "r", "0", "ci" } },
1095: { INDEX_op_sar_i32, { "r", "0", "ci" } },
1096:
1097: { INDEX_op_brcond_i32, { "r", "ri" } },
1098:
1099: { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
1100: { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
1101: { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
1102:
1103: #if TARGET_LONG_BITS == 32
1104: { INDEX_op_qemu_ld8u, { "r", "L" } },
1105: { INDEX_op_qemu_ld8s, { "r", "L" } },
1106: { INDEX_op_qemu_ld16u, { "r", "L" } },
1107: { INDEX_op_qemu_ld16s, { "r", "L" } },
1108: { INDEX_op_qemu_ld32u, { "r", "L" } },
1109: { INDEX_op_qemu_ld64, { "r", "r", "L" } },
1110:
1111: { INDEX_op_qemu_st8, { "cb", "L" } },
1112: { INDEX_op_qemu_st16, { "L", "L" } },
1113: { INDEX_op_qemu_st32, { "L", "L" } },
1114: { INDEX_op_qemu_st64, { "L", "L", "L" } },
1115: #else
1116: { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
1117: { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
1118: { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
1119: { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
1120: { INDEX_op_qemu_ld32u, { "r", "L", "L" } },
1121: { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
1122:
1123: { INDEX_op_qemu_st8, { "cb", "L", "L" } },
1124: { INDEX_op_qemu_st16, { "L", "L", "L" } },
1125: { INDEX_op_qemu_st32, { "L", "L", "L" } },
1126: { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
1127: #endif
1128: { -1 },
1129: };
1130:
1131: static int tcg_target_callee_save_regs[] = {
1132: /* TCG_REG_EBP, */ /* currently used for the global env, so no
1133: need to save */
1134: TCG_REG_EBX,
1135: TCG_REG_ESI,
1136: TCG_REG_EDI,
1137: };
1138:
1139: static inline void tcg_out_push(TCGContext *s, int reg)
1140: {
1141: tcg_out_opc(s, 0x50 + reg);
1142: }
1143:
1144: static inline void tcg_out_pop(TCGContext *s, int reg)
1145: {
1146: tcg_out_opc(s, 0x58 + reg);
1147: }
1148:
1149: /* Generate global QEMU prologue and epilogue code */
1150: void tcg_target_qemu_prologue(TCGContext *s)
1151: {
1152: int i, frame_size, push_size, stack_addend;
1153:
1154: /* TB prologue */
1155: /* save all callee saved registers */
1156: for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
1157: tcg_out_push(s, tcg_target_callee_save_regs[i]);
1158: }
1159: /* reserve some stack space */
1160: push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
1161: frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
1162: frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
1163: ~(TCG_TARGET_STACK_ALIGN - 1);
1164: stack_addend = frame_size - push_size;
1165: tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
1166:
1167: tcg_out_modrm(s, 0xff, 4, TCG_REG_EAX); /* jmp *%eax */
1168:
1169: /* TB epilogue */
1170: tb_ret_addr = s->code_ptr;
1171: tcg_out_addi(s, TCG_REG_ESP, stack_addend);
1172: for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
1173: tcg_out_pop(s, tcg_target_callee_save_regs[i]);
1174: }
1175: tcg_out8(s, 0xc3); /* ret */
1176: }
1177:
1178: void tcg_target_init(TCGContext *s)
1179: {
1180: /* fail safe */
1181: if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
1182: tcg_abort();
1183:
1184: tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
1185: tcg_regset_set32(tcg_target_call_clobber_regs, 0,
1186: (1 << TCG_REG_EAX) |
1187: (1 << TCG_REG_EDX) |
1188: (1 << TCG_REG_ECX));
1189:
1190: tcg_regset_clear(s->reserved_regs);
1191: tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP);
1192:
1193: tcg_add_target_add_op_defs(x86_op_defs);
1194: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.