History

x86-asm: Reorganize instr_type

Disjoint instruction types don't need to be a bit field, so introduce an enumeration (3 bits). Also the 0x0f prefix can be expressed by a bit, doesn't need a byte in the opcode field. That enables to encode further prefixes still in 16 bit. To not have to touch all insns do some macro fiddling filtering out a 0x0f byte in the second position.

Michael Matz committed 10 years ago

Commit bde802d1 parent 4af6e083 files · +65 −46Browse files

Unified · Split

3 files
  1. i386-asm.c +63 −44
  2. i386-asm.h +1 −1
  3. x86_64-asm.h +1 −1
i386-asm.c+63−44
@@ -29,19 +29,26 @@ · 28 unmodified lines
29#define TOK_ASM_last TOK_ASM_emms29#define TOK_ASM_last TOK_ASM_emms
30#define TOK_ASM_alllast TOK_ASM_subps30#define TOK_ASM_alllast TOK_ASM_subps
31 31
32#define OPC_JMP 0x01 /* jmp operand */32#define OPC_B 0x01 /* only used with OPC_WL */
33#define OPC_B 0x02 /* only used with OPC_WL */33#define OPC_WL 0x02 /* accepts w, l or no suffix */
34#define OPC_WL 0x04 /* accepts w, l or no suffix */
35#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */34#define OPC_BWL (OPC_B | OPC_WL) /* accepts b, w, l or no suffix */
36#define OPC_REG 0x08 /* register is added to opcode */35#define OPC_REG 0x04 /* register is added to opcode */
37#define OPC_MODRM 0x10 /* modrm encoding */36#define OPC_MODRM 0x08 /* modrm encoding */
38#define OPC_FWAIT 0x20 /* add fwait opcode */37
39#define OPC_TEST 0x40 /* test opcodes */38#define OPCT_MASK 0x70
40#define OPC_SHIFT 0x80 /* shift opcodes */39#define OPC_FWAIT 0x10 /* add fwait opcode */
41#define OPC_D16 0x0100 /* generate data16 prefix */40#define OPC_SHIFT 0x20 /* shift opcodes */
42#define OPC_ARITH 0x0200 /* arithmetic opcodes */41#define OPC_ARITH 0x30 /* arithmetic opcodes */
43#define OPC_SHORTJMP 0x0400 /* short jmp operand */42#define OPC_FARITH 0x40 /* FPU arithmetic opcodes */
44#define OPC_FARITH 0x0800 /* FPU arithmetic opcodes */43#define OPC_TEST 0x50 /* test opcodes */
44#define OPC_JMP_TEST 0x60 /* A test and jmp opcode */
45#define OPC_JMP 0x70 /* A non-testing jmp opcode */
46#define OPCT_IS(v,i) (((v) & OPCT_MASK) == (i))
47
48#define OPC_SHORTJMP 0x80 /* short jmp operand */
49
50#define OPC_0F 0x100 /* Is secondary map (0x0f prefix) */
51#define OPC_D16 0x0800 /* generate data16 prefix */
45#ifdef TCC_TARGET_X86_6452#ifdef TCC_TARGET_X86_64
46# define OPC_WLQ 0x1000 /* accepts w, l, q or no suffix */53# 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 */54# define OPC_BWLQ (OPC_B | OPC_WLQ) /* accepts b, w, l, q or no suffix */
@@ -211,11 +218,15 @@ static const uint8_t segment_prefixes[] = { · 163 unmodified lines
211 218
212static const ASMInstr asm_instrs[] = {219static const ASMInstr asm_instrs[] = {
213#define ALT(x) x220#define ALT(x) x
221/* This removes a 0x0f in the second byte */
222#define O(o) ((((o) & 0xff00) == 0x0f00) ? ((((o) >> 8) & ~0xff) | ((o) & 0xff)) : (o))
223/* This constructs instr_type from opcode, type and group. */
224#define T(o,i,g) ((i) | ((g) << OPC_GROUP_SHIFT) | ((((o) & 0xff00) == 0x0f00) ? OPC_0F : 0))
214#define DEF_ASM_OP0(name, opcode)225#define DEF_ASM_OP0(name, opcode)
215#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 0 },226#define DEF_ASM_OP0L(name, opcode, group, instr_type) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 0 },
216#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 1, { op0 }},227#define DEF_ASM_OP1(name, opcode, group, instr_type, op0) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 1, { op0 }},
217#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, opcode, (instr_type | group << OPC_GROUP_SHIFT), 2, { op0, op1 }},228#define DEF_ASM_OP2(name, opcode, group, instr_type, op0, op1) { TOK_ASM_ ## name, O(opcode), T(opcode, instr_type, group), 2, { op0, op1 }},
218#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 }},229#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 }},
219#ifdef TCC_TARGET_X86_64230#ifdef TCC_TARGET_X86_64
220# include "x86_64-asm.h"231# include "x86_64-asm.h"
221#else232#else
@@ -594,12 +605,13 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 372 unmodified lines
594 /* optimize matching by using a lookup table (no hashing is needed605 /* optimize matching by using a lookup table (no hashing is needed
595 !) */606 !) */
596 for(pa = asm_instrs; pa->sym != 0; pa++) {607 for(pa = asm_instrs; pa->sym != 0; pa++) {
608 int it = pa->instr_type & OPCT_MASK;
597 s = 0;609 s = 0;
598 if (pa->instr_type & OPC_FARITH) {610 if (it == OPC_FARITH) {
599 v = opcode - pa->sym;611 v = opcode - pa->sym;
600 if (!((unsigned)v < 8 * 6 && (v % 6) == 0))612 if (!((unsigned)v < 8 * 6 && (v % 6) == 0))
601 continue;613 continue;
602 } else if (pa->instr_type & OPC_ARITH) {614 } else if (it == OPC_ARITH) {
603 if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX))615 if (!(opcode >= pa->sym && opcode < pa->sym + 8*NBWLX))
604 continue;616 continue;
605 s = (opcode - pa->sym) % NBWLX;617 s = (opcode - pa->sym) % NBWLX;
@@ -612,11 +624,11 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 6 unmodified lines
612 continue;624 continue;
613 s++;625 s++;
614 }626 }
615 } else if (pa->instr_type & OPC_SHIFT) {627 } else if (it == OPC_SHIFT) {
616 if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX))628 if (!(opcode >= pa->sym && opcode < pa->sym + 7*NBWLX))
617 continue;629 continue;
618 s = (opcode - pa->sym) % NBWLX;630 s = (opcode - pa->sym) % NBWLX;
619 } else if (pa->instr_type & OPC_TEST) {631 } else if (it == OPC_TEST || it == OPC_JMP_TEST) {
620 if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))632 if (!(opcode >= pa->sym && opcode < pa->sym + NB_TEST_OPCODES))
621 continue;633 continue;
622 /* cmovxx is a test opcode but accepts multiple sizes.634 /* cmovxx is a test opcode but accepts multiple sizes.
@@ -650,7 +662,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 27 unmodified lines
650 should only be done if we really have an >32bit imm64, and that662 should only be done if we really have an >32bit imm64, and that
651 is hardcoded. Ignore it here. */663 is hardcoded. Ignore it here. */
652 if (pa->opcode == 0xb0 && ops[0].type != OP_IM64664 if (pa->opcode == 0xb0 && ops[0].type != OP_IM64
653 && ops[1].type == OP_REG64)665 && ops[1].type == OP_REG64
666 && !(pa->instr_type & OPC_0F))
654 continue;667 continue;
655#endif668#endif
656 /* now decode and check each operand */669 /* now decode and check each operand */
@@ -777,12 +790,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 120 unmodified lines
777#endif790#endif
778 791
779 /* now generates the operation */792 /* now generates the operation */
780 if (pa->instr_type & OPC_FWAIT)793 if (OPCT_IS(pa->instr_type, OPC_FWAIT))
781 g(0x9b);794 g(0x9b);
782 if (seg_prefix)795 if (seg_prefix)
783 g(seg_prefix);796 g(seg_prefix);
784 797
785 v = pa->opcode;798 v = pa->opcode;
799 if (pa->instr_type & OPC_0F)
800 v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff);
786 if ((v == 0x69 || v == 0x6b) && nb_ops == 2) {801 if ((v == 0x69 || v == 0x6b) && nb_ops == 2) {
787 /* kludge for imul $im, %reg */802 /* kludge for imul $im, %reg */
788 nb_ops = 3;803 nb_ops = 3;
@@ -802,25 +817,23 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 13 unmodified lines
802 } else if (v <= 0x05) {817 } else if (v <= 0x05) {
803 /* arith case */818 /* arith case */
804 v += ((opcode - TOK_ASM_addb) / NBWLX) << 3;819 v += ((opcode - TOK_ASM_addb) / NBWLX) << 3;
805 } else if ((pa->instr_type & (OPC_FARITH | OPC_MODRM)) == OPC_FARITH) {820 } else if ((pa->instr_type & (OPCT_MASK | OPC_MODRM)) == OPC_FARITH) {
806 /* fpu arith case */821 /* fpu arith case */
807 v += ((opcode - pa->sym) / 6) << 3;822 v += ((opcode - pa->sym) / 6) << 3;
808 }823 }
809 if (pa->instr_type & OPC_REG) {824 if (pa->instr_type & OPC_REG) {
825 /* mov $im, %reg case */
826 if (v == 0xb0 && s >= 1)
827 v += 7;
810 for(i = 0; i < nb_ops; i++) {828 for(i = 0; i < nb_ops; i++) {
811 if (op_type[i] & (OP_REG | OP_ST)) {829 if (op_type[i] & (OP_REG | OP_ST)) {
812 v += ops[i].reg;830 v += ops[i].reg;
813 break;831 break;
814 }832 }
815 }833 }
816 /* mov $im, %reg case */
817 if (pa->opcode == 0xb0 && s >= 1)
818 v += 7;
819 }834 }
820 if (pa->instr_type & OPC_B)835 if (pa->instr_type & OPC_B)
821 v += s >= 1;836 v += s >= 1;
822 if (pa->instr_type & OPC_TEST)
823 v += test_bits[opcode - pa->sym];
824 if (pa->instr_type & OPC_SHORTJMP) {837 if (pa->instr_type & OPC_SHORTJMP) {
825 Sym *sym;838 Sym *sym;
826 int jmp_disp;839 int jmp_disp;
@@ -839,32 +852,36 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 12 unmodified lines
839 op_type[0] = OP_IM8S;852 op_type[0] = OP_IM8S;
840 } else {853 } else {
841 no_short_jump:854 no_short_jump:
842 if (pa->instr_type & OPC_JMP) {855 /* long jump will be allowed. need to modify the
843 /* long jump will be allowed. need to modify the856 opcode slightly */
844 opcode slightly */857 if (v == 0xeb) /* jmp */
845 if (v == 0xeb)858 v = 0xe9;
846 v = 0xe9;859 else if (v == 0x70) /* jcc */
847 else860 v += 0x0f10;
848 v += 0x0f10;861 else
849 } else {862 tcc_error("invalid displacement");
850 tcc_error("invalid displacement");
851 }
852 }863 }
853 }864 }
854 op1 = v >> 8;865 if (OPCT_IS(pa->instr_type, OPC_TEST)
866 || OPCT_IS(pa->instr_type, OPC_JMP_TEST))
867 v += test_bits[opcode - pa->sym];
868 op1 = v >> 16;
869 if (op1)
870 g(op1);
871 op1 = (v >> 8) & 0xff;
855 if (op1)872 if (op1)
856 g(op1);873 g(op1);
857 g(v);874 g(v);
858 875
859 /* search which operand will used for modrm */876 /* search which operand will used for modrm */
860 modrm_index = 0;877 modrm_index = 0;
861 if (pa->instr_type & OPC_SHIFT) {878 if (OPCT_IS(pa->instr_type, OPC_SHIFT)) {
862 reg = (opcode - pa->sym) / NBWLX;879 reg = (opcode - pa->sym) / NBWLX;
863 if (reg == 6)880 if (reg == 6)
864 reg = 7;881 reg = 7;
865 } else if (pa->instr_type & OPC_ARITH) {882 } else if (OPCT_IS(pa->instr_type, OPC_ARITH)) {
866 reg = (opcode - pa->sym) / NBWLX;883 reg = (opcode - pa->sym) / NBWLX;
867 } else if (pa->instr_type & OPC_FARITH) {884 } else if (OPCT_IS(pa->instr_type, OPC_FARITH)) {
868 reg = (opcode - pa->sym) / 6;885 reg = (opcode - pa->sym) / 6;
869 } else {886 } else {
870 reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;887 reg = (pa->instr_type >> OPC_GROUP_SHIFT) & 7;
@@ -902,7 +919,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 31 unmodified lines
902 919
903 /* emit constants */920 /* emit constants */
904#ifndef TCC_TARGET_X86_64921#ifndef TCC_TARGET_X86_64
905 if (pa->opcode == 0x9a || pa->opcode == 0xea) {922 if (!(pa->instr_type & OPC_0F)
923 && (pa->opcode == 0x9a || pa->opcode == 0xea)) {
906 /* ljmp or lcall kludge */924 /* ljmp or lcall kludge */
907 gen_expr32(&ops[1].e);925 gen_expr32(&ops[1].e);
908 if (ops[0].e.sym)926 if (ops[0].e.sym)
@@ -938,7 +956,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 29 unmodified lines
938 } else if (v & OP_IM64) {956 } else if (v & OP_IM64) {
939 gen_expr64(&ops[i].e);957 gen_expr64(&ops[i].e);
940#endif958#endif
941 } else if (pa->instr_type & (OPC_JMP | OPC_SHORTJMP)) {959 } else if (OPCT_IS (pa->instr_type, OPC_JMP)
960 || OPCT_IS (pa->instr_type, OPC_JMP_TEST)) {
942 gen_disp32(&ops[i].e);961 gen_disp32(&ops[i].e);
943 } else {962 } else {
944 gen_expr32(&ops[i].e);963 gen_expr32(&ops[i].e);
i386-asm.h+1−1
@@ -221,7 +221,7 @@ ALT(DEF_ASM_OP1(ret, 0xc2, 0, 0, OPT_IM16)) · 220 unmodified lines
221 DEF_ASM_OP0(lret, 0xcb)221 DEF_ASM_OP0(lret, 0xcb)
222ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))222ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
223 223
224ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))224ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP_TEST, OPT_ADDR))
225 DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)225 DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
226 DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)226 DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
227 DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)227 DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)
x86_64-asm.h+1−1
@@ -226,7 +226,7 @@ ALT(DEF_ASM_OP1(retq, 0xc2, 0, 0, OPT_IM16)) · 225 unmodified lines
226 DEF_ASM_OP0(lret, 0xcb)226 DEF_ASM_OP0(lret, 0xcb)
227ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))227ALT(DEF_ASM_OP1(lret, 0xca, 0, 0, OPT_IM16))
228 228
229ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP | OPC_TEST, OPT_ADDR))229ALT(DEF_ASM_OP1(jo, 0x70, 0, OPC_SHORTJMP | OPC_JMP_TEST, OPT_ADDR))
230 DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)230 DEF_ASM_OP1(loopne, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
231 DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)231 DEF_ASM_OP1(loopnz, 0xe0, 0, OPC_SHORTJMP, OPT_ADDR)
232 DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)232 DEF_ASM_OP1(loope, 0xe1, 0, OPC_SHORTJMP, OPT_ADDR)

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