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