History

x86asm: Add popcnt

as this is the first opcode TCC supports that has a 0xf3 prefix and uses integer registers (not SSE ones) this also needs some shuffling of the prefix code to not generate invalid instructions (the REX prefix _must_ come directly before the main opcode (including 0f prefix), and hence needs to come after the 0xf3 prefix). Also disable some mnemonics in asmtest.S that new GAS doesn't support anymore. The only difference to GAS (in asmtest.S) is now the 'lock negl' instruction which TCC emits as 'lock; negl'. That's fine.

Michael Matz committed 4 years ago

Commit 23095171 parent 98bab416 files · +62 −32Browse files

Unified · Split

6 files
  1. i386-asm.c +38 −25
  2. i386-asm.h +2 −0
  3. i386-tok.h +1 −0
  4. tests/Makefile +1 −1
  5. tests/asmtest.S +18 −6
  6. x86_64-asm.h +2 −0
i386-asm.c+38−25
@@ -682,7 +682,7 @@ static void maybe_print_stats (void) · 681 unmodified lines
682ST_FUNC void asm_opcode(TCCState *s1, int opcode)682ST_FUNC void asm_opcode(TCCState *s1, int opcode)
683{683{
684 const ASMInstr *pa;684 const ASMInstr *pa;
685 int i, modrm_index, modreg_index, reg, v, op1, seg_prefix, pc;685 int i, modrm_index, modreg_index, reg, v, op1, seg_prefix, pc, p;
686 int nb_ops, s;686 int nb_ops, s;
687 Operand ops[MAX_OPERANDS], *pop;687 Operand ops[MAX_OPERANDS], *pop;
688 int op_type[3]; /* decoded op type */688 int op_type[3]; /* decoded op type */
@@ -891,30 +891,6 @@ again: · 202 unmodified lines
891 }891 }
892 }892 }
893 893
894#ifdef TCC_TARGET_X86_64
895 /* Generate addr32 prefix if needed */
896 for(i = 0; i < nb_ops; i++) {
897 if (ops[i].type & OP_EA32) {
898 g(0x67);
899 break;
900 }
901 }
902#endif
903 /* generate data16 prefix if needed */
904 p66 = 0;
905 if (s == 1)
906 p66 = 1;
907 else {
908 /* accepting mmx+sse in all operands --> needs 0x66 to
909 switch to sse mode. Accepting only sse in an operand --> is
910 already SSE insn and needs 0x66/f2/f3 handling. */
911 for (i = 0; i < nb_ops; i++)
912 if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE)
913 && ops[i].type & OP_SSE)
914 p66 = 1;
915 }
916 if (p66)
917 g(0x66);
918#ifdef TCC_TARGET_X86_64894#ifdef TCC_TARGET_X86_64
919 rex64 = 0;895 rex64 = 0;
920 if (pa->instr_type & OPC_48)896 if (pa->instr_type & OPC_48)
@@ -947,8 +923,45 @@ again: · 26 unmodified lines
947 g(0x9b);923 g(0x9b);
948 if (seg_prefix)924 if (seg_prefix)
949 g(seg_prefix);925 g(seg_prefix);
926#ifdef TCC_TARGET_X86_64
927 /* Generate addr32 prefix if needed */
928 for(i = 0; i < nb_ops; i++) {
929 if (ops[i].type & OP_EA32) {
930 g(0x67);
931 break;
932 }
933 }
934#endif
935 /* generate data16 prefix if needed */
936 p66 = 0;
937 if (s == 1)
938 p66 = 1;
939 else {
940 /* accepting mmx+sse in all operands --> needs 0x66 to
941 switch to sse mode. Accepting only sse in an operand --> is
942 already SSE insn and needs 0x66/f2/f3 handling. */
943 for (i = 0; i < nb_ops; i++)
944 if ((op_type[i] & (OP_MMX | OP_SSE)) == (OP_MMX | OP_SSE)
945 && ops[i].type & OP_SSE)
946 p66 = 1;
947 }
948 if (p66)
949 g(0x66);
950 950
951 v = pa->opcode;951 v = pa->opcode;
952 p = v >> 8; /* possibly prefix byte(s) */
953 switch (p) {
954 case 0: break; /* no prefix */
955 case 0x48: break; /* REX, handled elsewhere */
956 case 0x66:
957 case 0x67:
958 case 0xf2:
959 case 0xf3: v = v & 0xff; g(p); break;
960 case 0xd4: case 0xd5: break; /* aam and aad, not prefix, but hardcoded immediate argument "10" */
961 case 0xd8: case 0xd9: case 0xda: case 0xdb: /* x87, no normal prefix */
962 case 0xdc: case 0xdd: case 0xde: case 0xdf: break;
963 default: tcc_error("bad prefix 0x%2x in opcode table", p); break;
964 }
952 if (pa->instr_type & OPC_0F)965 if (pa->instr_type & OPC_0F)
953 v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff);966 v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff);
954 if ((v == 0x69 || v == 0x6b) && nb_ops == 2) {967 if ((v == 0x69 || v == 0x6b) && nb_ops == 2) {
i386-asm.h+2−0
@@ -73,6 +73,8 @@ ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA · 72 unmodified lines
73ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))73ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
74ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))74ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
75 75
76ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
77
76 /* prefixes */78 /* prefixes */
77 DEF_ASM_OP0(wait, 0x9b)79 DEF_ASM_OP0(wait, 0x9b)
78 DEF_ASM_OP0(fwait, 0x9b)80 DEF_ASM_OP0(fwait, 0x9b)
i386-tok.h+1−0
@@ -268,6 +268,7 @@ · 267 unmodified lines
268 DEF_WLX(bts)268 DEF_WLX(bts)
269 DEF_WLX(btr)269 DEF_WLX(btr)
270 DEF_WLX(btc)270 DEF_WLX(btc)
271 DEF_WLX(popcnt)
271 272
272 DEF_WLX(lar)273 DEF_WLX(lar)
273 DEF_WLX(lsl)274 DEF_WLX(lsl)
tests/Makefile+1−1
@@ -220,7 +220,7 @@ ex%: $(TOPSRC)/examples/ex%.c · 219 unmodified lines
220 220
221# tiny assembler testing221# tiny assembler testing
222asmtest.ref: asmtest.S222asmtest.ref: asmtest.S
223 $(CC) -Wa,-W -o asmtest.ref.o -c asmtest.S223 $(CC) -Wa,-W -Wa,-mx86-used-note=no -o asmtest.ref.o -c asmtest.S
224 objdump -D asmtest.ref.o > asmtest.ref224 objdump -D asmtest.ref.o > asmtest.ref
225 225
226ifeq ($(ARCH),arm)226ifeq ($(ARCH),arm)
tests/asmtest.S+18−6
@@ -425,7 +425,7 @@ L3: · 424 unmodified lines
425 425
426 fsubp %st(5)426 fsubp %st(5)
427 fsubp427 fsubp
428 fsubp %st(1), %st428 //fsubp %st(1), %st # not accepted by new GAS anymore
429 429
430 fsubs 0x1000430 fsubs 0x1000
431 fisubs 0x1002431 fisubs 0x1002
@@ -438,7 +438,7 @@ L3: · 6 unmodified lines
438 438
439 fsubrp %st(5)439 fsubrp %st(5)
440 fsubrp440 fsubrp
441 fsubrp %st(1), %st441 //fsubrp %st(1), %st # not accepted by new GAS anymore
442 442
443 fsubrs 0x1000443 fsubrs 0x1000
444 fisubrs 0x1002444 fisubrs 0x1002
@@ -451,7 +451,7 @@ L3: · 6 unmodified lines
451 451
452 fdivp %st(5)452 fdivp %st(5)
453 fdivp453 fdivp
454 fdivp %st(1), %st454 //fdivp %st(1), %st # not accepted by new GAS anymore
455 455
456 fdivs 0x1000456 fdivs 0x1000
457 fidivs 0x1002457 fidivs 0x1002
@@ -745,7 +745,14 @@ int $0x10 · 287 unmodified lines
745 bts %edx, 0x1000745 bts %edx, 0x1000
746 btsl $2, 0x1000746 btsl $2, 0x1000
747 747
748 748 popcnt %ax, %si
749 popcntw %ax, %si
750 popcnt 0x1000, %edx
751 popcntl 0x1000, %edx
752#ifdef __x86_64__
753 popcnt %rbx, %rdi
754 popcntq %rcx, %r8
755#endif
749 756
750#ifdef __i386__757#ifdef __i386__
751 boundl %edx, 0x10000758 boundl %edx, 0x10000
@@ -768,8 +775,13 @@ int $0x10 · 16 unmodified lines
768 775
769 swapgs776 swapgs
770 777
771 str %rdx778 /* Newer gas assemble 'str %rdx' as 'str %edx', based on the observation
772 str %r9779 that the 16bit value of the task register is zero-extended into the
780 destination anyway, and hence storing into %edx is the same as storing
781 into %rdx. TCC doesn't do that micro-optimization, hence just store
782 into the 32bit reg as well. */
783 str %edx
784 str %r9d
773#endif785#endif
774 786
775 lmsw 0x1000787 lmsw 0x1000
x86_64-asm.h+2−0
@@ -73,6 +73,8 @@ ALT(DEF_ASM_OP2(btrw, 0x0fba, 6, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA · 72 unmodified lines
73ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))73ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
74ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))74ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
75 75
76ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
77
76 /* prefixes */78 /* prefixes */
77 DEF_ASM_OP0(lock, 0xf0)79 DEF_ASM_OP0(lock, 0xf0)
78 DEF_ASM_OP0(rep, 0xf3)80 DEF_ASM_OP0(rep, 0xf3)

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