2 * i386 specific functions for TCC assembler
4 * Copyright (c) 2001, 2002 Fabrice Bellard
5 * Copyright (c) 2009 Frédéric Feret (x86_64 support)
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #define MAX_OPERANDS 3
26 #define TOK_ASM_first TOK_ASM_clc
27 #define TOK_ASM_last TOK_ASM_emms
28 #define TOK_ASM_alllast TOK_ASM_subps
30 #define OPC_B 0x01 /* only used with OPC_WL */
31 #define OPC_WL 0x02 /* 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 0x04 /* register is added to opcode */
34 #define OPC_MODRM 0x08 /* modrm encoding */
36 #define OPCT_MASK 0x70
37 #define OPC_FWAIT 0x10 /* add fwait opcode */
38 #define OPC_SHIFT 0x20 /* shift opcodes */
39 #define OPC_ARITH 0x30 /* arithmetic opcodes */
40 #define OPC_FARITH 0x40 /* FPU arithmetic opcodes */
41 #define OPC_TEST 0x50 /* test opcodes */
42 #define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
44 #define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */
45 #ifdef TCC_TARGET_X86_64
46 # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
47 # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
48 # define OPC_WLX OPC_WLQ
49 # define OPC_BWLX OPC_BWLQ
51 # define OPC_WLX OPC_WL
52 # define OPC_BWLX OPC_BWL
55 #define OPC_GROUP_SHIFT 13
57 /* in order to compress the operand type, we use specific operands and
60 OPT_REG8
=0, /* warning: value is hardcoded from TOK_ASM_xxx */
61 OPT_REG16
, /* warning: value is hardcoded from TOK_ASM_xxx */
62 OPT_REG32
, /* warning: value is hardcoded from TOK_ASM_xxx */
63 #ifdef TCC_TARGET_X86_64
64 OPT_REG64
, /* warning: value is hardcoded from TOK_ASM_xxx */
66 OPT_MMX
, /* warning: value is hardcoded from TOK_ASM_xxx */
67 OPT_SSE
, /* warning: value is hardcoded from TOK_ASM_xxx */
68 OPT_CR
, /* warning: value is hardcoded from TOK_ASM_xxx */
69 OPT_TR
, /* warning: value is hardcoded from TOK_ASM_xxx */
70 OPT_DB
, /* warning: value is hardcoded from TOK_ASM_xxx */
73 #ifdef TCC_TARGET_X86_64
74 OPT_REG8_LOW
, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but
75 with REX prefix, not used in insn templates */
81 #ifdef TCC_TARGET_X86_64
84 OPT_EAX
, /* %al, %ax, %eax or %rax register */
85 OPT_ST0
, /* %st(0) register */
86 OPT_CL
, /* %cl register */
87 OPT_DX
, /* %dx register */
88 OPT_ADDR
, /* OP_EA with only offset */
89 OPT_INDIR
, /* *(expr) */
92 OPT_IM
, /* IM8 | IM16 | IM32 */
93 OPT_REG
, /* REG8 | REG16 | REG32 | REG64 */
94 OPT_REGW
, /* REG16 | REG32 | REG64 */
95 OPT_IMW
, /* IM16 | IM32 */
96 OPT_MMXSSE
, /* MMX | SSE */
97 OPT_DISP
, /* Like OPT_ADDR, but emitted as displacement (for jumps) */
98 OPT_DISP8
, /* Like OPT_ADDR, but only 8bit (short jumps) */
99 /* can be ored with any OPT_xxx */
103 #define OP_REG8 (1 << OPT_REG8)
104 #define OP_REG16 (1 << OPT_REG16)
105 #define OP_REG32 (1 << OPT_REG32)
106 #define OP_MMX (1 << OPT_MMX)
107 #define OP_SSE (1 << OPT_SSE)
108 #define OP_CR (1 << OPT_CR)
109 #define OP_TR (1 << OPT_TR)
110 #define OP_DB (1 << OPT_DB)
111 #define OP_SEG (1 << OPT_SEG)
112 #define OP_ST (1 << OPT_ST)
113 #define OP_IM8 (1 << OPT_IM8)
114 #define OP_IM8S (1 << OPT_IM8S)
115 #define OP_IM16 (1 << OPT_IM16)
116 #define OP_IM32 (1 << OPT_IM32)
117 #define OP_EAX (1 << OPT_EAX)
118 #define OP_ST0 (1 << OPT_ST0)
119 #define OP_CL (1 << OPT_CL)
120 #define OP_DX (1 << OPT_DX)
121 #define OP_ADDR (1 << OPT_ADDR)
122 #define OP_INDIR (1 << OPT_INDIR)
123 #ifdef TCC_TARGET_X86_64
124 # define OP_REG64 (1 << OPT_REG64)
125 # define OP_REG8_LOW (1 << OPT_REG8_LOW)
126 # define OP_IM64 (1 << OPT_IM64)
127 # define OP_EA32 (OP_EA << 1)
130 # define OP_REG8_LOW 0
135 #define OP_EA 0x40000000
136 #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
138 #ifdef TCC_TARGET_X86_64
139 # define TREG_XAX TREG_RAX
140 # define TREG_XCX TREG_RCX
141 # define TREG_XDX TREG_RDX
143 # define TREG_XAX TREG_EAX
144 # define TREG_XCX TREG_ECX
145 # define TREG_XDX TREG_EDX
148 typedef struct ASMInstr
{
153 uint8_t op_type
[MAX_OPERANDS
]; /* see OP_xxx */
156 typedef struct Operand
{
158 int8_t reg
; /* register, -1 if none */
159 int8_t reg2
; /* second register, -1 if none */
164 static const uint8_t reg_to_size
[9] = {
169 #ifdef TCC_TARGET_X86_64
173 0, 0, 1, 0, 2, 0, 0, 0, 3
176 #define NB_TEST_OPCODES 30
178 static const uint8_t test_bits
[NB_TEST_OPCODES
] = {
211 static const uint8_t segment_prefixes
[] = {
220 static const ASMInstr asm_instrs
[] = {
222 /* This removes a 0x0f in the second byte */
223 #define O(o) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))
224 /* This constructs instr_type from opcode, type and group. */
225 #define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
226 #define DEF_ASM_OP0(name, opcode)
227 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0 },
228 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
229 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
230 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 3, { op0, op1, op2 }},
231 #ifdef TCC_TARGET_X86_64
232 # include "x86_64-asm.h"
234 # include "i386-asm.h"
240 static const uint16_t op0_codes
[] = {
242 #define DEF_ASM_OP0(x, opcode) opcode,
243 #define DEF_ASM_OP0L(name, opcode, group, instr_type)
244 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
245 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
246 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
247 #ifdef TCC_TARGET_X86_64
248 # include "x86_64-asm.h"
250 # include "i386-asm.h"
254 static inline int get_reg_shift(TCCState
*s1
)
257 v
= asm_int_expr(s1
);
272 expect("1, 2, 4 or 8 constant");
279 #ifdef TCC_TARGET_X86_64
280 static int asm_parse_numeric_reg(int t
, int *type
)
283 if (t
>= TOK_IDENT
&& t
< tok_ident
) {
284 const char *s
= table_ident
[t
- TOK_IDENT
]->str
;
293 /* Don't allow leading '0'. */
294 if ((c
= *s
++) >= '1' && c
<= '9')
298 if ((c
= *s
) >= '0' && c
<= '5')
299 s
++, reg
= reg
* 10 + c
- '0';
304 else if (*type
!= OP_REG64
)
306 else if (c
== 'b' && !s
[1])
308 else if (c
== 'w' && !s
[1])
310 else if (c
== 'd' && !s
[1])
319 static int asm_parse_reg(int *type
)
326 if (tok
>= TOK_ASM_eax
&& tok
<= TOK_ASM_edi
) {
327 reg
= tok
- TOK_ASM_eax
;
329 #ifdef TCC_TARGET_X86_64
330 } else if (tok
>= TOK_ASM_rax
&& tok
<= TOK_ASM_rdi
) {
331 reg
= tok
- TOK_ASM_rax
;
333 } else if (tok
== TOK_ASM_rip
) {
334 reg
= -2; /* Probably should use different escape code. */
336 } else if ((reg
= asm_parse_numeric_reg(tok
, type
)) >= 0
337 && (*type
== OP_REG32
|| *type
== OP_REG64
)) {
348 static void parse_operand(TCCState
*s1
, Operand
*op
)
362 if (tok
>= TOK_ASM_al
&& tok
<= TOK_ASM_db7
) {
363 reg
= tok
- TOK_ASM_al
;
364 op
->type
= 1 << (reg
>> 3); /* WARNING: do not change constant order */
366 if ((op
->type
& OP_REG
) && op
->reg
== TREG_XAX
)
368 else if (op
->type
== OP_REG8
&& op
->reg
== TREG_XCX
)
370 else if (op
->type
== OP_REG16
&& op
->reg
== TREG_XDX
)
372 } else if (tok
>= TOK_ASM_dr0
&& tok
<= TOK_ASM_dr7
) {
374 op
->reg
= tok
- TOK_ASM_dr0
;
375 } else if (tok
>= TOK_ASM_es
&& tok
<= TOK_ASM_gs
) {
377 op
->reg
= tok
- TOK_ASM_es
;
378 } else if (tok
== TOK_ASM_st
) {
384 if (tok
!= TOK_PPNUM
)
388 if ((unsigned)reg
>= 8 || p
[1] != '\0')
397 #ifdef TCC_TARGET_X86_64
398 } else if (tok
>= TOK_ASM_spl
&& tok
<= TOK_ASM_dil
) {
399 op
->type
= OP_REG8
| OP_REG8_LOW
;
400 op
->reg
= 4 + tok
- TOK_ASM_spl
;
401 } else if ((op
->reg
= asm_parse_numeric_reg(tok
, &op
->type
)) >= 0) {
406 tcc_error("unknown register %%%s", get_tok_str(tok
, &tokc
));
410 } else if (tok
== '$') {
417 if (op
->e
.v
== (uint8_t)op
->e
.v
)
419 if (op
->e
.v
== (int8_t)op
->e
.v
)
421 if (op
->e
.v
== (uint16_t)op
->e
.v
)
423 #ifdef TCC_TARGET_X86_64
424 if (op
->e
.v
!= (int32_t)op
->e
.v
&& op
->e
.v
!= (uint32_t)op
->e
.v
)
429 /* address(reg,reg2,shift) with all variants */
444 /* bracketed offset expression */
458 op
->reg
= asm_parse_reg(&type
);
463 op
->reg2
= asm_parse_reg(&type
);
467 op
->shift
= get_reg_shift(s1
);
474 if (op
->reg
== -1 && op
->reg2
== -1)
480 /* XXX: unify with C code output ? */
481 ST_FUNC
void gen_expr32(ExprValue
*pe
)
484 /* If PC-relative, always set VT_SYM, even without symbol,
485 so as to force a relocation to be emitted. */
486 gen_addrpc32(VT_SYM
, pe
->sym
, pe
->v
);
488 gen_addr32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
491 #ifdef TCC_TARGET_X86_64
492 ST_FUNC
void gen_expr64(ExprValue
*pe
)
494 gen_addr64(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
498 /* XXX: unify with C code output ? */
499 static void gen_disp32(ExprValue
*pe
)
502 if (sym
&& sym
->r
== cur_text_section
->sh_num
) {
503 /* same section: we can output an absolute value. Note
504 that the TCC compiler behaves differently here because
505 it always outputs a relocation to ease (future) code
506 elimination in the linker */
507 gen_le32(pe
->v
+ sym
->jnext
- ind
- 4);
509 if (sym
&& sym
->type
.t
== VT_VOID
) {
510 sym
->type
.t
= VT_FUNC
;
511 sym
->type
.ref
= NULL
;
513 gen_addrpc32(VT_SYM
, sym
, pe
->v
);
517 /* generate the modrm operand */
518 static inline int asm_modrm(int reg
, Operand
*op
)
520 int mod
, reg1
, reg2
, sib_reg1
;
522 if (op
->type
& (OP_REG
| OP_MMX
| OP_SSE
)) {
523 g(0xc0 + (reg
<< 3) + op
->reg
);
524 } else if (op
->reg
== -1 && op
->reg2
== -1) {
525 /* displacement only */
526 #ifdef TCC_TARGET_X86_64
527 g(0x04 + (reg
<< 3));
530 g(0x05 + (reg
<< 3));
533 #ifdef TCC_TARGET_X86_64
534 } else if (op
->reg
== -2) {
535 ExprValue
*pe
= &op
->e
;
536 g(0x05 + (reg
<< 3));
537 gen_addrpc32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
542 /* fist compute displacement encoding */
543 if (sib_reg1
== -1) {
546 } else if (op
->e
.v
== 0 && !op
->e
.sym
&& op
->reg
!= 5) {
548 } else if (op
->e
.v
== (int8_t)op
->e
.v
&& !op
->e
.sym
) {
553 /* compute if sib byte needed */
557 g(mod
+ (reg
<< 3) + reg1
);
562 reg2
= 4; /* indicate no index */
563 g((op
->shift
<< 6) + (reg2
<< 3) + sib_reg1
);
568 } else if (mod
== 0x80 || op
->reg
== -1) {
575 #ifdef TCC_TARGET_X86_64
581 static void asm_rex(int width64
, Operand
*ops
, int nb_ops
, int *op_type
,
584 unsigned char rex
= width64
? 0x48 : 0;
585 int saw_high_8bit
= 0;
588 /* No mod/rm byte, but we might have a register op nevertheless
589 (we will add it to the opcode later). */
590 for(i
= 0; i
< nb_ops
; i
++) {
591 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
592 if (ops
[i
].reg
>= 8) {
595 } else if (ops
[i
].type
& OP_REG8_LOW
)
597 else if (ops
[i
].type
& OP_REG8
&& ops
[i
].reg
>= 4)
598 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
599 saw_high_8bit
= ops
[i
].reg
;
605 if (ops
[regi
].reg
>= 8) {
608 } else if (ops
[regi
].type
& OP_REG8_LOW
)
610 else if (ops
[regi
].type
& OP_REG8
&& ops
[regi
].reg
>= 4)
611 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
612 saw_high_8bit
= ops
[regi
].reg
;
614 if (ops
[rmi
].type
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_EA
)) {
615 if (ops
[rmi
].reg
>= 8) {
618 } else if (ops
[rmi
].type
& OP_REG8_LOW
)
620 else if (ops
[rmi
].type
& OP_REG8
&& ops
[rmi
].reg
>= 4)
621 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
622 saw_high_8bit
= ops
[rmi
].reg
;
624 if (ops
[rmi
].type
& OP_EA
&& ops
[rmi
].reg2
>= 8) {
631 tcc_error("can't encode register %%%ch when REX prefix is required",
632 "acdb"[saw_high_8bit
-4]);
638 static void maybe_print_stats (void)
640 static int already
= 1;
642 /* print stats about opcodes */
644 const struct ASMInstr
*pa
;
647 int nb_op_vals
, i
, j
;
651 memset(freq
, 0, sizeof(freq
));
652 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
654 //for(i=0;i<pa->nb_ops;i++) {
655 for(j
=0;j
<nb_op_vals
;j
++) {
656 //if (pa->op_type[i] == op_vals[j])
657 if (pa
->instr_type
== op_vals
[j
])
660 //op_vals[nb_op_vals++] = pa->op_type[i];
661 op_vals
[nb_op_vals
++] = pa
->instr_type
;
665 for(i
=0;i
<nb_op_vals
;i
++) {
667 //if ((v & (v - 1)) != 0)
668 printf("%3d: %08x\n", i
, v
);
670 printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
671 (int)sizeof(asm_instrs
),
672 (int)sizeof(asm_instrs
) / (int)sizeof(ASMInstr
),
673 freq
[0], freq
[1], freq
[2], freq
[3]);
677 ST_FUNC
void asm_opcode(TCCState
*s1
, int opcode
)
680 int i
, modrm_index
, modreg_index
, reg
, v
, op1
, seg_prefix
, pc
;
682 Operand ops
[MAX_OPERANDS
], *pop
;
683 int op_type
[3]; /* decoded op type */
684 int alltypes
; /* OR of all operand types */
687 #ifdef TCC_TARGET_X86_64
692 /* force synthetic ';' after prefix instruction, so we can handle */
693 /* one-line things like "rep stosb" instead of only "rep\nstosb" */
694 if (opcode
>= TOK_ASM_wait
&& opcode
<= TOK_ASM_repnz
)
703 if (tok
== ';' || tok
== TOK_LINEFEED
)
705 if (nb_ops
>= MAX_OPERANDS
) {
706 tcc_error("incorrect number of operands");
708 parse_operand(s1
, pop
);
710 if (pop
->type
!= OP_SEG
|| seg_prefix
)
711 tcc_error("incorrect prefix");
712 seg_prefix
= segment_prefixes
[pop
->reg
];
714 parse_operand(s1
, pop
);
715 if (!(pop
->type
& OP_EA
)) {
716 tcc_error("segment prefix must be followed by memory reference");
726 s
= 0; /* avoid warning */
728 /* optimize matching by using a lookup table (no hashing is needed
730 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
731 int it
= pa
->instr_type
& OPCT_MASK
;
733 if (it
== OPC_FARITH
) {
734 v
= opcode
- pa
->sym
;
735 if (!((unsigned)v
< 8 * 6 && (v
% 6) == 0))
737 } else if (it
== OPC_ARITH
) {
738 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 8*NBWLX
))
740 s
= (opcode
- pa
->sym
) % NBWLX
;
741 if ((pa
->instr_type
& OPC_BWLX
) == OPC_WLX
)
743 /* We need to reject the xxxb opcodes that we accepted above.
744 Note that pa->sym for WLX opcodes is the 'w' token,
745 to get the 'b' token subtract one. */
746 if (((opcode
- pa
->sym
+ 1) % NBWLX
) == 0)
750 } else if (it
== OPC_SHIFT
) {
751 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 7*NBWLX
))
753 s
= (opcode
- pa
->sym
) % NBWLX
;
754 } else if (it
== OPC_TEST
) {
755 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NB_TEST_OPCODES
))
757 /* cmovxx is a test opcode but accepts multiple sizes.
758 TCC doesn't accept the suffixed mnemonic, instead we
759 simply force size autodetection always. */
760 if (pa
->instr_type
& OPC_WLX
)
762 } else if (pa
->instr_type
& OPC_B
) {
763 #ifdef TCC_TARGET_X86_64
764 /* Some instructions don't have the full size but only
765 bwl form. insb e.g. */
766 if ((pa
->instr_type
& OPC_WLQ
) != OPC_WLQ
767 && !(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
770 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
))
772 s
= opcode
- pa
->sym
;
773 } else if (pa
->instr_type
& OPC_WLX
) {
774 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
776 s
= opcode
- pa
->sym
+ 1;
778 if (pa
->sym
!= opcode
)
781 if (pa
->nb_ops
!= nb_ops
)
783 #ifdef TCC_TARGET_X86_64
784 /* Special case for moves. Selecting the IM64->REG64 form
785 should only be done if we really have an >32bit imm64, and that
786 is hardcoded. Ignore it here. */
787 if (pa
->opcode
== 0xb0 && ops
[0].type
!= OP_IM64
788 && ops
[1].type
== OP_REG64
789 && !(pa
->instr_type
& OPC_0F
))
792 /* now decode and check each operand */
794 for(i
= 0; i
< nb_ops
; i
++) {
796 op1
= pa
->op_type
[i
];
800 v
= OP_IM8
| OP_IM16
| OP_IM32
;
803 v
= OP_REG8
| OP_REG16
| OP_REG32
| OP_REG64
;
806 v
= OP_REG16
| OP_REG32
| OP_REG64
;
809 v
= OP_IM16
| OP_IM32
;
825 if ((ops
[i
].type
& v
) == 0)
827 alltypes
|= ops
[i
].type
;
829 /* all is matching ! */
834 if (opcode
>= TOK_ASM_first
&& opcode
<= TOK_ASM_last
) {
836 b
= op0_codes
[opcode
- TOK_ASM_first
];
841 } else if (opcode
<= TOK_ASM_alllast
) {
842 tcc_error("bad operand with opcode '%s'",
843 get_tok_str(opcode
, NULL
));
845 tcc_error("unknown opcode '%s'",
846 get_tok_str(opcode
, NULL
));
849 /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
851 #ifdef TCC_TARGET_X86_64
852 /* XXX the autosize should rather be zero, to not have to adjust this
854 if ((pa
->instr_type
& OPC_BWLQ
) == OPC_B
)
858 /* Check for register operands providing hints about the size.
859 Start from the end, i.e. destination operands. This matters
860 only for opcodes accepting different sized registers, lar and lsl
862 for(i
= nb_ops
- 1; s
== autosize
&& i
>= 0; i
--) {
863 if ((ops
[i
].type
& OP_REG
) && !(op_type
[i
] & (OP_CL
| OP_DX
)))
864 s
= reg_to_size
[ops
[i
].type
& OP_REG
];
867 if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
868 (ops
[0].type
& (OP_SEG
| OP_IM8S
| OP_IM32
)))
870 else if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
871 (ops
[0].type
& OP_EA
))
874 tcc_error("cannot infer opcode suffix");
878 #ifdef TCC_TARGET_X86_64
879 /* Generate addr32 prefix if needed */
880 for(i
= 0; i
< nb_ops
; i
++) {
881 if (ops
[i
].type
& OP_EA32
) {
887 /* generate data16 prefix if needed */
892 /* accepting mmx+sse in all operands --> needs 0x66 to
893 switch to sse mode. Accepting only sse in an operand --> is
894 already SSE insn and needs 0x66/f2/f3 handling. */
895 for (i
= 0; i
< nb_ops
; i
++)
896 if ((op_type
[i
] & (OP_MMX
| OP_SSE
)) == (OP_MMX
| OP_SSE
)
897 && ops
[i
].type
& OP_SSE
)
902 #ifdef TCC_TARGET_X86_64
904 if (s
== 3 || (alltypes
& OP_REG64
)) {
905 /* generate REX prefix */
907 for(i
= 0; i
< nb_ops
; i
++) {
908 if (op_type
[i
] == OP_REG64
) {
909 /* If only 64bit regs are accepted in one operand
910 this is a default64 instruction without need for
916 /* XXX find better encoding for the default64 instructions. */
917 if (((opcode
!= TOK_ASM_push
&& opcode
!= TOK_ASM_pop
918 && opcode
!= TOK_ASM_pushw
&& opcode
!= TOK_ASM_pushl
919 && opcode
!= TOK_ASM_pushq
&& opcode
!= TOK_ASM_popw
920 && opcode
!= TOK_ASM_popl
&& opcode
!= TOK_ASM_popq
921 && opcode
!= TOK_ASM_call
&& opcode
!= TOK_ASM_jmp
))
927 /* now generates the operation */
928 if (OPCT_IS(pa
->instr_type
, OPC_FWAIT
))
934 if (pa
->instr_type
& OPC_0F
)
935 v
= ((v
& ~0xff) << 8) | 0x0f00 | (v
& 0xff);
936 if ((v
== 0x69 || v
== 0x6b) && nb_ops
== 2) {
937 /* kludge for imul $im, %reg */
940 op_type
[2] = op_type
[1];
941 } else if (v
== 0xcd && ops
[0].e
.v
== 3 && !ops
[0].e
.sym
) {
942 v
--; /* int $3 case */
944 } else if ((v
== 0x06 || v
== 0x07)) {
945 if (ops
[0].reg
>= 4) {
946 /* push/pop %fs or %gs */
947 v
= 0x0fa0 + (v
- 0x06) + ((ops
[0].reg
- 4) << 3);
949 v
+= ops
[0].reg
<< 3;
952 } else if (v
<= 0x05) {
954 v
+= ((opcode
- TOK_ASM_addb
) / NBWLX
) << 3;
955 } else if ((pa
->instr_type
& (OPCT_MASK
| OPC_MODRM
)) == OPC_FARITH
) {
957 v
+= ((opcode
- pa
->sym
) / 6) << 3;
960 /* search which operand will be used for modrm */
963 if (pa
->instr_type
& OPC_MODRM
) {
965 /* A modrm opcode without operands is a special case (e.g. mfence).
966 It has a group and acts as if there's an register operand 0
969 ops
[i
].type
= OP_REG
;
973 /* first look for an ea operand */
974 for(i
= 0;i
< nb_ops
; i
++) {
975 if (op_type
[i
] & OP_EA
)
978 /* then if not found, a register or indirection (shift instructions) */
979 for(i
= 0;i
< nb_ops
; i
++) {
980 if (op_type
[i
] & (OP_REG
| OP_MMX
| OP_SSE
| OP_INDIR
))
984 tcc_error("bad op table");
988 /* if a register is used in another operand then it is
989 used instead of group */
990 for(i
= 0;i
< nb_ops
; i
++) {
992 if (i
!= modrm_index
&&
993 (t
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_TR
| OP_DB
| OP_SEG
))) {
999 #ifdef TCC_TARGET_X86_64
1000 asm_rex (rex64
, ops
, nb_ops
, op_type
, modreg_index
, modrm_index
);
1003 if (pa
->instr_type
& OPC_REG
) {
1004 /* mov $im, %reg case */
1005 if (v
== 0xb0 && s
>= 1)
1007 for(i
= 0; i
< nb_ops
; i
++) {
1008 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
1014 if (pa
->instr_type
& OPC_B
)
1016 if (nb_ops
== 1 && pa
->op_type
[0] == OPT_DISP8
) {
1020 /* see if we can really generate the jump with a byte offset */
1024 if (sym
->r
!= cur_text_section
->sh_num
)
1026 jmp_disp
= ops
[0].e
.v
+ sym
->jnext
- ind
- 2 - (v
>= 0xff);
1027 if (jmp_disp
== (int8_t)jmp_disp
) {
1028 /* OK to generate jump */
1030 ops
[0].e
.v
= jmp_disp
;
1031 op_type
[0] = OP_IM8S
;
1034 /* long jump will be allowed. need to modify the
1036 if (v
== 0xeb) /* jmp */
1038 else if (v
== 0x70) /* jcc */
1041 tcc_error("invalid displacement");
1044 if (OPCT_IS(pa
->instr_type
, OPC_TEST
))
1045 v
+= test_bits
[opcode
- pa
->sym
];
1049 op1
= (v
>> 8) & 0xff;
1054 if (OPCT_IS(pa
->instr_type
, OPC_SHIFT
)) {
1055 reg
= (opcode
- pa
->sym
) / NBWLX
;
1058 } else if (OPCT_IS(pa
->instr_type
, OPC_ARITH
)) {
1059 reg
= (opcode
- pa
->sym
) / NBWLX
;
1060 } else if (OPCT_IS(pa
->instr_type
, OPC_FARITH
)) {
1061 reg
= (opcode
- pa
->sym
) / 6;
1063 reg
= (pa
->instr_type
>> OPC_GROUP_SHIFT
) & 7;
1067 if (pa
->instr_type
& OPC_MODRM
) {
1068 /* if a register is used in another operand then it is
1069 used instead of group */
1070 if (modreg_index
>= 0)
1071 reg
= ops
[modreg_index
].reg
;
1072 pc
= asm_modrm(reg
, &ops
[modrm_index
]);
1075 /* emit constants */
1076 #ifndef TCC_TARGET_X86_64
1077 if (!(pa
->instr_type
& OPC_0F
)
1078 && (pa
->opcode
== 0x9a || pa
->opcode
== 0xea)) {
1079 /* ljmp or lcall kludge */
1080 gen_expr32(&ops
[1].e
);
1082 tcc_error("cannot relocate");
1083 gen_le16(ops
[0].e
.v
);
1087 for(i
= 0;i
< nb_ops
; i
++) {
1089 if (v
& (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
| OP_IM8S
| OP_ADDR
)) {
1090 /* if multiple sizes are given it means we must look
1092 if ((v
| OP_IM8
| OP_IM64
) == (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
)) {
1097 else if (s
== 2 || (v
& OP_IM64
) == 0)
1103 if ((v
& (OP_IM8
| OP_IM8S
| OP_IM16
)) && ops
[i
].e
.sym
)
1104 tcc_error("cannot relocate");
1106 if (v
& (OP_IM8
| OP_IM8S
)) {
1108 } else if (v
& OP_IM16
) {
1109 gen_le16(ops
[i
].e
.v
);
1110 #ifdef TCC_TARGET_X86_64
1111 } else if (v
& OP_IM64
) {
1112 gen_expr64(&ops
[i
].e
);
1114 } else if (pa
->op_type
[i
] == OPT_DISP
|| pa
->op_type
[i
] == OPT_DISP8
) {
1115 gen_disp32(&ops
[i
].e
);
1117 gen_expr32(&ops
[i
].e
);
1122 /* after immediate operands, adjust pc-relative address */
1124 add32le(cur_text_section
->data
+ pc
- 4, pc
- ind
);
1127 /* return the constraint priority (we allocate first the lowest
1128 numbered constraints) */
1129 static inline int constraint_priority(const char *str
)
1131 int priority
, c
, pr
;
1133 /* we take the lowest priority */
1170 tcc_error("unknown constraint '%c'", c
);
1179 static const char *skip_constraint_modifiers(const char *p
)
1181 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1186 /* If T (a token) is of the form "%reg" returns the register
1187 number and type, otherwise return -1. */
1188 ST_FUNC
int asm_parse_regvar (int t
)
1194 s
= table_ident
[t
- TOK_IDENT
]->str
;
1197 t
= tok_alloc(s
+1, strlen(s
)-1)->tok
;
1200 parse_operand(tcc_state
, &op
);
1201 /* Accept only integer regs for now. */
1202 if (op
.type
& OP_REG
)
1208 #define REG_OUT_MASK 0x01
1209 #define REG_IN_MASK 0x02
1211 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1213 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1214 int nb_operands
, int nb_outputs
,
1215 const uint8_t *clobber_regs
,
1219 int sorted_op
[MAX_ASM_OPERANDS
];
1220 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1222 uint8_t regs_allocated
[NB_ASM_REGS
];
1225 for(i
=0;i
<nb_operands
;i
++) {
1227 op
->input_index
= -1;
1233 /* compute constraint priority and evaluate references to output
1234 constraints if input constraints */
1235 for(i
=0;i
<nb_operands
;i
++) {
1237 str
= op
->constraint
;
1238 str
= skip_constraint_modifiers(str
);
1239 if (isnum(*str
) || *str
== '[') {
1240 /* this is a reference to another constraint */
1241 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1242 if ((unsigned)k
>= i
|| i
< nb_outputs
)
1243 tcc_error("invalid reference in constraint %d ('%s')",
1246 if (operands
[k
].input_index
>= 0)
1247 tcc_error("cannot reference twice the same operand");
1248 operands
[k
].input_index
= i
;
1250 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1252 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1256 op
->priority
= constraint_priority(str
);
1260 /* sort operands according to their priority */
1261 for(i
=0;i
<nb_operands
;i
++)
1263 for(i
=0;i
<nb_operands
- 1;i
++) {
1264 for(j
=i
+1;j
<nb_operands
;j
++) {
1265 p1
= operands
[sorted_op
[i
]].priority
;
1266 p2
= operands
[sorted_op
[j
]].priority
;
1269 sorted_op
[i
] = sorted_op
[j
];
1275 for(i
= 0;i
< NB_ASM_REGS
; i
++) {
1276 if (clobber_regs
[i
])
1277 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1279 regs_allocated
[i
] = 0;
1281 /* esp cannot be used */
1282 regs_allocated
[4] = REG_IN_MASK
| REG_OUT_MASK
;
1283 /* ebp cannot be used yet */
1284 regs_allocated
[5] = REG_IN_MASK
| REG_OUT_MASK
;
1286 /* allocate registers and generate corresponding asm moves */
1287 for(i
=0;i
<nb_operands
;i
++) {
1290 str
= op
->constraint
;
1291 /* no need to allocate references */
1292 if (op
->ref_index
>= 0)
1294 /* select if register is used for output, input or both */
1295 if (op
->input_index
>= 0) {
1296 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1297 } else if (j
< nb_outputs
) {
1298 reg_mask
= REG_OUT_MASK
;
1300 reg_mask
= REG_IN_MASK
;
1303 if (is_reg_allocated(op
->reg
))
1304 tcc_error("asm regvar requests register that's taken already");
1317 if (j
>= nb_outputs
)
1318 tcc_error("'%c' modifier can only be applied to outputs", c
);
1319 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1322 /* allocate both eax and edx */
1323 if (is_reg_allocated(TREG_XAX
) ||
1324 is_reg_allocated(TREG_XDX
))
1328 regs_allocated
[TREG_XAX
] |= reg_mask
;
1329 regs_allocated
[TREG_XDX
] |= reg_mask
;
1349 if (is_reg_allocated(reg
))
1353 /* eax, ebx, ecx or edx */
1354 for(reg
= 0; reg
< 4; reg
++) {
1355 if (!is_reg_allocated(reg
))
1361 case 'p': /* A general address, for x86(64) any register is acceptable*/
1362 /* any general register */
1363 for(reg
= 0; reg
< 8; reg
++) {
1364 if (!is_reg_allocated(reg
))
1369 /* now we can reload in the register */
1372 regs_allocated
[reg
] |= reg_mask
;
1376 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1382 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
))
1387 /* nothing special to do because the operand is already in
1388 memory, except if the pointer itself is stored in a
1389 memory variable (VT_LLOCAL case) */
1390 /* XXX: fix constant case */
1391 /* if it is a reference to a memory zone, it must lie
1392 in a register, so we reserve the register in the
1393 input registers and a load will be generated
1395 if (j
< nb_outputs
|| c
== 'm') {
1396 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1397 /* any general register */
1398 for(reg
= 0; reg
< 8; reg
++) {
1399 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1404 /* now we can reload in the register */
1405 regs_allocated
[reg
] |= REG_IN_MASK
;
1412 tcc_error("asm constraint %d ('%s') could not be satisfied",
1416 /* if a reference is present for that operand, we assign it too */
1417 if (op
->input_index
>= 0) {
1418 operands
[op
->input_index
].reg
= op
->reg
;
1419 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1423 /* compute out_reg. It is used to store outputs registers to memory
1424 locations references by pointers (VT_LLOCAL case) */
1426 for(i
=0;i
<nb_operands
;i
++) {
1429 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1431 for(reg
= 0; reg
< 8; reg
++) {
1432 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1435 tcc_error("could not find free output register for reloading");
1442 /* print sorted constraints */
1444 for(i
=0;i
<nb_operands
;i
++) {
1447 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1449 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1455 printf("out_reg=%d\n", *pout_reg
);
1459 ST_FUNC
void subst_asm_operand(CString
*add_str
,
1460 SValue
*sv
, int modifier
)
1462 int r
, reg
, size
, val
;
1466 if ((r
& VT_VALMASK
) == VT_CONST
) {
1467 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1469 cstr_ccat(add_str
, '$');
1471 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1472 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1473 /* In case of anonymuous symbols ("L.42", used
1474 for static data labels) we can't find them
1475 in the C symbol table when later looking up
1476 this name. So enter them now into the asm label
1477 list when we still know the symbol. */
1478 get_asm_sym(tok_alloc(name
, strlen(name
))->tok
, sv
->sym
);
1480 cstr_cat(add_str
, name
, -1);
1481 if ((uint32_t)sv
->c
.i
== 0)
1483 cstr_ccat(add_str
, '+');
1486 if (modifier
== 'n')
1488 snprintf(buf
, sizeof(buf
), "%d", (int)sv
->c
.i
);
1489 cstr_cat(add_str
, buf
, -1);
1491 #ifdef TCC_TARGET_X86_64
1493 cstr_cat(add_str
, "(%rip)", -1);
1495 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1496 #ifdef TCC_TARGET_X86_64
1497 snprintf(buf
, sizeof(buf
), "%d(%%rbp)", (int)sv
->c
.i
);
1499 snprintf(buf
, sizeof(buf
), "%d(%%ebp)", (int)sv
->c
.i
);
1501 cstr_cat(add_str
, buf
, -1);
1502 } else if (r
& VT_LVAL
) {
1503 reg
= r
& VT_VALMASK
;
1504 if (reg
>= VT_CONST
)
1505 tcc_error("internal compiler error");
1506 snprintf(buf
, sizeof(buf
), "(%%%s)",
1507 #ifdef TCC_TARGET_X86_64
1508 get_tok_str(TOK_ASM_rax
+ reg
, NULL
)
1510 get_tok_str(TOK_ASM_eax
+ reg
, NULL
)
1513 cstr_cat(add_str
, buf
, -1);
1516 reg
= r
& VT_VALMASK
;
1517 if (reg
>= VT_CONST
)
1518 tcc_error("internal compiler error");
1520 /* choose register operand size */
1521 if ((sv
->type
.t
& VT_BTYPE
) == VT_BYTE
||
1522 (sv
->type
.t
& VT_BTYPE
) == VT_BOOL
)
1524 else if ((sv
->type
.t
& VT_BTYPE
) == VT_SHORT
)
1526 #ifdef TCC_TARGET_X86_64
1527 else if ((sv
->type
.t
& VT_BTYPE
) == VT_LLONG
||
1528 (sv
->type
.t
& VT_BTYPE
) == VT_PTR
)
1533 if (size
== 1 && reg
>= 4)
1536 if (modifier
== 'b') {
1538 tcc_error("cannot use byte register");
1540 } else if (modifier
== 'h') {
1542 tcc_error("cannot use byte register");
1544 } else if (modifier
== 'w') {
1546 } else if (modifier
== 'k') {
1548 #ifdef TCC_TARGET_X86_64
1549 } else if (modifier
== 'q') {
1556 reg
= TOK_ASM_ah
+ reg
;
1559 reg
= TOK_ASM_al
+ reg
;
1562 reg
= TOK_ASM_ax
+ reg
;
1565 reg
= TOK_ASM_eax
+ reg
;
1567 #ifdef TCC_TARGET_X86_64
1569 reg
= TOK_ASM_rax
+ reg
;
1573 snprintf(buf
, sizeof(buf
), "%%%s", get_tok_str(reg
, NULL
));
1574 cstr_cat(add_str
, buf
, -1);
1578 /* generate prolog and epilog code for asm statement */
1579 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1580 int nb_outputs
, int is_output
,
1581 uint8_t *clobber_regs
,
1584 uint8_t regs_allocated
[NB_ASM_REGS
];
1588 /* Strictly speaking %Xbp and %Xsp should be included in the
1589 call-preserved registers, but currently it doesn't matter. */
1590 #ifdef TCC_TARGET_X86_64
1591 #ifdef TCC_TARGET_PE
1592 static uint8_t reg_saved
[] = { 3, 6, 7, 12, 13, 14, 15 };
1594 static uint8_t reg_saved
[] = { 3, 12, 13, 14, 15 };
1597 static uint8_t reg_saved
[] = { 3, 6, 7 };
1600 /* mark all used registers */
1601 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1602 for(i
= 0; i
< nb_operands
;i
++) {
1605 regs_allocated
[op
->reg
] = 1;
1608 /* generate reg save code */
1609 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1611 if (regs_allocated
[reg
]) {
1618 /* generate load code */
1619 for(i
= 0; i
< nb_operands
; i
++) {
1622 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1624 /* memory reference case (for both input and
1628 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1631 } else if (i
>= nb_outputs
|| op
->is_rw
) {
1632 /* load value in register */
1633 load(op
->reg
, op
->vt
);
1638 load(TREG_XDX
, &sv
);
1644 /* generate save code */
1645 for(i
= 0 ; i
< nb_outputs
; i
++) {
1648 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1649 if (!op
->is_memory
) {
1652 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1657 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1658 store(op
->reg
, &sv
);
1661 store(op
->reg
, op
->vt
);
1666 store(TREG_XDX
, &sv
);
1671 /* generate reg restore code */
1672 for(i
= sizeof(reg_saved
)/sizeof(reg_saved
[0]) - 1; i
>= 0; i
--) {
1674 if (regs_allocated
[reg
]) {
1683 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1687 #ifdef TCC_TARGET_X86_64
1691 if (!strcmp(str
, "memory") ||
1692 !strcmp(str
, "cc") ||
1693 !strcmp(str
, "flags"))
1695 ts
= tok_alloc(str
, strlen(str
));
1697 if (reg
>= TOK_ASM_eax
&& reg
<= TOK_ASM_edi
) {
1699 } else if (reg
>= TOK_ASM_ax
&& reg
<= TOK_ASM_di
) {
1701 #ifdef TCC_TARGET_X86_64
1702 } else if (reg
>= TOK_ASM_rax
&& reg
<= TOK_ASM_rdi
) {
1704 } else if ((reg
= asm_parse_numeric_reg(reg
, &type
)) >= 0) {
1708 tcc_error("invalid clobber register '%s'", str
);
1710 clobber_regs
[reg
] = 1;