]> git.proxmox.com Git - mirror_qemu.git/blame - tcg/i386/tcg-target.c
tcg-i386: Tidy ret.
[mirror_qemu.git] / tcg / i386 / tcg-target.c
CommitLineData
c896fe29
FB
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 */
d4a9eb1f
BS
24
25#ifndef NDEBUG
26static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
c896fe29
FB
27 "%eax",
28 "%ecx",
29 "%edx",
30 "%ebx",
31 "%esp",
32 "%ebp",
33 "%esi",
34 "%edi",
35};
d4a9eb1f 36#endif
c896fe29 37
d4a9eb1f 38static const int tcg_target_reg_alloc_order[] = {
c896fe29
FB
39 TCG_REG_EBX,
40 TCG_REG_ESI,
41 TCG_REG_EDI,
42 TCG_REG_EBP,
6648e296
RH
43 TCG_REG_ECX,
44 TCG_REG_EDX,
45 TCG_REG_EAX,
c896fe29
FB
46};
47
d4a9eb1f
BS
48static const int tcg_target_call_iarg_regs[3] = { TCG_REG_EAX, TCG_REG_EDX, TCG_REG_ECX };
49static const int tcg_target_call_oarg_regs[2] = { TCG_REG_EAX, TCG_REG_EDX };
c896fe29 50
b03cce8e
FB
51static uint8_t *tb_ret_addr;
52
c896fe29 53static void patch_reloc(uint8_t *code_ptr, int type,
f54b3f92 54 tcg_target_long value, tcg_target_long addend)
c896fe29 55{
f54b3f92 56 value += addend;
c896fe29
FB
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;
f75b56c1
RH
64 case R_386_PC8:
65 value -= (long)code_ptr;
66 if (value != (int8_t)value) {
67 tcg_abort();
68 }
69 *(uint8_t *)code_ptr = value;
70 break;
c896fe29
FB
71 default:
72 tcg_abort();
73 }
74}
75
76/* maximum number of register used for input function arguments */
77static inline int tcg_target_get_call_iarg_regs_count(int flags)
78{
79 flags &= TCG_CALL_TYPE_MASK;
80 switch(flags) {
81 case TCG_CALL_TYPE_STD:
82 return 0;
83 case TCG_CALL_TYPE_REGPARM_1:
84 case TCG_CALL_TYPE_REGPARM_2:
85 case TCG_CALL_TYPE_REGPARM:
86 return flags - TCG_CALL_TYPE_REGPARM_1 + 1;
87 default:
88 tcg_abort();
89 }
90}
91
92/* parse target specific constraints */
d4a9eb1f 93static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
c896fe29
FB
94{
95 const char *ct_str;
96
97 ct_str = *pct_str;
98 switch(ct_str[0]) {
99 case 'a':
100 ct->ct |= TCG_CT_REG;
101 tcg_regset_set_reg(ct->u.regs, TCG_REG_EAX);
102 break;
103 case 'b':
104 ct->ct |= TCG_CT_REG;
105 tcg_regset_set_reg(ct->u.regs, TCG_REG_EBX);
106 break;
107 case 'c':
108 ct->ct |= TCG_CT_REG;
109 tcg_regset_set_reg(ct->u.regs, TCG_REG_ECX);
110 break;
111 case 'd':
112 ct->ct |= TCG_CT_REG;
113 tcg_regset_set_reg(ct->u.regs, TCG_REG_EDX);
114 break;
115 case 'S':
116 ct->ct |= TCG_CT_REG;
117 tcg_regset_set_reg(ct->u.regs, TCG_REG_ESI);
118 break;
119 case 'D':
120 ct->ct |= TCG_CT_REG;
121 tcg_regset_set_reg(ct->u.regs, TCG_REG_EDI);
122 break;
123 case 'q':
124 ct->ct |= TCG_CT_REG;
125 tcg_regset_set32(ct->u.regs, 0, 0xf);
126 break;
127 case 'r':
128 ct->ct |= TCG_CT_REG;
129 tcg_regset_set32(ct->u.regs, 0, 0xff);
130 break;
131
132 /* qemu_ld/st address constraint */
133 case 'L':
134 ct->ct |= TCG_CT_REG;
135 tcg_regset_set32(ct->u.regs, 0, 0xff);
136 tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX);
137 tcg_regset_reset_reg(ct->u.regs, TCG_REG_EDX);
138 break;
139 default:
140 return -1;
141 }
142 ct_str++;
143 *pct_str = ct_str;
144 return 0;
145}
146
147/* test if a constant matches the constraint */
148static inline int tcg_target_const_match(tcg_target_long val,
149 const TCGArgConstraint *arg_ct)
150{
151 int ct;
152 ct = arg_ct->ct;
153 if (ct & TCG_CT_CONST)
154 return 1;
155 else
156 return 0;
157}
158
fcb5dac1
RH
159#define P_EXT 0x100 /* 0x0f opcode prefix */
160
a369a702
RH
161#define OPC_ARITH_EvIz (0x81)
162#define OPC_ARITH_EvIb (0x83)
81570a70
RH
163#define OPC_ARITH_GvEv (0x03) /* ... plus (ARITH_FOO << 3) */
164#define OPC_ADD_GvEv (OPC_ARITH_GvEv | (ARITH_ADD << 3))
fcb5dac1 165#define OPC_BSWAP (0xc8 | P_EXT)
aadb21a4 166#define OPC_CALL_Jz (0xe8)
81570a70
RH
167#define OPC_CMP_GvEv (OPC_ARITH_GvEv | (ARITH_CMP << 3))
168#define OPC_DEC_r32 (0x48)
169#define OPC_INC_r32 (0x40)
da441cff
RH
170#define OPC_JCC_long (0x80 | P_EXT) /* ... plus condition code */
171#define OPC_JCC_short (0x70) /* ... plus condition code */
172#define OPC_JMP_long (0xe9)
173#define OPC_JMP_short (0xeb)
af266089
RH
174#define OPC_MOVB_EvGv (0x88) /* stores, more or less */
175#define OPC_MOVL_EvGv (0x89) /* stores, more or less */
176#define OPC_MOVL_GvEv (0x8b) /* loads, more or less */
ef10b106 177#define OPC_MOVL_Iv (0xb8)
6817c355
RH
178#define OPC_MOVSBL (0xbe | P_EXT)
179#define OPC_MOVSWL (0xbf | P_EXT)
55e082a7
RH
180#define OPC_MOVZBL (0xb6 | P_EXT)
181#define OPC_MOVZWL (0xb7 | P_EXT)
6858614e
RH
182#define OPC_POP_r32 (0x58)
183#define OPC_PUSH_r32 (0x50)
184#define OPC_PUSH_Iv (0x68)
185#define OPC_PUSH_Ib (0x6a)
3c3accc6 186#define OPC_RET (0xc3)
f53dba01
RH
187#define OPC_SHIFT_1 (0xd1)
188#define OPC_SHIFT_Ib (0xc1)
189#define OPC_SHIFT_cl (0xd3)
81570a70 190#define OPC_TESTL (0x85)
fcb5dac1 191
da441cff 192/* Group 1 opcode extensions for 0x80-0x83. */
c896fe29
FB
193#define ARITH_ADD 0
194#define ARITH_OR 1
195#define ARITH_ADC 2
196#define ARITH_SBB 3
197#define ARITH_AND 4
198#define ARITH_SUB 5
199#define ARITH_XOR 6
200#define ARITH_CMP 7
201
da441cff 202/* Group 2 opcode extensions for 0xc0, 0xc1, 0xd0-0xd3. */
9619376c
AJ
203#define SHIFT_ROL 0
204#define SHIFT_ROR 1
c896fe29
FB
205#define SHIFT_SHL 4
206#define SHIFT_SHR 5
207#define SHIFT_SAR 7
208
da441cff 209/* Group 5 opcode extensions for 0xff. */
aadb21a4 210#define EXT_CALLN_Ev 2
da441cff
RH
211#define EXT_JMPN_Ev 4
212
213/* Condition codes to be added to OPC_JCC_{long,short}. */
c896fe29
FB
214#define JCC_JMP (-1)
215#define JCC_JO 0x0
216#define JCC_JNO 0x1
217#define JCC_JB 0x2
218#define JCC_JAE 0x3
219#define JCC_JE 0x4
220#define JCC_JNE 0x5
221#define JCC_JBE 0x6
222#define JCC_JA 0x7
223#define JCC_JS 0x8
224#define JCC_JNS 0x9
225#define JCC_JP 0xa
226#define JCC_JNP 0xb
227#define JCC_JL 0xc
228#define JCC_JGE 0xd
229#define JCC_JLE 0xe
230#define JCC_JG 0xf
231
c896fe29
FB
232static const uint8_t tcg_cond_to_jcc[10] = {
233 [TCG_COND_EQ] = JCC_JE,
234 [TCG_COND_NE] = JCC_JNE,
235 [TCG_COND_LT] = JCC_JL,
236 [TCG_COND_GE] = JCC_JGE,
237 [TCG_COND_LE] = JCC_JLE,
238 [TCG_COND_GT] = JCC_JG,
239 [TCG_COND_LTU] = JCC_JB,
240 [TCG_COND_GEU] = JCC_JAE,
241 [TCG_COND_LEU] = JCC_JBE,
242 [TCG_COND_GTU] = JCC_JA,
243};
244
245static inline void tcg_out_opc(TCGContext *s, int opc)
246{
247 if (opc & P_EXT)
248 tcg_out8(s, 0x0f);
249 tcg_out8(s, opc);
250}
251
252static inline void tcg_out_modrm(TCGContext *s, int opc, int r, int rm)
253{
254 tcg_out_opc(s, opc);
255 tcg_out8(s, 0xc0 | (r << 3) | rm);
256}
257
258/* rm == -1 means no register index */
259static inline void tcg_out_modrm_offset(TCGContext *s, int opc, int r, int rm,
260 int32_t offset)
261{
262 tcg_out_opc(s, opc);
263 if (rm == -1) {
264 tcg_out8(s, 0x05 | (r << 3));
265 tcg_out32(s, offset);
266 } else if (offset == 0 && rm != TCG_REG_EBP) {
267 if (rm == TCG_REG_ESP) {
268 tcg_out8(s, 0x04 | (r << 3));
269 tcg_out8(s, 0x24);
270 } else {
271 tcg_out8(s, 0x00 | (r << 3) | rm);
272 }
273 } else if ((int8_t)offset == offset) {
274 if (rm == TCG_REG_ESP) {
275 tcg_out8(s, 0x44 | (r << 3));
276 tcg_out8(s, 0x24);
277 } else {
278 tcg_out8(s, 0x40 | (r << 3) | rm);
279 }
280 tcg_out8(s, offset);
281 } else {
282 if (rm == TCG_REG_ESP) {
283 tcg_out8(s, 0x84 | (r << 3));
284 tcg_out8(s, 0x24);
285 } else {
286 tcg_out8(s, 0x80 | (r << 3) | rm);
287 }
288 tcg_out32(s, offset);
289 }
290}
291
81570a70
RH
292/* Generate dest op= src. Uses the same ARITH_* codes as tgen_arithi. */
293static inline void tgen_arithr(TCGContext *s, int subop, int dest, int src)
294{
295 tcg_out_modrm(s, OPC_ARITH_GvEv + (subop << 3), dest, src);
296}
297
c896fe29
FB
298static inline void tcg_out_mov(TCGContext *s, int ret, int arg)
299{
af266089
RH
300 if (arg != ret) {
301 tcg_out_modrm(s, OPC_MOVL_GvEv, ret, arg);
302 }
c896fe29
FB
303}
304
305static inline void tcg_out_movi(TCGContext *s, TCGType type,
306 int ret, int32_t arg)
307{
308 if (arg == 0) {
81570a70 309 tgen_arithr(s, ARITH_XOR, ret, ret);
c896fe29 310 } else {
ef10b106 311 tcg_out8(s, OPC_MOVL_Iv + ret);
c896fe29
FB
312 tcg_out32(s, arg);
313 }
314}
315
6858614e
RH
316static inline void tcg_out_pushi(TCGContext *s, tcg_target_long val)
317{
318 if (val == (int8_t)val) {
319 tcg_out_opc(s, OPC_PUSH_Ib);
320 tcg_out8(s, val);
321 } else {
322 tcg_out_opc(s, OPC_PUSH_Iv);
323 tcg_out32(s, val);
324 }
325}
326
327static inline void tcg_out_push(TCGContext *s, int reg)
328{
329 tcg_out_opc(s, OPC_PUSH_r32 + reg);
330}
331
332static inline void tcg_out_pop(TCGContext *s, int reg)
333{
334 tcg_out_opc(s, OPC_POP_r32 + reg);
335}
336
e4d5434c
BS
337static inline void tcg_out_ld(TCGContext *s, TCGType type, int ret,
338 int arg1, tcg_target_long arg2)
c896fe29 339{
af266089 340 tcg_out_modrm_offset(s, OPC_MOVL_GvEv, ret, arg1, arg2);
c896fe29
FB
341}
342
e4d5434c
BS
343static inline void tcg_out_st(TCGContext *s, TCGType type, int arg,
344 int arg1, tcg_target_long arg2)
c896fe29 345{
af266089 346 tcg_out_modrm_offset(s, OPC_MOVL_EvGv, arg, arg1, arg2);
c896fe29
FB
347}
348
f53dba01
RH
349static void tcg_out_shifti(TCGContext *s, int subopc, int reg, int count)
350{
351 if (count == 1) {
352 tcg_out_modrm(s, OPC_SHIFT_1, subopc, reg);
353 } else {
354 tcg_out_modrm(s, OPC_SHIFT_Ib, subopc, reg);
355 tcg_out8(s, count);
356 }
357}
358
fcb5dac1
RH
359static inline void tcg_out_bswap32(TCGContext *s, int reg)
360{
361 tcg_out_opc(s, OPC_BSWAP + reg);
362}
363
364static inline void tcg_out_rolw_8(TCGContext *s, int reg)
365{
366 tcg_out8(s, 0x66);
f53dba01 367 tcg_out_shifti(s, SHIFT_ROL, reg, 8);
fcb5dac1
RH
368}
369
55e082a7
RH
370static inline void tcg_out_ext8u(TCGContext *s, int dest, int src)
371{
372 /* movzbl */
373 assert(src < 4);
374 tcg_out_modrm(s, OPC_MOVZBL, dest, src);
375}
376
6817c355
RH
377static void tcg_out_ext8s(TCGContext *s, int dest, int src)
378{
379 /* movsbl */
380 assert(src < 4);
381 tcg_out_modrm(s, OPC_MOVSBL, dest, src);
382}
383
55e082a7
RH
384static inline void tcg_out_ext16u(TCGContext *s, int dest, int src)
385{
386 /* movzwl */
387 tcg_out_modrm(s, OPC_MOVZWL, dest, src);
388}
389
6817c355
RH
390static inline void tcg_out_ext16s(TCGContext *s, int dest, int src)
391{
392 /* movswl */
393 tcg_out_modrm(s, OPC_MOVSWL, dest, src);
394}
395
81570a70
RH
396static inline void tgen_arithi(TCGContext *s, int c, int r0,
397 int32_t val, int cf)
c896fe29 398{
81570a70
RH
399 /* ??? While INC is 2 bytes shorter than ADDL $1, they also induce
400 partial flags update stalls on Pentium4 and are not recommended
401 by current Intel optimization manuals. */
402 if (!cf && (c == ARITH_ADD || c == ARITH_SUB) && (val == 1 || val == -1)) {
403 int opc = ((c == ARITH_ADD) ^ (val < 0) ? OPC_INC_r32 : OPC_DEC_r32);
404 tcg_out_opc(s, opc + r0);
17cf428f 405 } else if (val == (int8_t)val) {
a369a702 406 tcg_out_modrm(s, OPC_ARITH_EvIb, c, r0);
c896fe29 407 tcg_out8(s, val);
b70650cb 408 } else if (c == ARITH_AND && val == 0xffu && r0 < 4) {
55e082a7 409 tcg_out_ext8u(s, r0, r0);
b70650cb 410 } else if (c == ARITH_AND && val == 0xffffu) {
55e082a7 411 tcg_out_ext16u(s, r0, r0);
c896fe29 412 } else {
a369a702 413 tcg_out_modrm(s, OPC_ARITH_EvIz, c, r0);
c896fe29
FB
414 tcg_out32(s, val);
415 }
416}
417
3e9a474e 418static void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
c896fe29
FB
419{
420 if (val != 0)
17cf428f 421 tgen_arithi(s, ARITH_ADD, reg, val, 0);
c896fe29
FB
422}
423
f75b56c1
RH
424/* Use SMALL != 0 to force a short forward branch. */
425static void tcg_out_jxx(TCGContext *s, int opc, int label_index, int small)
c896fe29
FB
426{
427 int32_t val, val1;
428 TCGLabel *l = &s->labels[label_index];
429
430 if (l->has_value) {
431 val = l->u.value - (tcg_target_long)s->code_ptr;
432 val1 = val - 2;
433 if ((int8_t)val1 == val1) {
f75b56c1 434 if (opc == -1) {
da441cff 435 tcg_out8(s, OPC_JMP_short);
f75b56c1 436 } else {
da441cff 437 tcg_out8(s, OPC_JCC_short + opc);
f75b56c1 438 }
c896fe29
FB
439 tcg_out8(s, val1);
440 } else {
f75b56c1
RH
441 if (small) {
442 tcg_abort();
443 }
c896fe29 444 if (opc == -1) {
da441cff 445 tcg_out8(s, OPC_JMP_long);
c896fe29
FB
446 tcg_out32(s, val - 5);
447 } else {
da441cff 448 tcg_out_opc(s, OPC_JCC_long + opc);
c896fe29
FB
449 tcg_out32(s, val - 6);
450 }
451 }
f75b56c1
RH
452 } else if (small) {
453 if (opc == -1) {
da441cff 454 tcg_out8(s, OPC_JMP_short);
f75b56c1 455 } else {
da441cff 456 tcg_out8(s, OPC_JCC_short + opc);
f75b56c1
RH
457 }
458 tcg_out_reloc(s, s->code_ptr, R_386_PC8, label_index, -1);
459 s->code_ptr += 1;
c896fe29
FB
460 } else {
461 if (opc == -1) {
da441cff 462 tcg_out8(s, OPC_JMP_long);
c896fe29 463 } else {
da441cff 464 tcg_out_opc(s, OPC_JCC_long + opc);
c896fe29
FB
465 }
466 tcg_out_reloc(s, s->code_ptr, R_386_PC32, label_index, -4);
623e265c 467 s->code_ptr += 4;
c896fe29
FB
468 }
469}
470
1d2699ae
RH
471static void tcg_out_cmp(TCGContext *s, TCGArg arg1, TCGArg arg2,
472 int const_arg2)
c896fe29 473{
c896fe29
FB
474 if (const_arg2) {
475 if (arg2 == 0) {
c896fe29 476 /* test r, r */
81570a70 477 tcg_out_modrm(s, OPC_TESTL, arg1, arg1);
c896fe29 478 } else {
17cf428f 479 tgen_arithi(s, ARITH_CMP, arg1, arg2, 0);
c896fe29
FB
480 }
481 } else {
81570a70 482 tgen_arithr(s, ARITH_CMP, arg1, arg2);
c896fe29 483 }
1d2699ae
RH
484}
485
8a56e840 486static void tcg_out_brcond(TCGContext *s, TCGCond cond,
1d2699ae
RH
487 TCGArg arg1, TCGArg arg2, int const_arg2,
488 int label_index, int small)
489{
490 tcg_out_cmp(s, arg1, arg2, const_arg2);
f75b56c1 491 tcg_out_jxx(s, tcg_cond_to_jcc[cond], label_index, small);
c896fe29
FB
492}
493
494/* XXX: we implement it at the target level to avoid having to
495 handle cross basic blocks temporaries */
f75b56c1
RH
496static void tcg_out_brcond2(TCGContext *s, const TCGArg *args,
497 const int *const_args, int small)
c896fe29
FB
498{
499 int label_next;
500 label_next = gen_new_label();
501 switch(args[4]) {
502 case TCG_COND_EQ:
f75b56c1
RH
503 tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2],
504 label_next, 1);
505 tcg_out_brcond(s, TCG_COND_EQ, args[1], args[3], const_args[3],
506 args[5], small);
c896fe29
FB
507 break;
508 case TCG_COND_NE:
f75b56c1
RH
509 tcg_out_brcond(s, TCG_COND_NE, args[0], args[2], const_args[2],
510 args[5], small);
511 tcg_out_brcond(s, TCG_COND_NE, args[1], args[3], const_args[3],
512 args[5], small);
c896fe29
FB
513 break;
514 case TCG_COND_LT:
f75b56c1
RH
515 tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3],
516 args[5], small);
517 tcg_out_jxx(s, JCC_JNE, label_next, 1);
518 tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2],
519 args[5], small);
c896fe29
FB
520 break;
521 case TCG_COND_LE:
f75b56c1
RH
522 tcg_out_brcond(s, TCG_COND_LT, args[1], args[3], const_args[3],
523 args[5], small);
524 tcg_out_jxx(s, JCC_JNE, label_next, 1);
525 tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2],
526 args[5], small);
c896fe29
FB
527 break;
528 case TCG_COND_GT:
f75b56c1
RH
529 tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3],
530 args[5], small);
531 tcg_out_jxx(s, JCC_JNE, label_next, 1);
532 tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2],
533 args[5], small);
c896fe29
FB
534 break;
535 case TCG_COND_GE:
f75b56c1
RH
536 tcg_out_brcond(s, TCG_COND_GT, args[1], args[3], const_args[3],
537 args[5], small);
538 tcg_out_jxx(s, JCC_JNE, label_next, 1);
539 tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2],
540 args[5], small);
c896fe29
FB
541 break;
542 case TCG_COND_LTU:
f75b56c1
RH
543 tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3],
544 args[5], small);
545 tcg_out_jxx(s, JCC_JNE, label_next, 1);
546 tcg_out_brcond(s, TCG_COND_LTU, args[0], args[2], const_args[2],
547 args[5], small);
c896fe29
FB
548 break;
549 case TCG_COND_LEU:
f75b56c1
RH
550 tcg_out_brcond(s, TCG_COND_LTU, args[1], args[3], const_args[3],
551 args[5], small);
552 tcg_out_jxx(s, JCC_JNE, label_next, 1);
553 tcg_out_brcond(s, TCG_COND_LEU, args[0], args[2], const_args[2],
554 args[5], small);
c896fe29
FB
555 break;
556 case TCG_COND_GTU:
f75b56c1
RH
557 tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3],
558 args[5], small);
559 tcg_out_jxx(s, JCC_JNE, label_next, 1);
560 tcg_out_brcond(s, TCG_COND_GTU, args[0], args[2], const_args[2],
561 args[5], small);
c896fe29
FB
562 break;
563 case TCG_COND_GEU:
f75b56c1
RH
564 tcg_out_brcond(s, TCG_COND_GTU, args[1], args[3], const_args[3],
565 args[5], small);
566 tcg_out_jxx(s, JCC_JNE, label_next, 1);
567 tcg_out_brcond(s, TCG_COND_GEU, args[0], args[2], const_args[2],
568 args[5], small);
c896fe29
FB
569 break;
570 default:
571 tcg_abort();
572 }
573 tcg_out_label(s, label_next, (tcg_target_long)s->code_ptr);
574}
575
8a56e840 576static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGArg dest,
1d2699ae
RH
577 TCGArg arg1, TCGArg arg2, int const_arg2)
578{
579 tcg_out_cmp(s, arg1, arg2, const_arg2);
580 /* setcc */
581 tcg_out_modrm(s, 0x90 | tcg_cond_to_jcc[cond] | P_EXT, 0, dest);
a369a702 582 tcg_out_ext8u(s, dest, dest);
1d2699ae
RH
583}
584
585static void tcg_out_setcond2(TCGContext *s, const TCGArg *args,
586 const int *const_args)
587{
588 TCGArg new_args[6];
589 int label_true, label_over;
590
591 memcpy(new_args, args+1, 5*sizeof(TCGArg));
592
593 if (args[0] == args[1] || args[0] == args[2]
594 || (!const_args[3] && args[0] == args[3])
595 || (!const_args[4] && args[0] == args[4])) {
596 /* When the destination overlaps with one of the argument
597 registers, don't do anything tricky. */
598 label_true = gen_new_label();
599 label_over = gen_new_label();
600
601 new_args[5] = label_true;
602 tcg_out_brcond2(s, new_args, const_args+1, 1);
603
604 tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
605 tcg_out_jxx(s, JCC_JMP, label_over, 1);
606 tcg_out_label(s, label_true, (tcg_target_long)s->code_ptr);
607
608 tcg_out_movi(s, TCG_TYPE_I32, args[0], 1);
609 tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
610 } else {
611 /* When the destination does not overlap one of the arguments,
612 clear the destination first, jump if cond false, and emit an
613 increment in the true case. This results in smaller code. */
614
615 tcg_out_movi(s, TCG_TYPE_I32, args[0], 0);
616
617 label_over = gen_new_label();
618 new_args[4] = tcg_invert_cond(new_args[4]);
619 new_args[5] = label_over;
620 tcg_out_brcond2(s, new_args, const_args+1, 1);
621
622 tgen_arithi(s, ARITH_ADD, args[0], 1, 0);
623 tcg_out_label(s, label_over, (tcg_target_long)s->code_ptr);
624 }
625}
626
aadb21a4
RH
627static void tcg_out_calli(TCGContext *s, tcg_target_long dest)
628{
629 tcg_out_opc(s, OPC_CALL_Jz);
630 tcg_out32(s, dest - (tcg_target_long)s->code_ptr - 4);
631}
632
c896fe29 633#if defined(CONFIG_SOFTMMU)
79383c9c
BS
634
635#include "../../softmmu_defs.h"
c896fe29
FB
636
637static void *qemu_ld_helpers[4] = {
638 __ldb_mmu,
639 __ldw_mmu,
640 __ldl_mmu,
641 __ldq_mmu,
642};
643
644static void *qemu_st_helpers[4] = {
645 __stb_mmu,
646 __stw_mmu,
647 __stl_mmu,
648 __stq_mmu,
649};
650#endif
651
379f6698
PB
652#ifndef CONFIG_USER_ONLY
653#define GUEST_BASE 0
654#endif
655
c896fe29
FB
656/* XXX: qemu_ld and qemu_st could be modified to clobber only EDX and
657 EAX. It will be useful once fixed registers globals are less
658 common. */
659static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
660 int opc)
661{
662 int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
663#if defined(CONFIG_SOFTMMU)
664 uint8_t *label1_ptr, *label2_ptr;
665#endif
666#if TARGET_LONG_BITS == 64
667#if defined(CONFIG_SOFTMMU)
668 uint8_t *label3_ptr;
669#endif
670 int addr_reg2;
671#endif
672
673 data_reg = *args++;
674 if (opc == 3)
675 data_reg2 = *args++;
676 else
677 data_reg2 = 0;
678 addr_reg = *args++;
679#if TARGET_LONG_BITS == 64
680 addr_reg2 = *args++;
681#endif
682 mem_index = *args;
683 s_bits = opc & 3;
684
685 r0 = TCG_REG_EAX;
686 r1 = TCG_REG_EDX;
687
688#if defined(CONFIG_SOFTMMU)
689 tcg_out_mov(s, r1, addr_reg);
c896fe29 690 tcg_out_mov(s, r0, addr_reg);
a369a702 691
f53dba01
RH
692 tcg_out_shifti(s, SHIFT_SHR, r1, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
693
a369a702
RH
694 tgen_arithi(s, ARITH_AND, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
695 tgen_arithi(s, ARITH_AND, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
c896fe29
FB
696
697 tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */
698 tcg_out8(s, 0x80 | (r1 << 3) | 0x04);
699 tcg_out8(s, (5 << 3) | r1);
700 tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_read));
701
702 /* cmp 0(r1), r0 */
81570a70 703 tcg_out_modrm_offset(s, OPC_CMP_GvEv, r0, r1, 0);
c896fe29
FB
704
705 tcg_out_mov(s, r0, addr_reg);
706
707#if TARGET_LONG_BITS == 32
708 /* je label1 */
da441cff 709 tcg_out8(s, OPC_JCC_short + JCC_JE);
c896fe29
FB
710 label1_ptr = s->code_ptr;
711 s->code_ptr++;
712#else
713 /* jne label3 */
da441cff 714 tcg_out8(s, OPC_JCC_short + JCC_JNE);
c896fe29
FB
715 label3_ptr = s->code_ptr;
716 s->code_ptr++;
717
718 /* cmp 4(r1), addr_reg2 */
81570a70 719 tcg_out_modrm_offset(s, OPC_CMP_GvEv, addr_reg2, r1, 4);
c896fe29
FB
720
721 /* je label1 */
da441cff 722 tcg_out8(s, OPC_JCC_short + JCC_JE);
c896fe29
FB
723 label1_ptr = s->code_ptr;
724 s->code_ptr++;
725
726 /* label3: */
727 *label3_ptr = s->code_ptr - label3_ptr - 1;
728#endif
729
730 /* XXX: move that code at the end of the TB */
731#if TARGET_LONG_BITS == 32
732 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EDX, mem_index);
733#else
734 tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
735 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
736#endif
aadb21a4 737 tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]);
c896fe29
FB
738
739 switch(opc) {
740 case 0 | 4:
6817c355 741 tcg_out_ext8s(s, data_reg, TCG_REG_EAX);
c896fe29
FB
742 break;
743 case 1 | 4:
6817c355 744 tcg_out_ext16s(s, data_reg, TCG_REG_EAX);
c896fe29
FB
745 break;
746 case 0:
55e082a7 747 tcg_out_ext8u(s, data_reg, TCG_REG_EAX);
9db3ba4d 748 break;
c896fe29 749 case 1:
55e082a7 750 tcg_out_ext16u(s, data_reg, TCG_REG_EAX);
9db3ba4d 751 break;
c896fe29
FB
752 case 2:
753 default:
754 tcg_out_mov(s, data_reg, TCG_REG_EAX);
755 break;
756 case 3:
757 if (data_reg == TCG_REG_EDX) {
758 tcg_out_opc(s, 0x90 + TCG_REG_EDX); /* xchg %edx, %eax */
759 tcg_out_mov(s, data_reg2, TCG_REG_EAX);
760 } else {
761 tcg_out_mov(s, data_reg, TCG_REG_EAX);
762 tcg_out_mov(s, data_reg2, TCG_REG_EDX);
763 }
764 break;
765 }
766
767 /* jmp label2 */
da441cff 768 tcg_out8(s, OPC_JMP_short);
c896fe29
FB
769 label2_ptr = s->code_ptr;
770 s->code_ptr++;
771
772 /* label1: */
773 *label1_ptr = s->code_ptr - label1_ptr - 1;
774
775 /* add x(r1), r0 */
81570a70
RH
776 tcg_out_modrm_offset(s, OPC_ADD_GvEv, r0, r1,
777 offsetof(CPUTLBEntry, addend) -
c896fe29
FB
778 offsetof(CPUTLBEntry, addr_read));
779#else
780 r0 = addr_reg;
781#endif
782
783#ifdef TARGET_WORDS_BIGENDIAN
784 bswap = 1;
785#else
786 bswap = 0;
787#endif
788 switch(opc) {
789 case 0:
790 /* movzbl */
55e082a7 791 tcg_out_modrm_offset(s, OPC_MOVZBL, data_reg, r0, GUEST_BASE);
c896fe29
FB
792 break;
793 case 0 | 4:
794 /* movsbl */
6817c355 795 tcg_out_modrm_offset(s, OPC_MOVSBL, data_reg, r0, GUEST_BASE);
c896fe29
FB
796 break;
797 case 1:
798 /* movzwl */
55e082a7 799 tcg_out_modrm_offset(s, OPC_MOVZWL, data_reg, r0, GUEST_BASE);
c896fe29 800 if (bswap) {
fcb5dac1 801 tcg_out_rolw_8(s, data_reg);
c896fe29
FB
802 }
803 break;
804 case 1 | 4:
805 /* movswl */
6817c355 806 tcg_out_modrm_offset(s, OPC_MOVSWL, data_reg, r0, GUEST_BASE);
c896fe29 807 if (bswap) {
fcb5dac1 808 tcg_out_rolw_8(s, data_reg);
c896fe29
FB
809
810 /* movswl data_reg, data_reg */
6817c355 811 tcg_out_modrm(s, OPC_MOVSWL, data_reg, data_reg);
c896fe29
FB
812 }
813 break;
814 case 2:
af266089 815 tcg_out_ld(s, TCG_TYPE_I32, data_reg, r0, GUEST_BASE);
c896fe29 816 if (bswap) {
fcb5dac1 817 tcg_out_bswap32(s, data_reg);
c896fe29
FB
818 }
819 break;
820 case 3:
a042ef94
RH
821 if (bswap) {
822 int t = data_reg;
823 data_reg = data_reg2;
824 data_reg2 = t;
c896fe29 825 }
a042ef94 826 if (r0 != data_reg) {
af266089
RH
827 tcg_out_ld(s, TCG_TYPE_I32, data_reg, r0, GUEST_BASE);
828 tcg_out_ld(s, TCG_TYPE_I32, data_reg2, r0, GUEST_BASE + 4);
c896fe29 829 } else {
a042ef94
RH
830 tcg_out_ld(s, TCG_TYPE_I32, data_reg2, r0, GUEST_BASE + 4);
831 tcg_out_ld(s, TCG_TYPE_I32, data_reg, r0, GUEST_BASE);
832 }
833 if (bswap) {
fcb5dac1 834 tcg_out_bswap32(s, data_reg);
fcb5dac1 835 tcg_out_bswap32(s, data_reg2);
c896fe29
FB
836 }
837 break;
838 default:
839 tcg_abort();
840 }
841
842#if defined(CONFIG_SOFTMMU)
843 /* label2: */
844 *label2_ptr = s->code_ptr - label2_ptr - 1;
845#endif
846}
847
848
849static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
850 int opc)
851{
852 int addr_reg, data_reg, data_reg2, r0, r1, mem_index, s_bits, bswap;
853#if defined(CONFIG_SOFTMMU)
aadb21a4 854 int stack_adjust;
c896fe29
FB
855 uint8_t *label1_ptr, *label2_ptr;
856#endif
857#if TARGET_LONG_BITS == 64
858#if defined(CONFIG_SOFTMMU)
859 uint8_t *label3_ptr;
860#endif
861 int addr_reg2;
862#endif
863
864 data_reg = *args++;
865 if (opc == 3)
866 data_reg2 = *args++;
867 else
868 data_reg2 = 0;
869 addr_reg = *args++;
870#if TARGET_LONG_BITS == 64
871 addr_reg2 = *args++;
872#endif
873 mem_index = *args;
874
875 s_bits = opc;
876
877 r0 = TCG_REG_EAX;
878 r1 = TCG_REG_EDX;
879
880#if defined(CONFIG_SOFTMMU)
881 tcg_out_mov(s, r1, addr_reg);
c896fe29
FB
882 tcg_out_mov(s, r0, addr_reg);
883
f53dba01
RH
884 tcg_out_shifti(s, SHIFT_SHR, r1, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS);
885
a369a702
RH
886 tgen_arithi(s, ARITH_AND, r0, TARGET_PAGE_MASK | ((1 << s_bits) - 1), 0);
887 tgen_arithi(s, ARITH_AND, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS, 0);
c896fe29
FB
888
889 tcg_out_opc(s, 0x8d); /* lea offset(r1, %ebp), r1 */
890 tcg_out8(s, 0x80 | (r1 << 3) | 0x04);
891 tcg_out8(s, (5 << 3) | r1);
892 tcg_out32(s, offsetof(CPUState, tlb_table[mem_index][0].addr_write));
893
894 /* cmp 0(r1), r0 */
81570a70 895 tcg_out_modrm_offset(s, OPC_CMP_GvEv, r0, r1, 0);
c896fe29
FB
896
897 tcg_out_mov(s, r0, addr_reg);
898
899#if TARGET_LONG_BITS == 32
900 /* je label1 */
da441cff 901 tcg_out8(s, OPC_JCC_short + JCC_JE);
c896fe29
FB
902 label1_ptr = s->code_ptr;
903 s->code_ptr++;
904#else
905 /* jne label3 */
da441cff 906 tcg_out8(s, OPC_JCC_short + JCC_JNE);
c896fe29
FB
907 label3_ptr = s->code_ptr;
908 s->code_ptr++;
909
910 /* cmp 4(r1), addr_reg2 */
81570a70 911 tcg_out_modrm_offset(s, OPC_CMP_GvEv, addr_reg2, r1, 4);
c896fe29
FB
912
913 /* je label1 */
da441cff 914 tcg_out8(s, OPC_JCC_short + JCC_JE);
c896fe29
FB
915 label1_ptr = s->code_ptr;
916 s->code_ptr++;
917
918 /* label3: */
919 *label3_ptr = s->code_ptr - label3_ptr - 1;
920#endif
921
922 /* XXX: move that code at the end of the TB */
923#if TARGET_LONG_BITS == 32
924 if (opc == 3) {
925 tcg_out_mov(s, TCG_REG_EDX, data_reg);
926 tcg_out_mov(s, TCG_REG_ECX, data_reg2);
6858614e 927 tcg_out_pushi(s, mem_index);
aadb21a4 928 stack_adjust = 4;
c896fe29
FB
929 } else {
930 switch(opc) {
931 case 0:
55e082a7 932 tcg_out_ext8u(s, TCG_REG_EDX, data_reg);
c896fe29
FB
933 break;
934 case 1:
55e082a7 935 tcg_out_ext16u(s, TCG_REG_EDX, data_reg);
c896fe29
FB
936 break;
937 case 2:
938 tcg_out_mov(s, TCG_REG_EDX, data_reg);
939 break;
940 }
941 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_ECX, mem_index);
aadb21a4 942 stack_adjust = 0;
c896fe29
FB
943 }
944#else
945 if (opc == 3) {
946 tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
6858614e
RH
947 tcg_out_pushi(s, mem_index);
948 tcg_out_push(s, data_reg2);
949 tcg_out_push(s, data_reg);
aadb21a4 950 stack_adjust = 12;
c896fe29
FB
951 } else {
952 tcg_out_mov(s, TCG_REG_EDX, addr_reg2);
953 switch(opc) {
954 case 0:
55e082a7 955 tcg_out_ext8u(s, TCG_REG_ECX, data_reg);
c896fe29
FB
956 break;
957 case 1:
55e082a7 958 tcg_out_ext16u(s, TCG_REG_ECX, data_reg);
c896fe29
FB
959 break;
960 case 2:
961 tcg_out_mov(s, TCG_REG_ECX, data_reg);
962 break;
963 }
6858614e 964 tcg_out_pushi(s, mem_index);
aadb21a4 965 stack_adjust = 4;
c896fe29
FB
966 }
967#endif
aadb21a4
RH
968
969 tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]);
970
971 if (stack_adjust == 4) {
972 /* Pop and discard. This is 2 bytes smaller than the add. */
973 tcg_out_pop(s, TCG_REG_ECX);
974 } else if (stack_adjust != 0) {
975 tcg_out_addi(s, TCG_REG_ESP, stack_adjust);
976 }
977
c896fe29 978 /* jmp label2 */
da441cff 979 tcg_out8(s, OPC_JMP_short);
c896fe29
FB
980 label2_ptr = s->code_ptr;
981 s->code_ptr++;
982
983 /* label1: */
984 *label1_ptr = s->code_ptr - label1_ptr - 1;
985
986 /* add x(r1), r0 */
81570a70
RH
987 tcg_out_modrm_offset(s, OPC_ADD_GvEv, r0, r1,
988 offsetof(CPUTLBEntry, addend) -
c896fe29
FB
989 offsetof(CPUTLBEntry, addr_write));
990#else
991 r0 = addr_reg;
992#endif
993
994#ifdef TARGET_WORDS_BIGENDIAN
995 bswap = 1;
996#else
997 bswap = 0;
998#endif
999 switch(opc) {
1000 case 0:
af266089 1001 tcg_out_modrm_offset(s, OPC_MOVB_EvGv, data_reg, r0, GUEST_BASE);
c896fe29
FB
1002 break;
1003 case 1:
1004 if (bswap) {
1005 tcg_out_mov(s, r1, data_reg);
fcb5dac1 1006 tcg_out_rolw_8(s, r1);
c896fe29
FB
1007 data_reg = r1;
1008 }
1009 /* movw */
1010 tcg_out8(s, 0x66);
af266089 1011 tcg_out_modrm_offset(s, OPC_MOVL_EvGv, data_reg, r0, GUEST_BASE);
c896fe29
FB
1012 break;
1013 case 2:
1014 if (bswap) {
1015 tcg_out_mov(s, r1, data_reg);
fcb5dac1 1016 tcg_out_bswap32(s, r1);
c896fe29
FB
1017 data_reg = r1;
1018 }
af266089 1019 tcg_out_st(s, TCG_TYPE_I32, data_reg, r0, GUEST_BASE);
c896fe29
FB
1020 break;
1021 case 3:
1022 if (bswap) {
1023 tcg_out_mov(s, r1, data_reg2);
fcb5dac1 1024 tcg_out_bswap32(s, r1);
af266089 1025 tcg_out_st(s, TCG_TYPE_I32, r1, r0, GUEST_BASE);
c896fe29 1026 tcg_out_mov(s, r1, data_reg);
fcb5dac1 1027 tcg_out_bswap32(s, r1);
af266089 1028 tcg_out_st(s, TCG_TYPE_I32, r1, r0, GUEST_BASE + 4);
c896fe29 1029 } else {
af266089
RH
1030 tcg_out_st(s, TCG_TYPE_I32, data_reg, r0, GUEST_BASE);
1031 tcg_out_st(s, TCG_TYPE_I32, data_reg2, r0, GUEST_BASE + 4);
c896fe29
FB
1032 }
1033 break;
1034 default:
1035 tcg_abort();
1036 }
1037
1038#if defined(CONFIG_SOFTMMU)
1039 /* label2: */
1040 *label2_ptr = s->code_ptr - label2_ptr - 1;
1041#endif
1042}
1043
a9751609 1044static inline void tcg_out_op(TCGContext *s, TCGOpcode opc,
c896fe29
FB
1045 const TCGArg *args, const int *const_args)
1046{
1047 int c;
1048
1049 switch(opc) {
1050 case INDEX_op_exit_tb:
1051 tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_EAX, args[0]);
da441cff 1052 tcg_out8(s, OPC_JMP_long); /* jmp tb_ret_addr */
b03cce8e 1053 tcg_out32(s, tb_ret_addr - s->code_ptr - 4);
c896fe29
FB
1054 break;
1055 case INDEX_op_goto_tb:
1056 if (s->tb_jmp_offset) {
1057 /* direct jump method */
da441cff 1058 tcg_out8(s, OPC_JMP_long); /* jmp im */
c896fe29
FB
1059 s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf;
1060 tcg_out32(s, 0);
1061 } else {
1062 /* indirect jump method */
da441cff 1063 tcg_out_modrm_offset(s, 0xff, EXT_JMPN_Ev, -1,
c896fe29
FB
1064 (tcg_target_long)(s->tb_next + args[0]));
1065 }
1066 s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf;
1067 break;
1068 case INDEX_op_call:
1069 if (const_args[0]) {
aadb21a4 1070 tcg_out_calli(s, args[0]);
c896fe29 1071 } else {
aadb21a4
RH
1072 /* call *reg */
1073 tcg_out_modrm(s, 0xff, EXT_CALLN_Ev, args[0]);
c896fe29
FB
1074 }
1075 break;
1076 case INDEX_op_jmp:
1077 if (const_args[0]) {
da441cff 1078 tcg_out8(s, OPC_JMP_long);
c896fe29
FB
1079 tcg_out32(s, args[0] - (tcg_target_long)s->code_ptr - 4);
1080 } else {
da441cff
RH
1081 /* jmp *reg */
1082 tcg_out_modrm(s, 0xff, EXT_JMPN_Ev, args[0]);
c896fe29
FB
1083 }
1084 break;
1085 case INDEX_op_br:
f75b56c1 1086 tcg_out_jxx(s, JCC_JMP, args[0], 0);
c896fe29
FB
1087 break;
1088 case INDEX_op_movi_i32:
1089 tcg_out_movi(s, TCG_TYPE_I32, args[0], args[1]);
1090 break;
1091 case INDEX_op_ld8u_i32:
1092 /* movzbl */
55e082a7 1093 tcg_out_modrm_offset(s, OPC_MOVZBL, args[0], args[1], args[2]);
c896fe29
FB
1094 break;
1095 case INDEX_op_ld8s_i32:
1096 /* movsbl */
6817c355 1097 tcg_out_modrm_offset(s, OPC_MOVSBL, args[0], args[1], args[2]);
c896fe29
FB
1098 break;
1099 case INDEX_op_ld16u_i32:
1100 /* movzwl */
55e082a7 1101 tcg_out_modrm_offset(s, OPC_MOVZWL, args[0], args[1], args[2]);
c896fe29
FB
1102 break;
1103 case INDEX_op_ld16s_i32:
1104 /* movswl */
6817c355 1105 tcg_out_modrm_offset(s, OPC_MOVSWL, args[0], args[1], args[2]);
c896fe29
FB
1106 break;
1107 case INDEX_op_ld_i32:
af266089 1108 tcg_out_ld(s, TCG_TYPE_I32, args[0], args[1], args[2]);
c896fe29
FB
1109 break;
1110 case INDEX_op_st8_i32:
1111 /* movb */
af266089 1112 tcg_out_modrm_offset(s, OPC_MOVB_EvGv, args[0], args[1], args[2]);
c896fe29
FB
1113 break;
1114 case INDEX_op_st16_i32:
1115 /* movw */
1116 tcg_out8(s, 0x66);
af266089 1117 tcg_out_modrm_offset(s, OPC_MOVL_EvGv, args[0], args[1], args[2]);
c896fe29
FB
1118 break;
1119 case INDEX_op_st_i32:
af266089 1120 tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]);
c896fe29
FB
1121 break;
1122 case INDEX_op_sub_i32:
1123 c = ARITH_SUB;
1124 goto gen_arith;
1125 case INDEX_op_and_i32:
1126 c = ARITH_AND;
1127 goto gen_arith;
1128 case INDEX_op_or_i32:
1129 c = ARITH_OR;
1130 goto gen_arith;
1131 case INDEX_op_xor_i32:
1132 c = ARITH_XOR;
1133 goto gen_arith;
1134 case INDEX_op_add_i32:
1135 c = ARITH_ADD;
1136 gen_arith:
1137 if (const_args[2]) {
17cf428f 1138 tgen_arithi(s, c, args[0], args[2], 0);
c896fe29 1139 } else {
81570a70 1140 tgen_arithr(s, c, args[0], args[2]);
c896fe29
FB
1141 }
1142 break;
1143 case INDEX_op_mul_i32:
1144 if (const_args[2]) {
1145 int32_t val;
1146 val = args[2];
1147 if (val == (int8_t)val) {
1148 tcg_out_modrm(s, 0x6b, args[0], args[0]);
1149 tcg_out8(s, val);
1150 } else {
1151 tcg_out_modrm(s, 0x69, args[0], args[0]);
1152 tcg_out32(s, val);
1153 }
1154 } else {
1155 tcg_out_modrm(s, 0xaf | P_EXT, args[0], args[2]);
1156 }
1157 break;
1158 case INDEX_op_mulu2_i32:
1159 tcg_out_modrm(s, 0xf7, 4, args[3]);
1160 break;
1161 case INDEX_op_div2_i32:
1162 tcg_out_modrm(s, 0xf7, 7, args[4]);
1163 break;
1164 case INDEX_op_divu2_i32:
1165 tcg_out_modrm(s, 0xf7, 6, args[4]);
1166 break;
1167 case INDEX_op_shl_i32:
1168 c = SHIFT_SHL;
1169 gen_shift32:
1170 if (const_args[2]) {
f53dba01 1171 tcg_out_shifti(s, c, args[0], args[2]);
c896fe29 1172 } else {
f53dba01 1173 tcg_out_modrm(s, OPC_SHIFT_cl, c, args[0]);
c896fe29
FB
1174 }
1175 break;
1176 case INDEX_op_shr_i32:
1177 c = SHIFT_SHR;
1178 goto gen_shift32;
1179 case INDEX_op_sar_i32:
1180 c = SHIFT_SAR;
1181 goto gen_shift32;
9619376c
AJ
1182 case INDEX_op_rotl_i32:
1183 c = SHIFT_ROL;
1184 goto gen_shift32;
1185 case INDEX_op_rotr_i32:
1186 c = SHIFT_ROR;
1187 goto gen_shift32;
1188
c896fe29 1189 case INDEX_op_add2_i32:
81570a70 1190 if (const_args[4]) {
17cf428f 1191 tgen_arithi(s, ARITH_ADD, args[0], args[4], 1);
81570a70
RH
1192 } else {
1193 tgen_arithr(s, ARITH_ADD, args[0], args[4]);
1194 }
1195 if (const_args[5]) {
17cf428f 1196 tgen_arithi(s, ARITH_ADC, args[1], args[5], 1);
81570a70
RH
1197 } else {
1198 tgen_arithr(s, ARITH_ADC, args[1], args[5]);
1199 }
c896fe29
FB
1200 break;
1201 case INDEX_op_sub2_i32:
81570a70 1202 if (const_args[4]) {
17cf428f 1203 tgen_arithi(s, ARITH_SUB, args[0], args[4], 1);
81570a70
RH
1204 } else {
1205 tgen_arithr(s, ARITH_SUB, args[0], args[4]);
1206 }
1207 if (const_args[5]) {
17cf428f 1208 tgen_arithi(s, ARITH_SBB, args[1], args[5], 1);
81570a70
RH
1209 } else {
1210 tgen_arithr(s, ARITH_SBB, args[1], args[5]);
1211 }
c896fe29
FB
1212 break;
1213 case INDEX_op_brcond_i32:
f75b56c1
RH
1214 tcg_out_brcond(s, args[2], args[0], args[1], const_args[1],
1215 args[3], 0);
c896fe29
FB
1216 break;
1217 case INDEX_op_brcond2_i32:
f75b56c1 1218 tcg_out_brcond2(s, args, const_args, 0);
c896fe29
FB
1219 break;
1220
5d40cd63 1221 case INDEX_op_bswap16_i32:
fcb5dac1 1222 tcg_out_rolw_8(s, args[0]);
5d40cd63 1223 break;
66896cb8 1224 case INDEX_op_bswap32_i32:
fcb5dac1 1225 tcg_out_bswap32(s, args[0]);
9619376c
AJ
1226 break;
1227
1228 case INDEX_op_neg_i32:
1229 tcg_out_modrm(s, 0xf7, 3, args[0]);
1230 break;
1231
1232 case INDEX_op_not_i32:
1233 tcg_out_modrm(s, 0xf7, 2, args[0]);
1234 break;
1235
1236 case INDEX_op_ext8s_i32:
6817c355 1237 tcg_out_ext8s(s, args[0], args[1]);
9619376c
AJ
1238 break;
1239 case INDEX_op_ext16s_i32:
6817c355 1240 tcg_out_ext16s(s, args[0], args[1]);
9619376c 1241 break;
5f0ce17f 1242 case INDEX_op_ext8u_i32:
55e082a7 1243 tcg_out_ext8u(s, args[0], args[1]);
5f0ce17f
AJ
1244 break;
1245 case INDEX_op_ext16u_i32:
55e082a7 1246 tcg_out_ext16u(s, args[0], args[1]);
5f0ce17f 1247 break;
9619376c 1248
1d2699ae
RH
1249 case INDEX_op_setcond_i32:
1250 tcg_out_setcond(s, args[3], args[0], args[1], args[2], const_args[2]);
1251 break;
1252 case INDEX_op_setcond2_i32:
1253 tcg_out_setcond2(s, args, const_args);
1254 break;
1255
c896fe29
FB
1256 case INDEX_op_qemu_ld8u:
1257 tcg_out_qemu_ld(s, args, 0);
1258 break;
1259 case INDEX_op_qemu_ld8s:
1260 tcg_out_qemu_ld(s, args, 0 | 4);
1261 break;
1262 case INDEX_op_qemu_ld16u:
1263 tcg_out_qemu_ld(s, args, 1);
1264 break;
1265 case INDEX_op_qemu_ld16s:
1266 tcg_out_qemu_ld(s, args, 1 | 4);
1267 break;
86feb1c8 1268 case INDEX_op_qemu_ld32:
c896fe29
FB
1269 tcg_out_qemu_ld(s, args, 2);
1270 break;
1271 case INDEX_op_qemu_ld64:
1272 tcg_out_qemu_ld(s, args, 3);
1273 break;
1274
1275 case INDEX_op_qemu_st8:
1276 tcg_out_qemu_st(s, args, 0);
1277 break;
1278 case INDEX_op_qemu_st16:
1279 tcg_out_qemu_st(s, args, 1);
1280 break;
1281 case INDEX_op_qemu_st32:
1282 tcg_out_qemu_st(s, args, 2);
1283 break;
1284 case INDEX_op_qemu_st64:
1285 tcg_out_qemu_st(s, args, 3);
1286 break;
1287
1288 default:
1289 tcg_abort();
1290 }
1291}
1292
1293static const TCGTargetOpDef x86_op_defs[] = {
1294 { INDEX_op_exit_tb, { } },
1295 { INDEX_op_goto_tb, { } },
1296 { INDEX_op_call, { "ri" } },
1297 { INDEX_op_jmp, { "ri" } },
1298 { INDEX_op_br, { } },
1299 { INDEX_op_mov_i32, { "r", "r" } },
1300 { INDEX_op_movi_i32, { "r" } },
1301 { INDEX_op_ld8u_i32, { "r", "r" } },
1302 { INDEX_op_ld8s_i32, { "r", "r" } },
1303 { INDEX_op_ld16u_i32, { "r", "r" } },
1304 { INDEX_op_ld16s_i32, { "r", "r" } },
1305 { INDEX_op_ld_i32, { "r", "r" } },
1306 { INDEX_op_st8_i32, { "q", "r" } },
1307 { INDEX_op_st16_i32, { "r", "r" } },
1308 { INDEX_op_st_i32, { "r", "r" } },
1309
1310 { INDEX_op_add_i32, { "r", "0", "ri" } },
1311 { INDEX_op_sub_i32, { "r", "0", "ri" } },
1312 { INDEX_op_mul_i32, { "r", "0", "ri" } },
1313 { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } },
1314 { INDEX_op_div2_i32, { "a", "d", "0", "1", "r" } },
1315 { INDEX_op_divu2_i32, { "a", "d", "0", "1", "r" } },
1316 { INDEX_op_and_i32, { "r", "0", "ri" } },
1317 { INDEX_op_or_i32, { "r", "0", "ri" } },
1318 { INDEX_op_xor_i32, { "r", "0", "ri" } },
1319
1320 { INDEX_op_shl_i32, { "r", "0", "ci" } },
1321 { INDEX_op_shr_i32, { "r", "0", "ci" } },
1322 { INDEX_op_sar_i32, { "r", "0", "ci" } },
9619376c
AJ
1323 { INDEX_op_rotl_i32, { "r", "0", "ci" } },
1324 { INDEX_op_rotr_i32, { "r", "0", "ci" } },
c896fe29
FB
1325
1326 { INDEX_op_brcond_i32, { "r", "ri" } },
1327
1328 { INDEX_op_add2_i32, { "r", "r", "0", "1", "ri", "ri" } },
1329 { INDEX_op_sub2_i32, { "r", "r", "0", "1", "ri", "ri" } },
1330 { INDEX_op_brcond2_i32, { "r", "r", "ri", "ri" } },
1331
5d40cd63 1332 { INDEX_op_bswap16_i32, { "r", "0" } },
66896cb8 1333 { INDEX_op_bswap32_i32, { "r", "0" } },
9619376c
AJ
1334
1335 { INDEX_op_neg_i32, { "r", "0" } },
1336
1337 { INDEX_op_not_i32, { "r", "0" } },
1338
1339 { INDEX_op_ext8s_i32, { "r", "q" } },
1340 { INDEX_op_ext16s_i32, { "r", "r" } },
55e082a7
RH
1341 { INDEX_op_ext8u_i32, { "r", "q" } },
1342 { INDEX_op_ext16u_i32, { "r", "r" } },
9619376c 1343
1d2699ae
RH
1344 { INDEX_op_setcond_i32, { "q", "r", "ri" } },
1345 { INDEX_op_setcond2_i32, { "r", "r", "r", "ri", "ri" } },
1346
c896fe29
FB
1347#if TARGET_LONG_BITS == 32
1348 { INDEX_op_qemu_ld8u, { "r", "L" } },
1349 { INDEX_op_qemu_ld8s, { "r", "L" } },
1350 { INDEX_op_qemu_ld16u, { "r", "L" } },
1351 { INDEX_op_qemu_ld16s, { "r", "L" } },
86feb1c8 1352 { INDEX_op_qemu_ld32, { "r", "L" } },
c896fe29
FB
1353 { INDEX_op_qemu_ld64, { "r", "r", "L" } },
1354
1355 { INDEX_op_qemu_st8, { "cb", "L" } },
1356 { INDEX_op_qemu_st16, { "L", "L" } },
1357 { INDEX_op_qemu_st32, { "L", "L" } },
1358 { INDEX_op_qemu_st64, { "L", "L", "L" } },
1359#else
1360 { INDEX_op_qemu_ld8u, { "r", "L", "L" } },
1361 { INDEX_op_qemu_ld8s, { "r", "L", "L" } },
1362 { INDEX_op_qemu_ld16u, { "r", "L", "L" } },
1363 { INDEX_op_qemu_ld16s, { "r", "L", "L" } },
86feb1c8 1364 { INDEX_op_qemu_ld32, { "r", "L", "L" } },
c896fe29
FB
1365 { INDEX_op_qemu_ld64, { "r", "r", "L", "L" } },
1366
1367 { INDEX_op_qemu_st8, { "cb", "L", "L" } },
1368 { INDEX_op_qemu_st16, { "L", "L", "L" } },
1369 { INDEX_op_qemu_st32, { "L", "L", "L" } },
1370 { INDEX_op_qemu_st64, { "L", "L", "L", "L" } },
1371#endif
1372 { -1 },
1373};
1374
b03cce8e
FB
1375static int tcg_target_callee_save_regs[] = {
1376 /* TCG_REG_EBP, */ /* currently used for the global env, so no
1377 need to save */
1378 TCG_REG_EBX,
1379 TCG_REG_ESI,
1380 TCG_REG_EDI,
1381};
1382
b03cce8e
FB
1383/* Generate global QEMU prologue and epilogue code */
1384void tcg_target_qemu_prologue(TCGContext *s)
1385{
1386 int i, frame_size, push_size, stack_addend;
1387
1388 /* TB prologue */
1389 /* save all callee saved registers */
1390 for(i = 0; i < ARRAY_SIZE(tcg_target_callee_save_regs); i++) {
1391 tcg_out_push(s, tcg_target_callee_save_regs[i]);
1392 }
1393 /* reserve some stack space */
1394 push_size = 4 + ARRAY_SIZE(tcg_target_callee_save_regs) * 4;
1395 frame_size = push_size + TCG_STATIC_CALL_ARGS_SIZE;
1396 frame_size = (frame_size + TCG_TARGET_STACK_ALIGN - 1) &
1397 ~(TCG_TARGET_STACK_ALIGN - 1);
1398 stack_addend = frame_size - push_size;
1399 tcg_out_addi(s, TCG_REG_ESP, -stack_addend);
1400
da441cff 1401 tcg_out_modrm(s, 0xff, EXT_JMPN_Ev, TCG_REG_EAX); /* jmp *%eax */
b03cce8e
FB
1402
1403 /* TB epilogue */
1404 tb_ret_addr = s->code_ptr;
1405 tcg_out_addi(s, TCG_REG_ESP, stack_addend);
1406 for(i = ARRAY_SIZE(tcg_target_callee_save_regs) - 1; i >= 0; i--) {
1407 tcg_out_pop(s, tcg_target_callee_save_regs[i]);
1408 }
3c3accc6 1409 tcg_out_opc(s, OPC_RET);
b03cce8e
FB
1410}
1411
c896fe29
FB
1412void tcg_target_init(TCGContext *s)
1413{
20cb400d 1414#if !defined(CONFIG_USER_ONLY)
c896fe29
FB
1415 /* fail safe */
1416 if ((1 << CPU_TLB_ENTRY_BITS) != sizeof(CPUTLBEntry))
1417 tcg_abort();
20cb400d 1418#endif
c896fe29
FB
1419
1420 tcg_regset_set32(tcg_target_available_regs[TCG_TYPE_I32], 0, 0xff);
4ab50ccf
RH
1421
1422 tcg_regset_clear(tcg_target_call_clobber_regs);
1423 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EAX);
1424 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_EDX);
1425 tcg_regset_set_reg(tcg_target_call_clobber_regs, TCG_REG_ECX);
1426
c896fe29
FB
1427 tcg_regset_clear(s->reserved_regs);
1428 tcg_regset_set_reg(s->reserved_regs, TCG_REG_ESP);
1429
1430 tcg_add_target_add_op_defs(x86_op_defs);
1431}