History

x86-64-asm: Clean up 64bit immediate support

Fix it to actually be able to parse 64bit immediates (enlarge operand value type). Then, generally there's no need for accepting IM64 anywhere, except in the 0xba+r mov opcodes, so OP_IM is unnecessary, as is OPT_IMNO64. Improve the generated code a bit by preferring the 0xc7 opcode for im32->reg64, instead of the im64->reg64 form (which we therefore hardcode).

Michael Matz committed 10 years ago

Commit b9f01df1 parent f3cee9c5 files · +39 −24Browse files

Unified · Split

5 files
  1. i386-asm.c +16 −18
  2. tcc.h +1 −1
  3. tccasm.c +2 −1
  4. tests/asmtest.S +10 −0
  5. x86_64-asm.h +10 −4
i386-asm.c+16−18
@@ -83,13 +83,10 @@ enum { · 82 unmodified lines
8383 OPT_INDIR, /* *(expr) */
8484 /* composite types */
8585 OPT_COMPOSITE_FIRST,
86− OPT_IM, /* IM8 | IM16 | IM32 | IM64 */
86+ OPT_IM, /* IM8 | IM16 | IM32 */
8787 OPT_REG, /* REG8 | REG16 | REG32 | REG64 */
8888 OPT_REGW, /* REG16 | REG32 | REG64 */
89− OPT_IMW, /* IM16 | IM32 | IM64 */
90−#ifdef TCC_TARGET_X86_64
91− OPT_IMNO64, /* IM16 | IM32 */
92−#endif
89+ OPT_IMW, /* IM16 | IM32 */
9390 /* can be ored with any OPT_xxx */
9491 OPT_EA = 0x80
9592 };
@@ -128,12 +125,10 @@ enum { · 32 unmodified lines
128125 #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
129126
130127 #ifdef TCC_TARGET_X86_64
131−# define OP_IM OP_IM64
132128 # define TREG_XAX TREG_RAX
133129 # define TREG_XCX TREG_RCX
134130 # define TREG_XDX TREG_RDX
135131 #else
136−# define OP_IM OP_IM32
137132 # define TREG_XAX TREG_EAX
138133 # define TREG_XCX TREG_ECX
139134 # define TREG_XDX TREG_EDX
@@ -347,7 +342,7 @@ static void parse_operand(TCCState *s1, Operand *op) · 207 unmodified lines
347342 /* constant value */
348343 next();
349344 asm_expr(s1, &e);
350− op->type = OP_IM;
345+ op->type = OP_IM32;
351346 op->e.v = e.v;
352347 op->e.sym = e.sym;
353348 if (!op->e.sym) {
@@ -358,8 +353,8 @@ static void parse_operand(TCCState *s1, Operand *op) · 4 unmodified lines
358353 if (op->e.v == (uint16_t)op->e.v)
359354 op->type |= OP_IM16;
360355 #ifdef TCC_TARGET_X86_64
361− if (op->e.v == (uint32_t)op->e.v)
362− op->type |= OP_IM32;
356+ if (op->e.v != (uint32_t)op->e.v)
357+ op->type = OP_IM64;
363358 #endif
364359 }
365360 } else {
@@ -587,6 +582,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 221 unmodified lines
587582 }
588583 if (pa->nb_ops != nb_ops)
589584 continue;
585+#ifdef TCC_TARGET_X86_64
586+ /* Special case for moves. Selecting the IM64->REG64 form
587+ should only be done if we really have an >32bit imm64, and that
588+ is hardcoded. Ignore it here. */
589+ if (pa->opcode == 0xb0 && ops[0].type != OP_IM64
590+ && ops[1].type == OP_REG64)
591+ continue;
592+#endif
590593 /* now decode and check each operand */
591594 alltypes = 0;
592595 for(i = 0; i < nb_ops; i++) {
@@ -595,7 +598,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 2 unmodified lines
595598 op2 = op1 & 0x1f;
596599 switch(op2) {
597600 case OPT_IM:
598− v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
601+ v = OP_IM8 | OP_IM16 | OP_IM32;
599602 break;
600603 case OPT_REG:
601604 v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64;
@@ -604,13 +607,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 2 unmodified lines
604607 v = OP_REG16 | OP_REG32 | OP_REG64;
605608 break;
606609 case OPT_IMW:
607− v = OP_IM16 | OP_IM32 | OP_IM64;
608− break;
609−#ifdef TCC_TARGET_X86_64
610− case OPT_IMNO64:
611610 v = OP_IM16 | OP_IM32;
612611 break;
613−#endif
614612 default:
615613 v = 1 << op2;
616614 break;
@@ -647,7 +645,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 30 unmodified lines
647645 #ifdef TCC_TARGET_X86_64
648646 /* XXX the autosize should rather be zero, to not have to adjust this
649647 all the time. */
650− if ((pa->instr_type & OPC_WLQ) != OPC_WLQ)
648+ if ((pa->instr_type & OPC_BWLQ) == OPC_B)
651649 autosize = NBWLX-2;
652650 #endif
653651 if (s == autosize) {
@@ -657,7 +655,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 3 unmodified lines
657655 }
658656 if (s == autosize) {
659657 if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
660− (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
658+ (ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
661659 s = 2;
662660 else
663661 tcc_error("cannot infer opcode suffix");
tcc.h+1−1
@@ -610,7 +610,7 @@ typedef struct CachedInclude { · 609 unmodified lines
610610
611611 #ifdef CONFIG_TCC_ASM
612612 typedef struct ExprValue {
613− uint32_t v;
613+ uint64_t v;
614614 Sym *sym;
615615 } ExprValue;
616616
tccasm.c+2−1
@@ -41,7 +41,8 @@ static Sym sym_dot; · 40 unmodified lines
4141 static void asm_expr_unary(TCCState *s1, ExprValue *pe)
4242 {
4343 Sym *sym;
44− int op, n, label;
44+ int op, label;
45+ long n;
4546 const char *p;
4647
4748 switch(tok) {
tests/asmtest.S+10−0
@@ -46,6 +46,16 @@ movl %eax, 0x100(%ebx,%edx,2) · 45 unmodified lines
4646 movl 0x100(%ebx,%edx,2), %edx
4747 movw %ax, 0x100(%ebx,%edx,2)
4848
49+movw $0x1122,%si
50+movl $0x112233,%edx
51+#ifdef __x86_64__
52+mov $0x11223344,%rbx
53+movq $0x11223344,%rbx
54+mov $0x1122334455,%rbx
55+movq $0x1122334455,%rbx
56+movl $0x11334455,(%rbx)
57+#endif
58+
4959 mov %eax, 0x12(,%edx,2)
5060
5161 #ifdef __i386__
x86_64-asm.h+10−4
@@ -97,7 +97,13 @@ ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLQ, OPT_ADDR, OPT_EAX)) · 96 unmodified lines
9797 ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLQ, OPT_EAX, OPT_ADDR)) */
9898 ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG))
9999 ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG))
100+/* The moves are special: the 0xb8 form supports IM64 (the only insn that
101+ does) with REG64. It doesn't support IM32 with REG64, it would use
102+ the full movabs form (64bit immediate). For IM32->REG64 we prefer
103+ the 0xc7 opcode. So disallow all 64bit forms and code the rest by hand. */
100104 ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLQ, OPT_IM, OPT_REG))
105+ALT(DEF_ASM_OP2(mov, 0x48b8, 0, OPC_REG, OPT_IM64, OPT_REG64))
106+ALT(DEF_ASM_OP2(movq, 0x48b8, 0, OPC_REG, OPT_IM64, OPT_REG64))
101107 ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_REG | OPT_EA))
102108
103109 ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLQ, OPT_SEG, OPT_EA | OPT_REG))
@@ -156,14 +162,14 @@ ALT(DEF_ASM_OP2(lgs, 0x0fb5, 0, OPC_MODRM, OPT_EA, OPT_REG32)) · 52 unmodified lines
156162 /* arith */
157163 ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */
158164 ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG))
159−ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLQ, OPT_IMNO64, OPT_EAX))
160−ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_IMNO64, OPT_EA | OPT_REG))
165+ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLQ, OPT_IM, OPT_EAX))
166+ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_EA | OPT_REG))
161167 ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLQ, OPT_IM8S, OPT_EA | OPT_REG))
162168
163169 ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG))
164170 ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG))
165−ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLQ, OPT_IMNO64, OPT_EAX))
166−ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLQ, OPT_IMNO64, OPT_EA | OPT_REG))
171+ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLQ, OPT_IM, OPT_EAX))
172+ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_EA | OPT_REG))
167173
168174 ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA))
169175 ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA))

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t