Fixed compilation error in i386-asm.c
[tinycc/kirr.git] / x86_64-asm.c
blob228ae3a9de438844a6c41340f86f57aae1e5767d
1 /*
2 * x86_64 specific functions for TCC assembler
4 * Copyright (c) 2009 Frédéric Feret
6 * Based on i386-asm.c by Fabrice Bellard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #define MAX_OPERANDS 3
25 typedef struct ASMInstr {
26 uint16_t sym;
27 uint16_t opcode;
28 uint16_t instr_type;
29 #define OPC_JMP 0x01 /* jmp operand */
30 #define OPC_B 0x02 /* only used zith OPC_WL */
31 #define OPC_WL 0x04 /* accepts w, l or no suffix */
32 #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
33 #define OPC_REG 0x08 /* register is added to opcode */
34 #define OPC_MODRM 0x10 /* modrm encoding */
35 #define OPC_FWAIT 0x20 /* add fwait opcode */
36 #define OPC_TEST 0x40 /* test opcodes */
37 #define OPC_SHIFT 0x80 /* shift opcodes */
38 #define OPC_D16 0x0100 /* generate data16 prefix */
39 #define OPC_ARITH 0x0200 /* arithmetic opcodes */
40 #define OPC_SHORTJMP 0x0400 /* short jmp operand */
41 #define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */
42 #define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
43 #define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
44 #define OPC_GROUP_SHIFT 13
46 /* in order to compress the operand type, we use specific operands and
47 we or only with EA */
48 #define OPT_REG8 0 /* warning: value is hardcoded from TOK_ASM_xxx */
49 #define OPT_REG16 1 /* warning: value is hardcoded from TOK_ASM_xxx */
50 #define OPT_REG32 2 /* warning: value is hardcoded from TOK_ASM_xxx */
51 #define OPT_REG64 3
52 #define OPT_MMX 4 /* warning: value is hardcoded from TOK_ASM_xxx */
53 #define OPT_SSE 5 /* warning: value is hardcoded from TOK_ASM_xxx */
54 #define OPT_CR 6 /* warning: value is hardcoded from TOK_ASM_xxx */
55 #define OPT_TR 7 /* warning: value is hardcoded from TOK_ASM_xxx */
56 #define OPT_DB 8 /* warning: value is hardcoded from TOK_ASM_xxx */
57 #define OPT_SEG 9
58 #define OPT_ST 10
59 #define OPT_IM8 11
60 #define OPT_IM8S 12
61 #define OPT_IM16 13
62 #define OPT_IM32 14
63 #define OPT_IM64 15
64 #define OPT_EAX 16 /* %al, %ax, %eax or %rax register */
65 #define OPT_ST0 17 /* %st(0) register */
66 #define OPT_CL 18 /* %cl register */
67 #define OPT_DX 19 /* %dx register */
68 #define OPT_ADDR 20 /* OP_EA with only offset */
69 #define OPT_INDIR 21 /* *(expr) */
71 /* composite types */
72 #define OPT_COMPOSITE_FIRST 22
73 #define OPT_IM 23 /* IM8 | IM16 | IM32 | IM64 */
74 #define OPT_REG 24 /* REG8 | REG16 | REG32 | REG64 */
75 #define OPT_REGW 25 /* REG16 | REG32 | REG64 */
76 #define OPT_IMW 26 /* IM16 | IM32 | IM64 */
77 #define OPT_IMNO64 27 /* IM16 | IM32 */
79 /* can be ored with any OPT_xxx */
80 #define OPT_EA 0x80
82 uint8_t nb_ops;
83 uint8_t op_type[MAX_OPERANDS]; /* see OP_xxx */
84 } ASMInstr;
86 typedef struct Operand {
87 uint32_t type;
88 #define OP_REG8 (1 << OPT_REG8)
89 #define OP_REG16 (1 << OPT_REG16)
90 #define OP_REG32 (1 << OPT_REG32)
91 #define OP_MMX (1 << OPT_MMX)
92 #define OP_SSE (1 << OPT_SSE)
93 #define OP_CR (1 << OPT_CR)
94 #define OP_TR (1 << OPT_TR)
95 #define OP_DB (1 << OPT_DB)
96 #define OP_SEG (1 << OPT_SEG)
97 #define OP_ST (1 << OPT_ST)
98 #define OP_IM8 (1 << OPT_IM8)
99 #define OP_IM8S (1 << OPT_IM8S)
100 #define OP_IM16 (1 << OPT_IM16)
101 #define OP_IM32 (1 << OPT_IM32)
102 #define OP_EAX (1 << OPT_EAX)
103 #define OP_ST0 (1 << OPT_ST0)
104 #define OP_CL (1 << OPT_CL)
105 #define OP_DX (1 << OPT_DX)
106 #define OP_ADDR (1 << OPT_ADDR)
107 #define OP_INDIR (1 << OPT_INDIR)
108 #define OP_REG64 (1 << OPT_REG64)
109 #define OP_IM64 (1 << OPT_IM64)
111 #define OP_EA 0x40000000
112 #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
113 #define OP_IM OP_IM64
114 int8_t reg; /* register, -1 if none */
115 int8_t reg2; /* second register, -1 if none */
116 uint8_t shift;
117 ExprValue e;
118 } Operand;
120 static const uint8_t reg_to_size[7] = {
122 [OP_REG8] = 0,
123 [OP_REG16] = 1,
124 [OP_REG32] = 2,
125 [OP_REG64] = 3,
127 0, 0, 1, 0, 2, 0, 3
130 #define NB_TEST_OPCODES 30
132 static const uint8_t test_bits[NB_TEST_OPCODES] = {
133 0x00, /* o */
134 0x01, /* no */
135 0x02, /* b */
136 0x02, /* c */
137 0x02, /* nae */
138 0x03, /* nb */
139 0x03, /* nc */
140 0x03, /* ae */
141 0x04, /* e */
142 0x04, /* z */
143 0x05, /* ne */
144 0x05, /* nz */
145 0x06, /* be */
146 0x06, /* na */
147 0x07, /* nbe */
148 0x07, /* a */
149 0x08, /* s */
150 0x09, /* ns */
151 0x0a, /* p */
152 0x0a, /* pe */
153 0x0b, /* np */
154 0x0b, /* po */
155 0x0c, /* l */
156 0x0c, /* nge */
157 0x0d, /* nl */
158 0x0d, /* ge */
159 0x0e, /* le */
160 0x0e, /* ng */
161 0x0f, /* nle */
162 0x0f, /* g */
165 static const uint8_t segment_prefixes[] = {
166 0x26, /* es */
167 0x2e, /* cs */
168 0x36, /* ss */
169 0x3e, /* ds */
170 0x64, /* fs */
171 0x65 /* gs */
174 static const ASMInstr asm_instrs[] = {
175 #define ALT(x) x
176 #define DEF_ASM_OP0(name, opcode)
177 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 },
178 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},
179 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},
180 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 3, { op0, op1, op2 }},
181 #include "x86_64-asm.h"
183 /* last operation */
184 { 0, },
187 static const uint16_t op0_codes[] = {
188 #define ALT(x)
189 #define DEF_ASM_OP0(x, opcode) opcode,
190 #define DEF_ASM_OP0L(name, opcode, group, instr_type)
191 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
192 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
193 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
194 #include "x86_64-asm.h"
197 static inline int get_reg_shift(TCCState *s1)
199 int shift, v;
201 v = asm_int_expr(s1);
202 switch(v) {
203 case 1:
204 shift = 0;
205 break;
206 case 2:
207 shift = 1;
208 break;
209 case 4:
210 shift = 2;
211 break;
212 case 8:
213 shift = 3;
214 break;
215 default:
216 expect("1, 2, 4 or 8 constant");
217 shift = 0;
218 break;
220 return shift;
223 static int asm_parse_reg(void)
225 int reg;
226 if (tok != '%')
227 goto error_32;
228 next();
229 if (tok >= TOK_ASM_rax && tok <= TOK_ASM_rdi) {
230 reg = tok - TOK_ASM_rax;
231 next();
232 return reg;
233 } else if (tok >= TOK_ASM_eax && tok <= TOK_ASM_edi) {
234 reg = tok - TOK_ASM_eax;
235 next();
236 return reg;
237 } else {
238 error_32:
239 expect("64 bit register");
240 return 0;
244 static void parse_operand(TCCState *s1, Operand *op)
246 ExprValue e;
247 int reg, indir;
248 const char *p;
250 indir = 0;
251 if (tok == '*') {
252 next();
253 indir = OP_INDIR;
256 if (tok == '%') {
257 next();
258 if (tok >= TOK_ASM_al && tok <= TOK_ASM_db7) {
259 reg = tok - TOK_ASM_al;
260 op->type = 1 << (reg >> 3); /* WARNING: do not change constant order */
261 op->reg = reg & 7;
262 if ((op->type & OP_REG) && op->reg == TREG_RAX)
263 op->type |= OP_EAX;
264 else if (op->type == OP_REG8 && op->reg == TREG_RCX)
265 op->type |= OP_CL;
266 else if (op->type == OP_REG16 && op->reg == TREG_RDX)
267 op->type |= OP_DX;
268 } else if (tok >= TOK_ASM_dr0 && tok <= TOK_ASM_dr7) {
269 op->type = OP_DB;
270 op->reg = tok - TOK_ASM_dr0;
271 } else if (tok >= TOK_ASM_es && tok <= TOK_ASM_gs) {
272 op->type = OP_SEG;
273 op->reg = tok - TOK_ASM_es;
274 } else if (tok == TOK_ASM_st) {
275 op->type = OP_ST;
276 op->reg = 0;
277 next();
278 if (tok == '(') {
279 next();
280 if (tok != TOK_PPNUM)
281 goto reg_error;
282 p = tokc.cstr->data;
283 reg = p[0] - '0';
284 if ((unsigned)reg >= 8 || p[1] != '\0')
285 goto reg_error;
286 op->reg = reg;
287 next();
288 skip(')');
290 if (op->reg == 0)
291 op->type |= OP_ST0;
292 goto no_skip;
293 } else {
294 reg_error:
295 error("unknown register");
297 next();
298 no_skip: ;
299 } else if (tok == '$') {
300 /* constant value */
301 next();
302 asm_expr(s1, &e);
303 op->type = OP_IM64;
304 op->e.v = e.v;
305 op->e.sym = e.sym;
306 if (!op->e.sym) {
307 if (op->e.v == (uint8_t)op->e.v)
308 op->type |= OP_IM8;
309 if (op->e.v == (int8_t)op->e.v)
310 op->type |= OP_IM8S;
311 if (op->e.v == (uint16_t)op->e.v)
312 op->type |= OP_IM16;
313 if (op->e.v == (uint32_t)op->e.v)
314 op->type |= OP_IM32;
316 } else {
317 /* address(reg,reg2,shift) with all variants */
318 op->type = OP_EA;
319 op->reg = -1;
320 op->reg2 = -1;
321 op->shift = 0;
322 if (tok != '(') {
323 asm_expr(s1, &e);
324 op->e.v = e.v;
325 op->e.sym = e.sym;
326 } else {
327 op->e.v = 0;
328 op->e.sym = NULL;
330 if (tok == '(') {
331 next();
332 if (tok != ',') {
333 op->reg = asm_parse_reg();
335 if (tok == ',') {
336 next();
337 if (tok != ',') {
338 op->reg2 = asm_parse_reg();
340 if (tok == ',') {
341 next();
342 op->shift = get_reg_shift(s1);
345 skip(')');
347 if (op->reg == -1 && op->reg2 == -1)
348 op->type |= OP_ADDR;
350 op->type |= indir;
353 /* XXX: unify with C code output ? */
354 static void gen_expr32(ExprValue *pe)
356 if (pe->sym)
357 greloc(cur_text_section, pe->sym, ind, R_X86_64_32);
358 gen_le32(pe->v);
361 static void gen_expr64(ExprValue *pe)
363 if (pe->sym)
364 greloc(cur_text_section, pe->sym, ind, R_X86_64_64);
365 gen_le64(pe->v);
368 /* XXX: unify with C code output ? */
369 static void gen_disp32(ExprValue *pe)
371 Sym *sym;
372 sym = pe->sym;
373 if (sym) {
374 if (sym->r == cur_text_section->sh_num) {
375 /* same section: we can output an absolute value. Note
376 that the TCC compiler behaves differently here because
377 it always outputs a relocation to ease (future) code
378 elimination in the linker */
379 gen_le32(pe->v + (long)sym->next - ind - 4);
380 } else {
381 greloc(cur_text_section, sym, ind, R_X86_64_PC32);
382 gen_le32(pe->v - 4);
384 } else {
385 /* put an empty PC32 relocation */
386 put_elf_reloc(symtab_section, cur_text_section,
387 ind, R_X86_64_PC32, 0);
388 gen_le32(pe->v - 4);
393 static void gen_le16(int v)
395 g(v);
396 g(v >> 8);
399 /* generate the modrm operand */
400 static inline void asm_modrm(int reg, Operand *op)
402 int mod, reg1, reg2, sib_reg1;
404 if (op->type & (OP_REG | OP_MMX | OP_SSE)) {
405 g(0xc0 + (reg << 3) + op->reg);
406 } else if (op->reg == -1 && op->reg2 == -1) {
407 /* displacement only */
408 g(0x05 + (reg << 3));
409 gen_expr32(&op->e);
410 } else {
411 sib_reg1 = op->reg;
412 /* fist compute displacement encoding */
413 if (sib_reg1 == -1) {
414 sib_reg1 = 5;
415 mod = 0x00;
416 } else if (op->e.v == 0 && !op->e.sym && op->reg != 5) {
417 mod = 0x00;
418 } else if (op->e.v == (int8_t)op->e.v && !op->e.sym) {
419 mod = 0x40;
420 } else {
421 mod = 0x80;
423 /* compute if sib byte needed */
424 reg1 = op->reg;
425 if (op->reg2 != -1)
426 reg1 = 4;
427 g(mod + (reg << 3) + reg1);
428 if (reg1 == 4) {
429 /* add sib byte */
430 reg2 = op->reg2;
431 if (reg2 == -1)
432 reg2 = 4; /* indicate no index */
433 g((op->shift << 6) + (reg2 << 3) + sib_reg1);
436 /* add offset */
437 if (mod == 0x40) {
438 g(op->e.v);
439 } else if (mod == 0x80 || op->reg == -1) {
440 gen_expr32(&op->e);
445 static void asm_opcode(TCCState *s1, int opcode)
447 const ASMInstr *pa;
448 int i, modrm_index, reg, v, op1, is_short_jmp, seg_prefix;
449 int nb_ops, s, ss;
450 Operand ops[MAX_OPERANDS], *pop;
451 int op_type[3]; /* decoded op type */
452 char rex;
454 /* get operands */
455 pop = ops;
456 nb_ops = 0;
457 seg_prefix = 0;
458 rex = 0x48;
459 for(;;) {
460 if (tok == ';' || tok == TOK_LINEFEED)
461 break;
462 if (nb_ops >= MAX_OPERANDS) {
463 error("incorrect number of operands");
465 parse_operand(s1, pop);
466 if (tok == ':') {
467 if (pop->type != OP_SEG || seg_prefix) {
468 error("incorrect prefix");
470 seg_prefix = segment_prefixes[pop->reg];
471 next();
472 parse_operand(s1, pop);
473 if (!(pop->type & OP_EA)) {
474 error("segment prefix must be followed by memory reference");
477 pop++;
478 nb_ops++;
479 if (tok != ',')
480 break;
481 next();
484 is_short_jmp = 0;
485 s = 0; /* avoid warning */
487 /* optimize matching by using a lookup table (no hashing is needed
488 !) */
489 for(pa = asm_instrs; pa->sym != 0; pa++) {
490 s = 0;
491 if (pa->instr_type & OPC_FARITH) {
492 v = opcode - pa->sym;
493 if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
494 continue;
495 } else if (pa->instr_type & OPC_ARITH) {
496 if (!(opcode >= pa->sym && opcode < pa->sym + 8 * 4))
497 continue;
498 goto compute_size;
499 } else if (pa->instr_type & OPC_SHIFT) {
500 if (!(opcode >= pa->sym && opcode < pa->sym + 7 * 4))
501 continue;
502 goto compute_size;
503 } else if (pa->instr_type & OPC_TEST) {
504 if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
505 continue;
506 } else if (pa->instr_type & OPC_B) {
507 if (!(opcode >= pa->sym && opcode <= pa->sym + 3))
508 continue;
509 compute_size:
510 s = (opcode - pa->sym) & 3;
511 } else if (pa->instr_type & OPC_WLQ) {
512 if (!(opcode >= pa->sym && opcode <= pa->sym + 2))
513 continue;
514 s = opcode - pa->sym + 1;
515 } else {
516 if (pa->sym != opcode)
517 continue;
519 if (pa->nb_ops != nb_ops)
520 continue;
521 /* now decode and check each operand */
522 for(i = 0; i < nb_ops; i++) {
523 int op1, op2;
524 op1 = pa->op_type[i];
525 op2 = op1 & 0x1f;
526 switch(op2) {
527 case OPT_IM:
528 v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
529 break;
530 case OPT_REG:
531 v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64;
532 break;
533 case OPT_REGW:
534 v = OP_REG16 | OP_REG32 | OP_REG64;
535 break;
536 case OPT_IMW:
537 v = OP_IM16 | OP_IM32 | OP_IM64;
538 break;
539 case OPT_IMNO64:
540 v = OP_IM16 | OP_IM32;
541 break;
542 default:
543 v = 1 << op2;
544 break;
546 if (op1 & OPT_EA)
547 v |= OP_EA;
548 op_type[i] = v;
549 if ((ops[i].type & v) == 0)
550 goto next;
552 /* all is matching ! */
553 break;
554 next: ;
556 if (pa->sym == 0) {
557 if (opcode >= TOK_ASM_clc && opcode <= TOK_ASM_emms) {
558 int b;
559 b = op0_codes[opcode - TOK_ASM_clc];
560 if (b & 0xff00)
561 g(b >> 8);
562 g(b);
563 return;
564 } else {
565 error("unknown opcode '%s'",
566 get_tok_str(opcode, NULL));
569 /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
570 if (s == 4) {
571 for(i = 0; s == 4 && i < nb_ops; i++) {
572 if ((ops[i].type & OP_REG) && !(op_type[i] & (OP_CL | OP_DX)))
573 s = reg_to_size[ops[i].type & OP_REG];
575 if (s == 4) {
576 if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
577 (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
578 s = 2;
579 else
580 error("cannot infer opcode suffix");
584 /* generate data16 prefix if needed */
585 ss = s;
586 if (s == 1 || (pa->instr_type & OPC_D16))
587 g(0x66);
588 else if (s == 2)
589 s = 1;
590 else if (s == 3) {
591 /* generate REX prefix */
592 g(rex);
593 s = 1;
595 /* now generates the operation */
596 if (pa->instr_type & OPC_FWAIT)
597 g(0x9b);
598 if (seg_prefix)
599 g(seg_prefix);
601 v = pa->opcode;
602 if (v == 0x69 || v == 0x69) {
603 /* kludge for imul $im, %reg */
604 nb_ops = 3;
605 ops[2] = ops[1];
606 } else if (v == 0xcd && ops[0].e.v == 3 && !ops[0].e.sym) {
607 v--; /* int $3 case */
608 nb_ops = 0;
609 } else if ((v == 0x06 || v == 0x07)) {
610 if (ops[0].reg >= 4) {
611 /* push/pop %fs or %gs */
612 v = 0x0fa0 + (v - 0x06) + ((ops[0].reg - 4) << 3);
613 } else {
614 v += ops[0].reg << 3;
616 nb_ops = 0;
617 } else if (v <= 0x05) {
618 /* arith case */
619 v += ((opcode - TOK_ASM_addb) >> 2) << 3;
620 } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {
621 /* fpu arith case */
622 v += ((opcode - pa->sym) / 6) << 3;
624 if (pa->instr_type & OPC_REG) {
625 for(i = 0; i < nb_ops; i++) {
626 if (op_type[i] & (OP_REG | OP_ST)) {
627 v += ops[i].reg;
628 break;
631 /* mov $im, %reg case */
632 if (pa->opcode == 0xb0 && s >= 1)
633 v += 7;
635 if (pa->instr_type & OPC_B)
636 v += s;
637 if (pa->instr_type & OPC_TEST)
638 v += test_bits[opcode - pa->sym];
639 if (pa->instr_type & OPC_SHORTJMP) {
640 Sym *sym;
641 int jmp_disp;
643 /* see if we can really generate the jump with a byte offset */
644 sym = ops[0].e.sym;
645 if (!sym)
646 goto no_short_jump;
647 if (sym->r != cur_text_section->sh_num)
648 goto no_short_jump;
649 jmp_disp = ops[0].e.v + (long)sym->next - ind - 2;
650 if (jmp_disp == (int8_t)jmp_disp) {
651 /* OK to generate jump */
652 is_short_jmp = 1;
653 ops[0].e.v = jmp_disp;
654 } else {
655 no_short_jump:
656 if (pa->instr_type & OPC_JMP) {
657 /* long jump will be allowed. need to modify the
658 opcode slightly */
659 if (v == 0xeb)
660 v = 0xe9;
661 else
662 v += 0x0f10;
663 } else {
664 error("invalid displacement");
668 op1 = v >> 8;
669 if (op1)
670 g(op1);
671 g(v);
673 /* search which operand will used for modrm */
674 modrm_index = 0;
675 if (pa->instr_type & OPC_SHIFT) {
676 reg = (opcode - pa->sym) >> 2;
677 if (reg == 6)
678 reg = 7;
679 } else if (pa->instr_type & OPC_ARITH) {
680 reg = (opcode - pa->sym) >> 2;
681 } else if (pa->instr_type & OPC_FARITH) {
682 reg = (opcode - pa->sym) / 6;
683 } else {
684 reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
686 if (pa->instr_type & OPC_MODRM) {
687 /* first look for an ea operand */
688 for(i = 0;i < nb_ops; i++) {
689 if (op_type[i] & OP_EA)
690 goto modrm_found;
692 /* then if not found, a register or indirection (shift instructions) */
693 for(i = 0;i < nb_ops; i++) {
694 if (op_type[i] & (OP_REG | OP_MMX | OP_SSE | OP_INDIR))
695 goto modrm_found;
697 #ifdef ASM_DEBUG
698 error("bad op table");
699 #endif
700 modrm_found:
701 modrm_index = i;
702 /* if a register is used in another operand then it is
703 used instead of group */
704 for(i = 0;i < nb_ops; i++) {
705 v = op_type[i];
706 if (i != modrm_index &&
707 (v & (OP_REG | OP_MMX | OP_SSE | OP_CR | OP_TR | OP_DB | OP_SEG))) {
708 reg = ops[i].reg;
709 break;
713 asm_modrm(reg, &ops[modrm_index]);
716 /* emit constants */
718 for(i = 0;i < nb_ops; i++) {
719 v = op_type[i];
720 if (v & (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64 | OP_IM8S | OP_ADDR)) {
721 /* if multiple sizes are given it means we must look
722 at the op size */
723 if (v == (OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64) ||
724 v == (OP_IM16 | OP_IM32 | OP_IM64)) {
725 if (ss == 0)
726 v = OP_IM8;
727 else if (ss == 1)
728 v = OP_IM16;
729 else if (ss == 2)
730 v = OP_IM32;
731 else
732 v = OP_IM64;
733 } else if (v == (OP_IM8 | OP_IM16 | OP_IM32) ||
734 v == (OP_IM16 | OP_IM32)) {
735 if (ss == 0)
736 v = OP_IM8;
737 else if (ss == 1)
738 v = OP_IM16;
739 else
740 v = OP_IM32;
742 if (v & (OP_IM8 | OP_IM8S)) {
743 if (ops[i].e.sym)
744 goto error_relocate;
745 g(ops[i].e.v);
746 } else if (v & OP_IM16) {
747 if (ops[i].e.sym) {
748 error_relocate:
749 error("cannot relocate");
751 gen_le16(ops[i].e.v);
752 } else {
753 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
754 if (is_short_jmp)
755 g(ops[i].e.v);
756 else
757 gen_disp32(&ops[i].e);
758 } else {
759 if (v & OP_IM64)
760 gen_expr64(&ops[i].e);
761 else
762 gen_expr32(&ops[i].e);
765 } else if (v & (OP_REG32 | OP_REG64)) {
766 if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {
767 /* jmp $r */
768 g(0xE0 + ops[i].reg);
775 #define NB_SAVED_REGS 3
776 #define NB_ASM_REGS 8
778 /* return the constraint priority (we allocate first the lowest
779 numbered constraints) */
780 static inline int constraint_priority(const char *str)
782 int priority, c, pr;
784 /* we take the lowest priority */
785 priority = 0;
786 for(;;) {
787 c = *str;
788 if (c == '\0')
789 break;
790 str++;
791 switch(c) {
792 case 'A':
793 pr = 0;
794 break;
795 case 'a':
796 case 'b':
797 case 'c':
798 case 'd':
799 case 'S':
800 case 'D':
801 pr = 1;
802 break;
803 case 'q':
804 pr = 2;
805 break;
806 case 'r':
807 pr = 3;
808 break;
809 case 'N':
810 case 'M':
811 case 'I':
812 case 'i':
813 case 'm':
814 case 'g':
815 pr = 4;
816 break;
817 default:
818 error("unknown constraint '%c'", c);
819 pr = 0;
821 if (pr > priority)
822 priority = pr;
824 return priority;
827 static const char *skip_constraint_modifiers(const char *p)
829 while (*p == '=' || *p == '&' || *p == '+' || *p == '%')
830 p++;
831 return p;
834 #define REG_OUT_MASK 0x01
835 #define REG_IN_MASK 0x02
837 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
839 static void asm_compute_constraints(ASMOperand *operands,
840 int nb_operands, int nb_outputs,
841 const uint8_t *clobber_regs,
842 int *pout_reg)
844 ASMOperand *op;
845 int sorted_op[MAX_ASM_OPERANDS];
846 int i, j, k, p1, p2, tmp, reg, c, reg_mask;
847 const char *str;
848 uint8_t regs_allocated[NB_ASM_REGS];
850 /* init fields */
851 for(i=0;i<nb_operands;i++) {
852 op = &operands[i];
853 op->input_index = -1;
854 op->ref_index = -1;
855 op->reg = -1;
856 op->is_memory = 0;
857 op->is_rw = 0;
859 /* compute constraint priority and evaluate references to output
860 constraints if input constraints */
861 for(i=0;i<nb_operands;i++) {
862 op = &operands[i];
863 str = op->constraint;
864 str = skip_constraint_modifiers(str);
865 if (isnum(*str) || *str == '[') {
866 /* this is a reference to another constraint */
867 k = find_constraint(operands, nb_operands, str, NULL);
868 if ((unsigned)k >= i || i < nb_outputs)
869 error("invalid reference in constraint %d ('%s')",
870 i, str);
871 op->ref_index = k;
872 if (operands[k].input_index >= 0)
873 error("cannot reference twice the same operand");
874 operands[k].input_index = i;
875 op->priority = 5;
876 } else {
877 op->priority = constraint_priority(str);
881 /* sort operands according to their priority */
882 for(i=0;i<nb_operands;i++)
883 sorted_op[i] = i;
884 for(i=0;i<nb_operands - 1;i++) {
885 for(j=i+1;j<nb_operands;j++) {
886 p1 = operands[sorted_op[i]].priority;
887 p2 = operands[sorted_op[j]].priority;
888 if (p2 < p1) {
889 tmp = sorted_op[i];
890 sorted_op[i] = sorted_op[j];
891 sorted_op[j] = tmp;
896 for(i = 0;i < NB_ASM_REGS; i++) {
897 if (clobber_regs[i])
898 regs_allocated[i] = REG_IN_MASK | REG_OUT_MASK;
899 else
900 regs_allocated[i] = 0;
902 /* esp cannot be used */
903 regs_allocated[4] = REG_IN_MASK | REG_OUT_MASK;
904 /* ebp cannot be used yet */
905 regs_allocated[5] = REG_IN_MASK | REG_OUT_MASK;
907 /* allocate registers and generate corresponding asm moves */
908 for(i=0;i<nb_operands;i++) {
909 j = sorted_op[i];
910 op = &operands[j];
911 str = op->constraint;
912 /* no need to allocate references */
913 if (op->ref_index >= 0)
914 continue;
915 /* select if register is used for output, input or both */
916 if (op->input_index >= 0) {
917 reg_mask = REG_IN_MASK | REG_OUT_MASK;
918 } else if (j < nb_outputs) {
919 reg_mask = REG_OUT_MASK;
920 } else {
921 reg_mask = REG_IN_MASK;
923 try_next:
924 c = *str++;
925 switch(c) {
926 case '=':
927 goto try_next;
928 case '+':
929 op->is_rw = 1;
930 /* FALL THRU */
931 case '&':
932 if (j >= nb_outputs)
933 error("'%c' modifier can only be applied to outputs", c);
934 reg_mask = REG_IN_MASK | REG_OUT_MASK;
935 goto try_next;
936 case 'A':
937 /* allocate both eax and edx */
938 if (is_reg_allocated(TREG_RAX) ||
939 is_reg_allocated(TREG_RDX))
940 goto try_next;
941 op->is_llong = 1;
942 op->reg = TREG_RAX;
943 regs_allocated[TREG_RAX] |= reg_mask;
944 regs_allocated[TREG_RDX] |= reg_mask;
945 break;
946 case 'a':
947 reg = TREG_RAX;
948 goto alloc_reg;
949 case 'b':
950 reg = 3;
951 goto alloc_reg;
952 case 'c':
953 reg = TREG_RCX;
954 goto alloc_reg;
955 case 'd':
956 reg = TREG_RDX;
957 goto alloc_reg;
958 case 'S':
959 reg = 6;
960 goto alloc_reg;
961 case 'D':
962 reg = 7;
963 alloc_reg:
964 if (is_reg_allocated(reg))
965 goto try_next;
966 goto reg_found;
967 case 'q':
968 /* eax, ebx, ecx or edx */
969 for(reg = 0; reg < 4; reg++) {
970 if (!is_reg_allocated(reg))
971 goto reg_found;
973 goto try_next;
974 case 'r':
975 /* any general register */
976 for(reg = 0; reg < 8; reg++) {
977 if (!is_reg_allocated(reg))
978 goto reg_found;
980 goto try_next;
981 reg_found:
982 /* now we can reload in the register */
983 op->is_llong = 0;
984 op->reg = reg;
985 regs_allocated[reg] |= reg_mask;
986 break;
987 case 'i':
988 if (!((op->vt->r & (VT_VALMASK | VT_LVAL)) == VT_CONST))
989 goto try_next;
990 break;
991 case 'I':
992 case 'N':
993 case 'M':
994 if (!((op->vt->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST))
995 goto try_next;
996 break;
997 case 'm':
998 case 'g':
999 /* nothing special to do because the operand is already in
1000 memory, except if the pointer itself is stored in a
1001 memory variable (VT_LLOCAL case) */
1002 /* XXX: fix constant case */
1003 /* if it is a reference to a memory zone, it must lie
1004 in a register, so we reserve the register in the
1005 input registers and a load will be generated
1006 later */
1007 if (j < nb_outputs || c == 'm') {
1008 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1009 /* any general register */
1010 for(reg = 0; reg < 8; reg++) {
1011 if (!(regs_allocated[reg] & REG_IN_MASK))
1012 goto reg_found1;
1014 goto try_next;
1015 reg_found1:
1016 /* now we can reload in the register */
1017 regs_allocated[reg] |= REG_IN_MASK;
1018 op->reg = reg;
1019 op->is_memory = 1;
1022 break;
1023 default:
1024 error("asm constraint %d ('%s') could not be satisfied",
1025 j, op->constraint);
1026 break;
1028 /* if a reference is present for that operand, we assign it too */
1029 if (op->input_index >= 0) {
1030 operands[op->input_index].reg = op->reg;
1031 operands[op->input_index].is_llong = op->is_llong;
1035 /* compute out_reg. It is used to store outputs registers to memory
1036 locations references by pointers (VT_LLOCAL case) */
1037 *pout_reg = -1;
1038 for(i=0;i<nb_operands;i++) {
1039 op = &operands[i];
1040 if (op->reg >= 0 &&
1041 (op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1042 !op->is_memory) {
1043 for(reg = 0; reg < 8; reg++) {
1044 if (!(regs_allocated[reg] & REG_OUT_MASK))
1045 goto reg_found2;
1047 error("could not find free output register for reloading");
1048 reg_found2:
1049 *pout_reg = reg;
1050 break;
1054 /* print sorted constraints */
1055 #ifdef ASM_DEBUG
1056 for(i=0;i<nb_operands;i++) {
1057 j = sorted_op[i];
1058 op = &operands[j];
1059 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1061 op->id ? get_tok_str(op->id, NULL) : "",
1062 op->constraint,
1063 op->vt->r,
1064 op->reg);
1066 if (*pout_reg >= 0)
1067 printf("out_reg=%d\n", *pout_reg);
1068 #endif
1071 static void subst_asm_operand(CString *add_str,
1072 SValue *sv, int modifier)
1074 int r, reg, size, val;
1075 char buf[64];
1077 r = sv->r;
1078 if ((r & VT_VALMASK) == VT_CONST) {
1079 if (!(r & VT_LVAL) && modifier != 'c' && modifier != 'n')
1080 cstr_ccat(add_str, '$');
1081 if (r & VT_SYM) {
1082 cstr_cat(add_str, get_tok_str(sv->sym->v, NULL));
1083 if (sv->c.i != 0) {
1084 cstr_ccat(add_str, '+');
1085 } else {
1086 return;
1089 val = sv->c.i;
1090 if (modifier == 'n')
1091 val = -val;
1092 snprintf(buf, sizeof(buf), "%d", sv->c.i);
1093 cstr_cat(add_str, buf);
1094 } else if ((r & VT_VALMASK) == VT_LOCAL) {
1095 snprintf(buf, sizeof(buf), "%d(%%ebp)", sv->c.i);
1096 cstr_cat(add_str, buf);
1097 } else if (r & VT_LVAL) {
1098 reg = r & VT_VALMASK;
1099 if (reg >= VT_CONST)
1100 error("internal compiler error");
1101 snprintf(buf, sizeof(buf), "(%%%s)",
1102 get_tok_str(TOK_ASM_eax + reg, NULL));
1103 cstr_cat(add_str, buf);
1104 } else {
1105 /* register case */
1106 reg = r & VT_VALMASK;
1107 if (reg >= VT_CONST)
1108 error("internal compiler error");
1110 /* choose register operand size */
1111 if ((sv->type.t & VT_BTYPE) == VT_BYTE)
1112 size = 1;
1113 else if ((sv->type.t & VT_BTYPE) == VT_SHORT)
1114 size = 2;
1115 else if ((sv->type.t & VT_BTYPE) == VT_LLONG)
1116 size = 8;
1117 else
1118 size = 4;
1119 if (size == 1 && reg >= 4)
1120 size = 4;
1122 if (modifier == 'b') {
1123 if (reg >= 4)
1124 error("cannot use byte register");
1125 size = 1;
1126 } else if (modifier == 'h') {
1127 if (reg >= 4)
1128 error("cannot use byte register");
1129 size = -1;
1130 } else if (modifier == 'w') {
1131 size = 2;
1132 } else if (modifier == 'q') {
1133 size = 8;
1136 switch(size) {
1137 case -1:
1138 reg = TOK_ASM_ah + reg;
1139 break;
1140 case 1:
1141 reg = TOK_ASM_al + reg;
1142 break;
1143 case 2:
1144 reg = TOK_ASM_ax + reg;
1145 break;
1146 case 4:
1147 reg = TOK_ASM_eax + reg;
1148 break;
1149 default:
1150 reg = TOK_ASM_rax + reg;
1151 break;
1153 snprintf(buf, sizeof(buf), "%%%s", get_tok_str(reg, NULL));
1154 cstr_cat(add_str, buf);
1158 /* generate prolog and epilog code for asm statment */
1159 static void asm_gen_code(ASMOperand *operands, int nb_operands,
1160 int nb_outputs, int is_output,
1161 uint8_t *clobber_regs,
1162 int out_reg)
1164 uint8_t regs_allocated[NB_ASM_REGS];
1165 ASMOperand *op;
1166 int i, reg;
1167 static uint8_t reg_saved[NB_SAVED_REGS] = { 3, 6, 7 };
1169 /* mark all used registers */
1170 memcpy(regs_allocated, clobber_regs, sizeof(regs_allocated));
1171 for(i = 0; i < nb_operands;i++) {
1172 op = &operands[i];
1173 if (op->reg >= 0)
1174 regs_allocated[op->reg] = 1;
1176 if (!is_output) {
1177 /* generate reg save code */
1178 for(i = 0; i < NB_SAVED_REGS; i++) {
1179 reg = reg_saved[i];
1180 if (regs_allocated[reg])
1181 g(0x50 + reg);
1184 /* generate load code */
1185 for(i = 0; i < nb_operands; i++) {
1186 op = &operands[i];
1187 if (op->reg >= 0) {
1188 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL &&
1189 op->is_memory) {
1190 /* memory reference case (for both input and
1191 output cases) */
1192 SValue sv;
1193 sv = *op->vt;
1194 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1195 load(op->reg, &sv);
1196 } else if (i >= nb_outputs || op->is_rw) {
1197 /* load value in register */
1198 load(op->reg, op->vt);
1199 if (op->is_llong) {
1200 SValue sv;
1201 sv = *op->vt;
1202 sv.c.ul += 4;
1203 load(TREG_RDX, &sv);
1208 } else {
1209 /* generate save code */
1210 for(i = 0 ; i < nb_outputs; i++) {
1211 op = &operands[i];
1212 if (op->reg >= 0) {
1213 if ((op->vt->r & VT_VALMASK) == VT_LLOCAL) {
1214 if (!op->is_memory) {
1215 SValue sv;
1216 sv = *op->vt;
1217 sv.r = (sv.r & ~VT_VALMASK) | VT_LOCAL;
1218 load(out_reg, &sv);
1220 sv.r = (sv.r & ~VT_VALMASK) | out_reg;
1221 store(op->reg, &sv);
1223 } else {
1224 store(op->reg, op->vt);
1225 if (op->is_llong) {
1226 SValue sv;
1227 sv = *op->vt;
1228 sv.c.ul += 4;
1229 store(TREG_RDX, &sv);
1234 /* generate reg restore code */
1235 for(i = NB_SAVED_REGS - 1; i >= 0; i--) {
1236 reg = reg_saved[i];
1237 if (regs_allocated[reg])
1238 g(0x58 + reg);
1243 static void asm_clobber(uint8_t *clobber_regs, const char *str)
1245 int reg;
1246 TokenSym *ts;
1248 if (!strcmp(str, "memory") ||
1249 !strcmp(str, "cc"))
1250 return;
1251 ts = tok_alloc(str, strlen(str));
1252 reg = ts->tok;
1253 if (reg >= TOK_ASM_rax && reg <= TOK_ASM_rdi) {
1254 reg -= TOK_ASM_rax;
1255 } else if (reg >= TOK_ASM_eax && reg <= TOK_ASM_edi) {
1256 reg -= TOK_ASM_eax;
1257 } else if (reg >= TOK_ASM_ax && reg <= TOK_ASM_di) {
1258 reg -= TOK_ASM_ax;
1259 } else {
1260 error("invalid clobber register '%s'", str);
1262 clobber_regs[reg] = 1;