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
25 #define MAX_OPERANDS 3
27 #define TOK_ASM_first TOK_ASM_clc
28 #define TOK_ASM_last TOK_ASM_emms
29 #define TOK_ASM_alllast TOK_ASM_subps
31 #define OPC_B 0x01 /* only used with OPC_WL */
32 #define OPC_WL 0x02 /* accepts w, l or no suffix */
33 #define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
34 #define OPC_REG 0x04 /* register is added to opcode */
35 #define OPC_MODRM 0x08 /* modrm encoding */
37 #define OPCT_MASK 0x70
38 #define OPC_FWAIT 0x10 /* add fwait opcode */
39 #define OPC_SHIFT 0x20 /* shift opcodes */
40 #define OPC_ARITH 0x30 /* arithmetic opcodes */
41 #define OPC_FARITH 0x40 /* FPU arithmetic opcodes */
42 #define OPC_TEST 0x50 /* test opcodes */
43 #define OPC_0F01 0x60 /* 0x0f01XX (group 7, XX is 2nd opcode,
44 no operands and unstructured mod/rm) */
45 #define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
47 #define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */
48 #define OPC_48 0x200 /* Always has REX prefix */
49 #ifdef TCC_TARGET_X86_64
50 # define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */
51 # define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
52 # define OPC_WLX OPC_WLQ
53 # define OPC_BWLX OPC_BWLQ
55 # define OPC_WLX OPC_WL
56 # define OPC_BWLX OPC_BWL
59 #define OPC_GROUP_SHIFT 13
61 /* in order to compress the operand type, we use specific operands and
64 OPT_REG8
=0, /* warning: value is hardcoded from TOK_ASM_xxx */
65 OPT_REG16
, /* warning: value is hardcoded from TOK_ASM_xxx */
66 OPT_REG32
, /* warning: value is hardcoded from TOK_ASM_xxx */
67 #ifdef TCC_TARGET_X86_64
68 OPT_REG64
, /* warning: value is hardcoded from TOK_ASM_xxx */
70 OPT_MMX
, /* warning: value is hardcoded from TOK_ASM_xxx */
71 OPT_SSE
, /* warning: value is hardcoded from TOK_ASM_xxx */
72 OPT_CR
, /* warning: value is hardcoded from TOK_ASM_xxx */
73 OPT_TR
, /* warning: value is hardcoded from TOK_ASM_xxx */
74 OPT_DB
, /* warning: value is hardcoded from TOK_ASM_xxx */
77 #ifdef TCC_TARGET_X86_64
78 OPT_REG8_LOW
, /* %spl,%bpl,%sil,%dil, encoded like ah,ch,dh,bh, but
79 with REX prefix, not used in insn templates */
85 #ifdef TCC_TARGET_X86_64
88 OPT_EAX
, /* %al, %ax, %eax or %rax register */
89 OPT_ST0
, /* %st(0) register */
90 OPT_CL
, /* %cl register */
91 OPT_DX
, /* %dx register */
92 OPT_ADDR
, /* OP_EA with only offset */
93 OPT_INDIR
, /* *(expr) */
96 OPT_IM
, /* IM8 | IM16 | IM32 */
97 OPT_REG
, /* REG8 | REG16 | REG32 | REG64 */
98 OPT_REGW
, /* REG16 | REG32 | REG64 */
99 OPT_IMW
, /* IM16 | IM32 */
100 OPT_MMXSSE
, /* MMX | SSE */
101 OPT_DISP
, /* Like OPT_ADDR, but emitted as displacement (for jumps) */
102 OPT_DISP8
, /* Like OPT_ADDR, but only 8bit (short jumps) */
103 /* can be ored with any OPT_xxx */
107 #define OP_REG8 (1 << OPT_REG8)
108 #define OP_REG16 (1 << OPT_REG16)
109 #define OP_REG32 (1 << OPT_REG32)
110 #define OP_MMX (1 << OPT_MMX)
111 #define OP_SSE (1 << OPT_SSE)
112 #define OP_CR (1 << OPT_CR)
113 #define OP_TR (1 << OPT_TR)
114 #define OP_DB (1 << OPT_DB)
115 #define OP_SEG (1 << OPT_SEG)
116 #define OP_ST (1 << OPT_ST)
117 #define OP_IM8 (1 << OPT_IM8)
118 #define OP_IM8S (1 << OPT_IM8S)
119 #define OP_IM16 (1 << OPT_IM16)
120 #define OP_IM32 (1 << OPT_IM32)
121 #define OP_EAX (1 << OPT_EAX)
122 #define OP_ST0 (1 << OPT_ST0)
123 #define OP_CL (1 << OPT_CL)
124 #define OP_DX (1 << OPT_DX)
125 #define OP_ADDR (1 << OPT_ADDR)
126 #define OP_INDIR (1 << OPT_INDIR)
127 #ifdef TCC_TARGET_X86_64
128 # define OP_REG64 (1 << OPT_REG64)
129 # define OP_REG8_LOW (1 << OPT_REG8_LOW)
130 # define OP_IM64 (1 << OPT_IM64)
131 # define OP_EA32 (OP_EA << 1)
134 # define OP_REG8_LOW 0
139 #define OP_EA 0x40000000
140 #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
142 #ifdef TCC_TARGET_X86_64
143 # define TREG_XAX TREG_RAX
144 # define TREG_XCX TREG_RCX
145 # define TREG_XDX TREG_RDX
147 # define TREG_XAX TREG_EAX
148 # define TREG_XCX TREG_ECX
149 # define TREG_XDX TREG_EDX
152 typedef struct ASMInstr
{
157 uint8_t op_type
[MAX_OPERANDS
]; /* see OP_xxx */
160 typedef struct Operand
{
162 int8_t reg
; /* register, -1 if none */
163 int8_t reg2
; /* second register, -1 if none */
168 static const uint8_t reg_to_size
[9] = {
173 #ifdef TCC_TARGET_X86_64
177 0, 0, 1, 0, 2, 0, 0, 0, 3
180 #define NB_TEST_OPCODES 30
182 static const uint8_t test_bits
[NB_TEST_OPCODES
] = {
215 static const uint8_t segment_prefixes
[] = {
224 static const ASMInstr asm_instrs
[] = {
226 /* This removes a 0x0f in the second byte */
227 #define O(o) ((uint64_t) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o)))
228 /* This constructs instr_type from opcode, type and group. */
229 #define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
230 #define DEF_ASM_OP0(name, opcode)
231 #define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0, { 0 } },
232 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
233 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
234 #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 }},
235 #ifdef TCC_TARGET_X86_64
236 # include "x86_64-asm.h"
238 # include "i386-asm.h"
244 static const uint16_t op0_codes
[] = {
246 #define DEF_ASM_OP0(x, opcode) opcode,
247 #define DEF_ASM_OP0L(name, opcode, group, instr_type)
248 #define DEF_ASM_OP1(name, opcode, group, instr_type, op0)
249 #define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1)
250 #define DEF_ASM_OP3(name, opcode, group, instr_type, op0, op1, op2)
251 #ifdef TCC_TARGET_X86_64
252 # include "x86_64-asm.h"
254 # include "i386-asm.h"
258 static inline int get_reg_shift(TCCState
*s1
)
261 v
= asm_int_expr(s1
);
276 expect("1, 2, 4 or 8 constant");
283 #ifdef TCC_TARGET_X86_64
284 static int asm_parse_numeric_reg(int t
, unsigned int *type
)
287 if (t
>= TOK_IDENT
&& t
< tok_ident
) {
288 const char *s
= table_ident
[t
- TOK_IDENT
]->str
;
297 /* Don't allow leading '0'. */
298 if ((c
= *s
++) >= '1' && c
<= '9')
302 if ((c
= *s
) >= '0' && c
<= '5')
303 s
++, reg
= reg
* 10 + c
- '0';
308 else if (*type
!= OP_REG64
)
310 else if (c
== 'b' && !s
[1])
312 else if (c
== 'w' && !s
[1])
314 else if (c
== 'd' && !s
[1])
323 static int asm_parse_reg(unsigned int *type
)
330 if (tok
>= TOK_ASM_eax
&& tok
<= TOK_ASM_edi
) {
331 reg
= tok
- TOK_ASM_eax
;
333 #ifdef TCC_TARGET_X86_64
334 } else if (tok
>= TOK_ASM_rax
&& tok
<= TOK_ASM_rdi
) {
335 reg
= tok
- TOK_ASM_rax
;
337 } else if (tok
== TOK_ASM_rip
) {
338 reg
= -2; /* Probably should use different escape code. */
340 } else if ((reg
= asm_parse_numeric_reg(tok
, type
)) >= 0
341 && (*type
== OP_REG32
|| *type
== OP_REG64
)) {
352 static void parse_operand(TCCState
*s1
, Operand
*op
)
366 if (tok
>= TOK_ASM_al
&& tok
<= TOK_ASM_db7
) {
367 reg
= tok
- TOK_ASM_al
;
368 op
->type
= 1 << (reg
>> 3); /* WARNING: do not change constant order */
370 if ((op
->type
& OP_REG
) && op
->reg
== TREG_XAX
)
372 else if (op
->type
== OP_REG8
&& op
->reg
== TREG_XCX
)
374 else if (op
->type
== OP_REG16
&& op
->reg
== TREG_XDX
)
376 } else if (tok
>= TOK_ASM_dr0
&& tok
<= TOK_ASM_dr7
) {
378 op
->reg
= tok
- TOK_ASM_dr0
;
379 } else if (tok
>= TOK_ASM_es
&& tok
<= TOK_ASM_gs
) {
381 op
->reg
= tok
- TOK_ASM_es
;
382 } else if (tok
== TOK_ASM_st
) {
388 if (tok
!= TOK_PPNUM
)
392 if ((unsigned)reg
>= 8 || p
[1] != '\0')
401 #ifdef TCC_TARGET_X86_64
402 } else if (tok
>= TOK_ASM_spl
&& tok
<= TOK_ASM_dil
) {
403 op
->type
= OP_REG8
| OP_REG8_LOW
;
404 op
->reg
= 4 + tok
- TOK_ASM_spl
;
405 } else if ((op
->reg
= asm_parse_numeric_reg(tok
, &op
->type
)) >= 0) {
410 tcc_error("unknown register %%%s", get_tok_str(tok
, &tokc
));
414 } else if (tok
== '$') {
421 if (op
->e
.v
== (uint8_t)op
->e
.v
)
423 if (op
->e
.v
== (int8_t)op
->e
.v
)
425 if (op
->e
.v
== (uint16_t)op
->e
.v
)
427 #ifdef TCC_TARGET_X86_64
428 if (op
->e
.v
!= (int32_t)op
->e
.v
&& op
->e
.v
!= (uint32_t)op
->e
.v
)
433 /* address(reg,reg2,shift) with all variants */
448 /* bracketed offset expression */
459 unsigned int type
= 0;
462 op
->reg
= asm_parse_reg(&type
);
467 op
->reg2
= asm_parse_reg(&type
);
471 op
->shift
= get_reg_shift(s1
);
478 if (op
->reg
== -1 && op
->reg2
== -1)
484 /* XXX: unify with C code output ? */
485 ST_FUNC
void gen_expr32(ExprValue
*pe
)
488 /* If PC-relative, always set VT_SYM, even without symbol,
489 so as to force a relocation to be emitted. */
490 gen_addrpc32(VT_SYM
, pe
->sym
, pe
->v
);
492 gen_addr32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
495 #ifdef TCC_TARGET_X86_64
496 ST_FUNC
void gen_expr64(ExprValue
*pe
)
498 gen_addr64(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
502 /* XXX: unify with C code output ? */
503 static void gen_disp32(ExprValue
*pe
)
506 ElfSym
*esym
= elfsym(sym
);
507 if (esym
&& esym
->st_shndx
== cur_text_section
->sh_num
) {
508 /* same section: we can output an absolute value. Note
509 that the TCC compiler behaves differently here because
510 it always outputs a relocation to ease (future) code
511 elimination in the linker */
512 gen_le32(pe
->v
+ esym
->st_value
- ind
- 4);
514 if (sym
&& sym
->type
.t
== VT_VOID
) {
515 sym
->type
.t
= VT_FUNC
;
516 sym
->type
.ref
= NULL
;
518 gen_addrpc32(VT_SYM
, sym
, pe
->v
);
522 /* generate the modrm operand */
523 static inline int asm_modrm(int reg
, Operand
*op
)
525 int mod
, reg1
, reg2
, sib_reg1
;
527 if (op
->type
& (OP_REG
| OP_MMX
| OP_SSE
)) {
528 g(0xc0 + (reg
<< 3) + op
->reg
);
529 } else if (op
->reg
== -1 && op
->reg2
== -1) {
530 /* displacement only */
531 #ifdef TCC_TARGET_X86_64
532 g(0x04 + (reg
<< 3));
535 g(0x05 + (reg
<< 3));
538 #ifdef TCC_TARGET_X86_64
539 } else if (op
->reg
== -2) {
540 ExprValue
*pe
= &op
->e
;
541 g(0x05 + (reg
<< 3));
542 gen_addrpc32(pe
->sym
? VT_SYM
: 0, pe
->sym
, pe
->v
);
547 /* fist compute displacement encoding */
548 if (sib_reg1
== -1) {
551 } else if (op
->e
.v
== 0 && !op
->e
.sym
&& op
->reg
!= 5) {
553 } else if (op
->e
.v
== (int8_t)op
->e
.v
&& !op
->e
.sym
) {
558 /* compute if sib byte needed */
562 g(mod
+ (reg
<< 3) + reg1
);
567 reg2
= 4; /* indicate no index */
568 g((op
->shift
<< 6) + (reg2
<< 3) + sib_reg1
);
573 } else if (mod
== 0x80 || op
->reg
== -1) {
580 #ifdef TCC_TARGET_X86_64
586 static void asm_rex(int width64
, Operand
*ops
, int nb_ops
, int *op_type
,
589 unsigned char rex
= width64
? 0x48 : 0;
590 int saw_high_8bit
= 0;
593 /* No mod/rm byte, but we might have a register op nevertheless
594 (we will add it to the opcode later). */
595 for(i
= 0; i
< nb_ops
; i
++) {
596 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
597 if (ops
[i
].reg
>= 8) {
600 } else if (ops
[i
].type
& OP_REG8_LOW
)
602 else if (ops
[i
].type
& OP_REG8
&& ops
[i
].reg
>= 4)
603 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
604 saw_high_8bit
= ops
[i
].reg
;
610 if (ops
[regi
].reg
>= 8) {
613 } else if (ops
[regi
].type
& OP_REG8_LOW
)
615 else if (ops
[regi
].type
& OP_REG8
&& ops
[regi
].reg
>= 4)
616 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
617 saw_high_8bit
= ops
[regi
].reg
;
619 if (ops
[rmi
].type
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_EA
)) {
620 if (ops
[rmi
].reg
>= 8) {
623 } else if (ops
[rmi
].type
& OP_REG8_LOW
)
625 else if (ops
[rmi
].type
& OP_REG8
&& ops
[rmi
].reg
>= 4)
626 /* An 8 bit reg >= 4 without REG8 is ah/ch/dh/bh */
627 saw_high_8bit
= ops
[rmi
].reg
;
629 if (ops
[rmi
].type
& OP_EA
&& ops
[rmi
].reg2
>= 8) {
636 tcc_error("can't encode register %%%ch when REX prefix is required",
637 "acdb"[saw_high_8bit
-4]);
644 static void maybe_print_stats (void)
649 /* print stats about opcodes */
651 const struct ASMInstr
*pa
;
654 int nb_op_vals
, i
, j
;
658 memset(freq
, 0, sizeof(freq
));
659 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
661 //for(i=0;i<pa->nb_ops;i++) {
662 for(j
=0;j
<nb_op_vals
;j
++) {
663 //if (pa->op_type[i] == op_vals[j])
664 if (pa
->instr_type
== op_vals
[j
])
667 //op_vals[nb_op_vals++] = pa->op_type[i];
668 op_vals
[nb_op_vals
++] = pa
->instr_type
;
672 for(i
=0;i
<nb_op_vals
;i
++) {
674 //if ((v & (v - 1)) != 0)
675 printf("%3d: %08x\n", i
, v
);
677 printf("size=%d nb=%d f0=%d f1=%d f2=%d f3=%d\n",
678 (int)sizeof(asm_instrs
),
679 (int)sizeof(asm_instrs
) / (int)sizeof(ASMInstr
),
680 freq
[0], freq
[1], freq
[2], freq
[3]);
684 ST_FUNC
void asm_opcode(TCCState
*s1
, int opcode
)
687 int i
, modrm_index
, modreg_index
, reg
, v
, op1
, seg_prefix
, pc
, p
;
689 Operand ops
[MAX_OPERANDS
], *pop
;
690 int op_type
[3]; /* decoded op type */
691 int alltypes
; /* OR of all operand types */
694 #ifdef TCC_TARGET_X86_64
699 /* force synthetic ';' after prefix instruction, so we can handle */
700 /* one-line things like "rep stosb" instead of only "rep\nstosb" */
701 if (opcode
>= TOK_ASM_wait
&& opcode
<= TOK_ASM_repnz
)
710 if (tok
== ';' || tok
== TOK_LINEFEED
)
712 if (nb_ops
>= MAX_OPERANDS
) {
713 tcc_error("incorrect number of operands");
715 parse_operand(s1
, pop
);
717 if (pop
->type
!= OP_SEG
|| seg_prefix
)
718 tcc_error("incorrect prefix");
719 seg_prefix
= segment_prefixes
[pop
->reg
];
721 parse_operand(s1
, pop
);
722 if (!(pop
->type
& OP_EA
)) {
723 tcc_error("segment prefix must be followed by memory reference");
733 s
= 0; /* avoid warning */
736 /* optimize matching by using a lookup table (no hashing is needed
738 for(pa
= asm_instrs
; pa
->sym
!= 0; pa
++) {
739 int it
= pa
->instr_type
& OPCT_MASK
;
741 if (it
== OPC_FARITH
) {
742 v
= opcode
- pa
->sym
;
743 if (!((unsigned)v
< 8 * 6 && (v
% 6) == 0))
745 } else if (it
== OPC_ARITH
) {
746 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 8*NBWLX
))
748 s
= (opcode
- pa
->sym
) % NBWLX
;
749 if ((pa
->instr_type
& OPC_BWLX
) == OPC_WLX
)
751 /* We need to reject the xxxb opcodes that we accepted above.
752 Note that pa->sym for WLX opcodes is the 'w' token,
753 to get the 'b' token subtract one. */
754 if (((opcode
- pa
->sym
+ 1) % NBWLX
) == 0)
758 } else if (it
== OPC_SHIFT
) {
759 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ 7*NBWLX
))
761 s
= (opcode
- pa
->sym
) % NBWLX
;
762 } else if (it
== OPC_TEST
) {
763 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NB_TEST_OPCODES
))
765 /* cmovxx is a test opcode but accepts multiple sizes.
766 The suffixes aren't encoded in the table, instead we
767 simply force size autodetection always and deal with suffixed
768 variants below when we don't find e.g. "cmovzl". */
769 if (pa
->instr_type
& OPC_WLX
)
771 } else if (pa
->instr_type
& OPC_B
) {
772 #ifdef TCC_TARGET_X86_64
773 /* Some instructions don't have the full size but only
774 bwl form. insb e.g. */
775 if ((pa
->instr_type
& OPC_WLQ
) != OPC_WLQ
776 && !(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
779 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
))
781 s
= opcode
- pa
->sym
;
782 } else if (pa
->instr_type
& OPC_WLX
) {
783 if (!(opcode
>= pa
->sym
&& opcode
< pa
->sym
+ NBWLX
-1))
785 s
= opcode
- pa
->sym
+ 1;
787 if (pa
->sym
!= opcode
)
790 if (pa
->nb_ops
!= nb_ops
)
792 #ifdef TCC_TARGET_X86_64
793 /* Special case for moves. Selecting the IM64->REG64 form
794 should only be done if we really have an >32bit imm64, and that
795 is hardcoded. Ignore it here. */
796 if (pa
->opcode
== 0xb0 && ops
[0].type
!= OP_IM64
797 && (ops
[1].type
& OP_REG
) == OP_REG64
798 && !(pa
->instr_type
& OPC_0F
))
801 /* now decode and check each operand */
803 for(i
= 0; i
< nb_ops
; i
++) {
805 op1
= pa
->op_type
[i
];
809 v
= OP_IM8
| OP_IM16
| OP_IM32
;
812 v
= OP_REG8
| OP_REG16
| OP_REG32
| OP_REG64
;
815 v
= OP_REG16
| OP_REG32
| OP_REG64
;
818 v
= OP_IM16
| OP_IM32
;
834 if ((ops
[i
].type
& v
) == 0)
836 alltypes
|= ops
[i
].type
;
838 (void)alltypes
; /* maybe unused */
839 /* all is matching ! */
844 if (opcode
>= TOK_ASM_first
&& opcode
<= TOK_ASM_last
) {
846 b
= op0_codes
[opcode
- TOK_ASM_first
];
851 } else if (opcode
<= TOK_ASM_alllast
) {
852 tcc_error("bad operand with opcode '%s'",
853 get_tok_str(opcode
, NULL
));
855 /* Special case for cmovcc, we accept size suffixes but ignore
856 them, but we don't want them to blow up our tables. */
857 TokenSym
*ts
= table_ident
[opcode
- TOK_IDENT
];
859 && strchr("wlq", ts
->str
[ts
->len
-1])
860 && !memcmp(ts
->str
, "cmov", 4)) {
861 opcode
= tok_alloc(ts
->str
, ts
->len
-1)->tok
;
864 tcc_error("unknown opcode '%s'", ts
->str
);
867 /* if the size is unknown, then evaluate it (OPC_B or OPC_WL case) */
869 #ifdef TCC_TARGET_X86_64
870 /* XXX the autosize should rather be zero, to not have to adjust this
872 if ((pa
->instr_type
& OPC_BWLQ
) == OPC_B
)
876 /* Check for register operands providing hints about the size.
877 Start from the end, i.e. destination operands. This matters
878 only for opcodes accepting different sized registers, lar and lsl
880 for(i
= nb_ops
- 1; s
== autosize
&& i
>= 0; i
--) {
881 if ((ops
[i
].type
& OP_REG
) && !(op_type
[i
] & (OP_CL
| OP_DX
)))
882 s
= reg_to_size
[ops
[i
].type
& OP_REG
];
885 if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
886 (ops
[0].type
& (OP_SEG
| OP_IM8S
| OP_IM32
)))
888 else if ((opcode
== TOK_ASM_push
|| opcode
== TOK_ASM_pop
) &&
889 (ops
[0].type
& OP_EA
))
892 tcc_error("cannot infer opcode suffix");
896 #ifdef TCC_TARGET_X86_64
898 if (pa
->instr_type
& OPC_48
)
900 else if (s
== 3 || (alltypes
& OP_REG64
)) {
901 /* generate REX prefix */
903 for(i
= 0; i
< nb_ops
; i
++) {
904 if (op_type
[i
] == OP_REG64
&& pa
->opcode
!= 0xb8) {
905 /* If only 64bit regs are accepted in one operand
906 this is a default64 instruction without need for
907 REX prefixes, except for movabs(0xb8). */
912 /* XXX find better encoding for the default64 instructions. */
913 if (((opcode
!= TOK_ASM_push
&& opcode
!= TOK_ASM_pop
914 && opcode
!= TOK_ASM_pushw
&& opcode
!= TOK_ASM_pushl
915 && opcode
!= TOK_ASM_pushq
&& opcode
!= TOK_ASM_popw
916 && opcode
!= TOK_ASM_popl
&& opcode
!= TOK_ASM_popq
917 && opcode
!= TOK_ASM_call
&& opcode
!= TOK_ASM_jmp
))
923 /* now generates the operation */
924 if (OPCT_IS(pa
->instr_type
, OPC_FWAIT
))
928 #ifdef TCC_TARGET_X86_64
929 /* Generate addr32 prefix if needed */
930 for(i
= 0; i
< nb_ops
; i
++) {
931 if (ops
[i
].type
& OP_EA32
) {
937 /* generate data16 prefix if needed */
942 /* accepting mmx+sse in all operands --> needs 0x66 to
943 switch to sse mode. Accepting only sse in an operand --> is
944 already SSE insn and needs 0x66/f2/f3 handling. */
945 for (i
= 0; i
< nb_ops
; i
++)
946 if ((op_type
[i
] & (OP_MMX
| OP_SSE
)) == (OP_MMX
| OP_SSE
)
947 && ops
[i
].type
& OP_SSE
)
954 p
= v
>> 8; /* possibly prefix byte(s) */
956 case 0: break; /* no prefix */
957 case 0x48: break; /* REX, handled elsewhere */
961 case 0xf3: v
= v
& 0xff; g(p
); break;
962 case 0xd4: case 0xd5: break; /* aam and aad, not prefix, but hardcoded immediate argument "10" */
963 case 0xd8: case 0xd9: case 0xda: case 0xdb: /* x87, no normal prefix */
964 case 0xdc: case 0xdd: case 0xde: case 0xdf: break;
965 default: tcc_error("bad prefix 0x%2x in opcode table", p
); break;
967 if (pa
->instr_type
& OPC_0F
)
968 v
= ((v
& ~0xff) << 8) | 0x0f00 | (v
& 0xff);
969 if ((v
== 0x69 || v
== 0x6b) && nb_ops
== 2) {
970 /* kludge for imul $im, %reg */
973 op_type
[2] = op_type
[1];
974 } else if (v
== 0xcd && ops
[0].e
.v
== 3 && !ops
[0].e
.sym
) {
975 v
--; /* int $3 case */
977 } else if ((v
== 0x06 || v
== 0x07)) {
978 if (ops
[0].reg
>= 4) {
979 /* push/pop %fs or %gs */
980 v
= 0x0fa0 + (v
- 0x06) + ((ops
[0].reg
- 4) << 3);
982 v
+= ops
[0].reg
<< 3;
985 } else if (v
<= 0x05) {
987 v
+= ((opcode
- TOK_ASM_addb
) / NBWLX
) << 3;
988 } else if ((pa
->instr_type
& (OPCT_MASK
| OPC_MODRM
)) == OPC_FARITH
) {
990 v
+= ((opcode
- pa
->sym
) / 6) << 3;
993 /* search which operand will be used for modrm */
996 if (pa
->instr_type
& OPC_MODRM
) {
998 /* A modrm opcode without operands is a special case (e.g. mfence).
999 It has a group and acts as if there's an register operand 0
1002 ops
[i
].type
= OP_REG
;
1006 /* first look for an ea operand */
1007 for(i
= 0;i
< nb_ops
; i
++) {
1008 if (op_type
[i
] & OP_EA
)
1011 /* then if not found, a register or indirection (shift instructions) */
1012 for(i
= 0;i
< nb_ops
; i
++) {
1013 if (op_type
[i
] & (OP_REG
| OP_MMX
| OP_SSE
| OP_INDIR
))
1017 tcc_error("bad op table");
1021 /* if a register is used in another operand then it is
1022 used instead of group */
1023 for(i
= 0;i
< nb_ops
; i
++) {
1025 if (i
!= modrm_index
&&
1026 (t
& (OP_REG
| OP_MMX
| OP_SSE
| OP_CR
| OP_TR
| OP_DB
| OP_SEG
))) {
1032 #ifdef TCC_TARGET_X86_64
1033 asm_rex (rex64
, ops
, nb_ops
, op_type
, modreg_index
, modrm_index
);
1036 if (pa
->instr_type
& OPC_REG
) {
1037 /* mov $im, %reg case */
1038 if (v
== 0xb0 && s
>= 1)
1040 for(i
= 0; i
< nb_ops
; i
++) {
1041 if (op_type
[i
] & (OP_REG
| OP_ST
)) {
1047 if (pa
->instr_type
& OPC_B
)
1049 if (nb_ops
== 1 && pa
->op_type
[0] == OPT_DISP8
) {
1053 /* see if we can really generate the jump with a byte offset */
1054 esym
= elfsym(ops
[0].e
.sym
);
1055 if (!esym
|| esym
->st_shndx
!= cur_text_section
->sh_num
)
1057 jmp_disp
= ops
[0].e
.v
+ esym
->st_value
- ind
- 2 - (v
>= 0xff);
1058 if (jmp_disp
== (int8_t)jmp_disp
) {
1059 /* OK to generate jump */
1061 ops
[0].e
.v
= jmp_disp
;
1062 op_type
[0] = OP_IM8S
;
1065 /* long jump will be allowed. need to modify the
1067 if (v
== 0xeb) /* jmp */
1069 else if (v
== 0x70) /* jcc */
1072 tcc_error("invalid displacement");
1075 if (OPCT_IS(pa
->instr_type
, OPC_TEST
))
1076 v
+= test_bits
[opcode
- pa
->sym
];
1077 else if (OPCT_IS(pa
->instr_type
, OPC_0F01
))
1082 op1
= (v
>> 8) & 0xff;
1087 if (OPCT_IS(pa
->instr_type
, OPC_SHIFT
)) {
1088 reg
= (opcode
- pa
->sym
) / NBWLX
;
1091 } else if (OPCT_IS(pa
->instr_type
, OPC_ARITH
)) {
1092 reg
= (opcode
- pa
->sym
) / NBWLX
;
1093 } else if (OPCT_IS(pa
->instr_type
, OPC_FARITH
)) {
1094 reg
= (opcode
- pa
->sym
) / 6;
1096 reg
= (pa
->instr_type
>> OPC_GROUP_SHIFT
) & 7;
1100 if (pa
->instr_type
& OPC_MODRM
) {
1101 /* if a register is used in another operand then it is
1102 used instead of group */
1103 if (modreg_index
>= 0)
1104 reg
= ops
[modreg_index
].reg
;
1105 pc
= asm_modrm(reg
, &ops
[modrm_index
]);
1108 /* emit constants */
1109 #ifndef TCC_TARGET_X86_64
1110 if (!(pa
->instr_type
& OPC_0F
)
1111 && (pa
->opcode
== 0x9a || pa
->opcode
== 0xea)) {
1112 /* ljmp or lcall kludge */
1113 gen_expr32(&ops
[1].e
);
1115 tcc_error("cannot relocate");
1116 gen_le16(ops
[0].e
.v
);
1120 for(i
= 0;i
< nb_ops
; i
++) {
1122 if (v
& (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
| OP_IM8S
| OP_ADDR
)) {
1123 /* if multiple sizes are given it means we must look
1125 if ((v
| OP_IM8
| OP_IM64
) == (OP_IM8
| OP_IM16
| OP_IM32
| OP_IM64
)) {
1130 else if (s
== 2 || (v
& OP_IM64
) == 0)
1136 if ((v
& (OP_IM8
| OP_IM8S
| OP_IM16
)) && ops
[i
].e
.sym
)
1137 tcc_error("cannot relocate");
1139 if (v
& (OP_IM8
| OP_IM8S
)) {
1141 } else if (v
& OP_IM16
) {
1142 gen_le16(ops
[i
].e
.v
);
1143 #ifdef TCC_TARGET_X86_64
1144 } else if (v
& OP_IM64
) {
1145 gen_expr64(&ops
[i
].e
);
1147 } else if (pa
->op_type
[i
] == OPT_DISP
|| pa
->op_type
[i
] == OPT_DISP8
) {
1148 gen_disp32(&ops
[i
].e
);
1150 gen_expr32(&ops
[i
].e
);
1155 /* after immediate operands, adjust pc-relative address */
1157 add32le(cur_text_section
->data
+ pc
- 4, pc
- ind
);
1160 /* return the constraint priority (we allocate first the lowest
1161 numbered constraints) */
1162 static inline int constraint_priority(const char *str
)
1164 int priority
, c
, pr
;
1166 /* we take the lowest priority */
1203 tcc_error("unknown constraint '%c'", c
);
1212 static const char *skip_constraint_modifiers(const char *p
)
1214 while (*p
== '=' || *p
== '&' || *p
== '+' || *p
== '%')
1219 /* If T (a token) is of the form "%reg" returns the register
1220 number and type, otherwise return -1. */
1221 ST_FUNC
int asm_parse_regvar (int t
)
1225 if (t
< TOK_IDENT
|| (t
& SYM_FIELD
))
1227 s
= table_ident
[t
- TOK_IDENT
]->str
;
1230 t
= tok_alloc_const(s
+ 1);
1233 parse_operand(tcc_state
, &op
);
1234 /* Accept only integer regs for now. */
1235 if (op
.type
& OP_REG
)
1241 #define REG_OUT_MASK 0x01
1242 #define REG_IN_MASK 0x02
1244 #define is_reg_allocated(reg) (regs_allocated[reg] & reg_mask)
1246 ST_FUNC
void asm_compute_constraints(ASMOperand
*operands
,
1247 int nb_operands
, int nb_outputs
,
1248 const uint8_t *clobber_regs
,
1252 int sorted_op
[MAX_ASM_OPERANDS
];
1253 int i
, j
, k
, p1
, p2
, tmp
, reg
, c
, reg_mask
;
1255 uint8_t regs_allocated
[NB_ASM_REGS
];
1258 for(i
=0;i
<nb_operands
;i
++) {
1260 op
->input_index
= -1;
1266 /* compute constraint priority and evaluate references to output
1267 constraints if input constraints */
1268 for(i
=0;i
<nb_operands
;i
++) {
1270 str
= op
->constraint
;
1271 str
= skip_constraint_modifiers(str
);
1272 if (isnum(*str
) || *str
== '[') {
1273 /* this is a reference to another constraint */
1274 k
= find_constraint(operands
, nb_operands
, str
, NULL
);
1275 if ((unsigned)k
>= i
|| i
< nb_outputs
)
1276 tcc_error("invalid reference in constraint %d ('%s')",
1279 if (operands
[k
].input_index
>= 0)
1280 tcc_error("cannot reference twice the same operand");
1281 operands
[k
].input_index
= i
;
1283 } else if ((op
->vt
->r
& VT_VALMASK
) == VT_LOCAL
1285 && (reg
= op
->vt
->sym
->r
& VT_VALMASK
) < VT_CONST
) {
1289 op
->priority
= constraint_priority(str
);
1293 /* sort operands according to their priority */
1294 for(i
=0;i
<nb_operands
;i
++)
1296 for(i
=0;i
<nb_operands
- 1;i
++) {
1297 for(j
=i
+1;j
<nb_operands
;j
++) {
1298 p1
= operands
[sorted_op
[i
]].priority
;
1299 p2
= operands
[sorted_op
[j
]].priority
;
1302 sorted_op
[i
] = sorted_op
[j
];
1308 for(i
= 0;i
< NB_ASM_REGS
; i
++) {
1309 if (clobber_regs
[i
])
1310 regs_allocated
[i
] = REG_IN_MASK
| REG_OUT_MASK
;
1312 regs_allocated
[i
] = 0;
1314 /* esp cannot be used */
1315 regs_allocated
[4] = REG_IN_MASK
| REG_OUT_MASK
;
1316 /* ebp cannot be used yet */
1317 regs_allocated
[5] = REG_IN_MASK
| REG_OUT_MASK
;
1319 /* allocate registers and generate corresponding asm moves */
1320 for(i
=0;i
<nb_operands
;i
++) {
1323 str
= op
->constraint
;
1324 /* no need to allocate references */
1325 if (op
->ref_index
>= 0)
1327 /* select if register is used for output, input or both */
1328 if (op
->input_index
>= 0) {
1329 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1330 } else if (j
< nb_outputs
) {
1331 reg_mask
= REG_OUT_MASK
;
1333 reg_mask
= REG_IN_MASK
;
1336 if (is_reg_allocated(op
->reg
))
1337 tcc_error("asm regvar requests register that's taken already");
1350 if (j
>= nb_outputs
)
1351 tcc_error("'%c' modifier can only be applied to outputs", c
);
1352 reg_mask
= REG_IN_MASK
| REG_OUT_MASK
;
1355 /* allocate both eax and edx */
1356 if (is_reg_allocated(TREG_XAX
) ||
1357 is_reg_allocated(TREG_XDX
))
1361 regs_allocated
[TREG_XAX
] |= reg_mask
;
1362 regs_allocated
[TREG_XDX
] |= reg_mask
;
1382 if (is_reg_allocated(reg
))
1386 /* eax, ebx, ecx or edx */
1387 for(reg
= 0; reg
< 4; reg
++) {
1388 if (!is_reg_allocated(reg
))
1394 case 'p': /* A general address, for x86(64) any register is acceptable*/
1395 /* any general register */
1396 for(reg
= 0; reg
< 8; reg
++) {
1397 if (!is_reg_allocated(reg
))
1402 /* now we can reload in the register */
1405 regs_allocated
[reg
] |= reg_mask
;
1409 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
)) == VT_CONST
))
1415 if (!((op
->vt
->r
& (VT_VALMASK
| VT_LVAL
| VT_SYM
)) == VT_CONST
))
1420 /* nothing special to do because the operand is already in
1421 memory, except if the pointer itself is stored in a
1422 memory variable (VT_LLOCAL case) */
1423 /* XXX: fix constant case */
1424 /* if it is a reference to a memory zone, it must lie
1425 in a register, so we reserve the register in the
1426 input registers and a load will be generated
1428 if (j
< nb_outputs
|| c
== 'm') {
1429 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1430 /* any general register */
1431 for(reg
= 0; reg
< 8; reg
++) {
1432 if (!(regs_allocated
[reg
] & REG_IN_MASK
))
1437 /* now we can reload in the register */
1438 regs_allocated
[reg
] |= REG_IN_MASK
;
1445 tcc_error("asm constraint %d ('%s') could not be satisfied",
1449 /* if a reference is present for that operand, we assign it too */
1450 if (op
->input_index
>= 0) {
1451 operands
[op
->input_index
].reg
= op
->reg
;
1452 operands
[op
->input_index
].is_llong
= op
->is_llong
;
1456 /* compute out_reg. It is used to store outputs registers to memory
1457 locations references by pointers (VT_LLOCAL case) */
1459 for(i
=0;i
<nb_operands
;i
++) {
1462 (op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1464 for(reg
= 0; reg
< 8; reg
++) {
1465 if (!(regs_allocated
[reg
] & REG_OUT_MASK
))
1468 tcc_error("could not find free output register for reloading");
1475 /* print sorted constraints */
1477 for(i
=0;i
<nb_operands
;i
++) {
1480 printf("%%%d [%s]: \"%s\" r=0x%04x reg=%d\n",
1482 op
->id
? get_tok_str(op
->id
, NULL
) : "",
1488 printf("out_reg=%d\n", *pout_reg
);
1492 ST_FUNC
void subst_asm_operand(CString
*add_str
,
1493 SValue
*sv
, int modifier
)
1495 int r
, reg
, size
, val
;
1499 if ((r
& VT_VALMASK
) == VT_CONST
) {
1500 if (!(r
& VT_LVAL
) && modifier
!= 'c' && modifier
!= 'n' &&
1502 cstr_ccat(add_str
, '$');
1504 const char *name
= get_tok_str(sv
->sym
->v
, NULL
);
1505 if (sv
->sym
->v
>= SYM_FIRST_ANOM
) {
1506 /* In case of anonymous symbols ("L.42", used
1507 for static data labels) we can't find them
1508 in the C symbol table when later looking up
1509 this name. So enter them now into the asm label
1510 list when we still know the symbol. */
1511 get_asm_sym(tok_alloc_const(name
), sv
->sym
);
1513 if (tcc_state
->leading_underscore
)
1514 cstr_ccat(add_str
, '_');
1515 cstr_cat(add_str
, name
, -1);
1516 if ((uint32_t)sv
->c
.i
== 0)
1518 cstr_ccat(add_str
, '+');
1521 if (modifier
== 'n')
1523 snprintf(buf
, sizeof(buf
), "%d", (int)sv
->c
.i
);
1524 cstr_cat(add_str
, buf
, -1);
1526 #ifdef TCC_TARGET_X86_64
1528 cstr_cat(add_str
, "(%rip)", -1);
1530 } else if ((r
& VT_VALMASK
) == VT_LOCAL
) {
1531 #ifdef TCC_TARGET_X86_64
1532 snprintf(buf
, sizeof(buf
), "%d(%%rbp)", (int)sv
->c
.i
);
1534 snprintf(buf
, sizeof(buf
), "%d(%%ebp)", (int)sv
->c
.i
);
1536 cstr_cat(add_str
, buf
, -1);
1537 } else if (r
& VT_LVAL
) {
1538 reg
= r
& VT_VALMASK
;
1539 if (reg
>= VT_CONST
)
1540 tcc_internal_error("");
1541 snprintf(buf
, sizeof(buf
), "(%%%s)",
1542 #ifdef TCC_TARGET_X86_64
1543 get_tok_str(TOK_ASM_rax
+ reg
, NULL
)
1545 get_tok_str(TOK_ASM_eax
+ reg
, NULL
)
1548 cstr_cat(add_str
, buf
, -1);
1551 reg
= r
& VT_VALMASK
;
1552 if (reg
>= VT_CONST
)
1553 tcc_internal_error("");
1555 /* choose register operand size */
1556 if ((sv
->type
.t
& VT_BTYPE
) == VT_BYTE
||
1557 (sv
->type
.t
& VT_BTYPE
) == VT_BOOL
)
1559 else if ((sv
->type
.t
& VT_BTYPE
) == VT_SHORT
)
1561 #ifdef TCC_TARGET_X86_64
1562 else if ((sv
->type
.t
& VT_BTYPE
) == VT_LLONG
||
1563 (sv
->type
.t
& VT_BTYPE
) == VT_PTR
)
1568 if (size
== 1 && reg
>= 4)
1571 if (modifier
== 'b') {
1573 tcc_error("cannot use byte register");
1575 } else if (modifier
== 'h') {
1577 tcc_error("cannot use byte register");
1579 } else if (modifier
== 'w') {
1581 } else if (modifier
== 'k') {
1583 #ifdef TCC_TARGET_X86_64
1584 } else if (modifier
== 'q') {
1591 reg
= TOK_ASM_ah
+ reg
;
1594 reg
= TOK_ASM_al
+ reg
;
1597 reg
= TOK_ASM_ax
+ reg
;
1600 reg
= TOK_ASM_eax
+ reg
;
1602 #ifdef TCC_TARGET_X86_64
1604 reg
= TOK_ASM_rax
+ reg
;
1608 snprintf(buf
, sizeof(buf
), "%%%s", get_tok_str(reg
, NULL
));
1609 cstr_cat(add_str
, buf
, -1);
1613 /* generate prolog and epilog code for asm statement */
1614 ST_FUNC
void asm_gen_code(ASMOperand
*operands
, int nb_operands
,
1615 int nb_outputs
, int is_output
,
1616 uint8_t *clobber_regs
,
1619 uint8_t regs_allocated
[NB_ASM_REGS
];
1623 /* Strictly speaking %Xbp and %Xsp should be included in the
1624 call-preserved registers, but currently it doesn't matter. */
1625 #ifdef TCC_TARGET_X86_64
1626 #ifdef TCC_TARGET_PE
1627 static const uint8_t reg_saved
[] = { 3, 6, 7, 12, 13, 14, 15 };
1629 static const uint8_t reg_saved
[] = { 3, 12, 13, 14, 15 };
1632 static const uint8_t reg_saved
[] = { 3, 6, 7 };
1635 /* mark all used registers */
1636 memcpy(regs_allocated
, clobber_regs
, sizeof(regs_allocated
));
1637 for(i
= 0; i
< nb_operands
;i
++) {
1640 regs_allocated
[op
->reg
] = 1;
1643 /* generate reg save code */
1644 for(i
= 0; i
< sizeof(reg_saved
)/sizeof(reg_saved
[0]); i
++) {
1646 if (regs_allocated
[reg
]) {
1653 /* generate load code */
1654 for(i
= 0; i
< nb_operands
; i
++) {
1657 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
&&
1659 /* memory reference case (for both input and
1663 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
| VT_LVAL
;
1666 } else if (i
>= nb_outputs
|| op
->is_rw
) {
1667 /* load value in register */
1668 load(op
->reg
, op
->vt
);
1673 load(TREG_XDX
, &sv
);
1679 /* generate save code */
1680 for(i
= 0 ; i
< nb_outputs
; i
++) {
1683 if ((op
->vt
->r
& VT_VALMASK
) == VT_LLOCAL
) {
1684 if (!op
->is_memory
) {
1687 sv
.r
= (sv
.r
& ~VT_VALMASK
) | VT_LOCAL
;
1692 sv
.r
= (sv
.r
& ~VT_VALMASK
) | out_reg
;
1693 store(op
->reg
, &sv
);
1696 store(op
->reg
, op
->vt
);
1701 store(TREG_XDX
, &sv
);
1706 /* generate reg restore code */
1707 for(i
= sizeof(reg_saved
)/sizeof(reg_saved
[0]) - 1; i
>= 0; i
--) {
1709 if (regs_allocated
[reg
]) {
1718 ST_FUNC
void asm_clobber(uint8_t *clobber_regs
, const char *str
)
1721 #ifdef TCC_TARGET_X86_64
1725 if (!strcmp(str
, "memory") ||
1726 !strcmp(str
, "cc") ||
1727 !strcmp(str
, "flags"))
1729 reg
= tok_alloc_const(str
);
1730 if (reg
>= TOK_ASM_eax
&& reg
<= TOK_ASM_edi
) {
1732 } else if (reg
>= TOK_ASM_ax
&& reg
<= TOK_ASM_di
) {
1734 #ifdef TCC_TARGET_X86_64
1735 } else if (reg
>= TOK_ASM_rax
&& reg
<= TOK_ASM_rdi
) {
1737 } else if ((reg
= asm_parse_numeric_reg(reg
, &type
)) >= 0) {
1741 tcc_error("invalid clobber register '%s'", str
);
1743 clobber_regs
[reg
] = 1;