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
682682 ST_FUNC void asm_opcode(TCCState *s1, int opcode)
683683 {
684684 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;
686686 int nb_ops, s;
687687 Operand ops[MAX_OPERANDS], *pop;
688688 int op_type[3]; /* decoded op type */
@@ -891,30 +891,6 @@ again: · 202 unmodified lines
891891 }
892892 }
893893
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);
918894 #ifdef TCC_TARGET_X86_64
919895 rex64 = 0;
920896 if (pa->instr_type & OPC_48)
@@ -947,8 +923,45 @@ again: · 26 unmodified lines
947923 g(0x9b);
948924 if (seg_prefix)
949925 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);
950950
951951 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+ }
952965 if (pa->instr_type & OPC_0F)
953966 v = ((v & ~0xff) << 8) | 0x0f00 | (v & 0xff);
954967 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
7373 ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
7474 ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
7575
76+ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
77+
7678 /* prefixes */
7779 DEF_ASM_OP0(wait, 0x9b)
7880 DEF_ASM_OP0(fwait, 0x9b)
i386-tok.h+1−0
@@ -268,6 +268,7 @@ · 267 unmodified lines
268268 DEF_WLX(bts)
269269 DEF_WLX(btr)
270270 DEF_WLX(btc)
271+ DEF_WLX(popcnt)
271272
272273 DEF_WLX(lar)
273274 DEF_WLX(lsl)
tests/Makefile+1−1
@@ -220,7 +220,7 @@ ex%: $(TOPSRC)/examples/ex%.c · 219 unmodified lines
220220
221221 # tiny assembler testing
222222 asmtest.ref: asmtest.S
223− $(CC) -Wa,-W -o asmtest.ref.o -c asmtest.S
223+ $(CC) -Wa,-W -Wa,-mx86-used-note=no -o asmtest.ref.o -c asmtest.S
224224 objdump -D asmtest.ref.o > asmtest.ref
225225
226226 ifeq ($(ARCH),arm)
tests/asmtest.S+18−6
@@ -425,7 +425,7 @@ L3: · 424 unmodified lines
425425
426426 fsubp %st(5)
427427 fsubp
428− fsubp %st(1), %st
428+ //fsubp %st(1), %st # not accepted by new GAS anymore
429429
430430 fsubs 0x1000
431431 fisubs 0x1002
@@ -438,7 +438,7 @@ L3: · 6 unmodified lines
438438
439439 fsubrp %st(5)
440440 fsubrp
441− fsubrp %st(1), %st
441+ //fsubrp %st(1), %st # not accepted by new GAS anymore
442442
443443 fsubrs 0x1000
444444 fisubrs 0x1002
@@ -451,7 +451,7 @@ L3: · 6 unmodified lines
451451
452452 fdivp %st(5)
453453 fdivp
454− fdivp %st(1), %st
454+ //fdivp %st(1), %st # not accepted by new GAS anymore
455455
456456 fdivs 0x1000
457457 fidivs 0x1002
@@ -745,7 +745,14 @@ int $0x10 · 287 unmodified lines
745745 bts %edx, 0x1000
746746 btsl $2, 0x1000
747747
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
749756
750757 #ifdef __i386__
751758 boundl %edx, 0x10000
@@ -768,8 +775,13 @@ int $0x10 · 16 unmodified lines
768775
769776 swapgs
770777
771− str %rdx
772− str %r9
778+ /* Newer gas assemble 'str %rdx' as 'str %edx', based on the observation
779+ 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
773785 #endif
774786
775787 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
7373 ALT(DEF_ASM_OP2(btcw, 0x0fbb, 0, OPC_MODRM | OPC_WLX, OPT_REGW, OPT_REGW | OPT_EA))
7474 ALT(DEF_ASM_OP2(btcw, 0x0fba, 7, OPC_MODRM | OPC_WLX, OPT_IM8, OPT_REGW | OPT_EA))
7575
76+ALT(DEF_ASM_OP2(popcntw, 0xf30fb8, 0, OPC_MODRM | OPC_WLX, OPT_REGW | OPT_EA, OPT_REGW))
77+
7678 /* prefixes */
7779 DEF_ASM_OP0(lock, 0xf0)
7880 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