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).
Unified · Split
| @@ -83,13 +83,10 @@ enum { · 82 unmodified lines | |||
| 83 | OPT_INDIR, /* *(expr) */ | 83 | OPT_INDIR, /* *(expr) */ |
| 84 | /* composite types */ | 84 | /* composite types */ |
| 85 | OPT_COMPOSITE_FIRST, | 85 | OPT_COMPOSITE_FIRST, |
| 86 | OPT_IM, /* IM8 | IM16 | IM32 | IM64 */ | 86 | OPT_IM, /* IM8 | IM16 | IM32 */ |
| 87 | OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ | 87 | OPT_REG, /* REG8 | REG16 | REG32 | REG64 */ |
| 88 | OPT_REGW, /* REG16 | REG32 | REG64 */ | 88 | OPT_REGW, /* REG16 | REG32 | REG64 */ |
| 89 | OPT_IMW, /* IM16 | IM32 | IM64 */ | 89 | OPT_IMW, /* IM16 | IM32 */ |
| 90 | #ifdef TCC_TARGET_X86_64 | ||
| 91 | OPT_IMNO64, /* IM16 | IM32 */ | ||
| 92 | #endif | ||
| 93 | /* can be ored with any OPT_xxx */ | 90 | /* can be ored with any OPT_xxx */ |
| 94 | OPT_EA = 0x80 | 91 | OPT_EA = 0x80 |
| 95 | }; | 92 | }; |
| @@ -128,12 +125,10 @@ enum { · 32 unmodified lines | |||
| 128 | #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) | 125 | #define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64) |
| 129 | 126 | ||
| 130 | #ifdef TCC_TARGET_X86_64 | 127 | #ifdef TCC_TARGET_X86_64 |
| 131 | # define OP_IM OP_IM64 | ||
| 132 | # define TREG_XAX TREG_RAX | 128 | # define TREG_XAX TREG_RAX |
| 133 | # define TREG_XCX TREG_RCX | 129 | # define TREG_XCX TREG_RCX |
| 134 | # define TREG_XDX TREG_RDX | 130 | # define TREG_XDX TREG_RDX |
| 135 | #else | 131 | #else |
| 136 | # define OP_IM OP_IM32 | ||
| 137 | # define TREG_XAX TREG_EAX | 132 | # define TREG_XAX TREG_EAX |
| 138 | # define TREG_XCX TREG_ECX | 133 | # define TREG_XCX TREG_ECX |
| 139 | # define TREG_XDX TREG_EDX | 134 | # define TREG_XDX TREG_EDX |
| @@ -347,7 +342,7 @@ static void parse_operand(TCCState *s1, Operand *op) · 207 unmodified lines | |||
| 347 | /* constant value */ | 342 | /* constant value */ |
| 348 | next(); | 343 | next(); |
| 349 | asm_expr(s1, &e); | 344 | asm_expr(s1, &e); |
| 350 | op->type = OP_IM; | 345 | op->type = OP_IM32; |
| 351 | op->e.v = e.v; | 346 | op->e.v = e.v; |
| 352 | op->e.sym = e.sym; | 347 | op->e.sym = e.sym; |
| 353 | if (!op->e.sym) { | 348 | if (!op->e.sym) { |
| @@ -358,8 +353,8 @@ static void parse_operand(TCCState *s1, Operand *op) · 4 unmodified lines | |||
| 358 | if (op->e.v == (uint16_t)op->e.v) | 353 | if (op->e.v == (uint16_t)op->e.v) |
| 359 | op->type |= OP_IM16; | 354 | op->type |= OP_IM16; |
| 360 | #ifdef TCC_TARGET_X86_64 | 355 | #ifdef TCC_TARGET_X86_64 |
| 361 | if (op->e.v == (uint32_t)op->e.v) | 356 | if (op->e.v != (uint32_t)op->e.v) |
| 362 | op->type |= OP_IM32; | 357 | op->type = OP_IM64; |
| 363 | #endif | 358 | #endif |
| 364 | } | 359 | } |
| 365 | } else { | 360 | } else { |
| @@ -587,6 +582,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 221 unmodified lines | |||
| 587 | } | 582 | } |
| 588 | if (pa->nb_ops != nb_ops) | 583 | if (pa->nb_ops != nb_ops) |
| 589 | continue; | 584 | 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 | ||
| 590 | /* now decode and check each operand */ | 593 | /* now decode and check each operand */ |
| 591 | alltypes = 0; | 594 | alltypes = 0; |
| 592 | for(i = 0; i < nb_ops; i++) { | 595 | for(i = 0; i < nb_ops; i++) { |
| @@ -595,7 +598,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 2 unmodified lines | |||
| 595 | op2 = op1 & 0x1f; | 598 | op2 = op1 & 0x1f; |
| 596 | switch(op2) { | 599 | switch(op2) { |
| 597 | case OPT_IM: | 600 | case OPT_IM: |
| 598 | v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64; | 601 | v = OP_IM8 | OP_IM16 | OP_IM32; |
| 599 | break; | 602 | break; |
| 600 | case OPT_REG: | 603 | case OPT_REG: |
| 601 | v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64; | 604 | 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 | |||
| 604 | v = OP_REG16 | OP_REG32 | OP_REG64; | 607 | v = OP_REG16 | OP_REG32 | OP_REG64; |
| 605 | break; | 608 | break; |
| 606 | case OPT_IMW: | 609 | case OPT_IMW: |
| 607 | v = OP_IM16 | OP_IM32 | OP_IM64; | ||
| 608 | break; | ||
| 609 | #ifdef TCC_TARGET_X86_64 | ||
| 610 | case OPT_IMNO64: | ||
| 611 | v = OP_IM16 | OP_IM32; | 610 | v = OP_IM16 | OP_IM32; |
| 612 | break; | 611 | break; |
| 613 | #endif | ||
| 614 | default: | 612 | default: |
| 615 | v = 1 << op2; | 613 | v = 1 << op2; |
| 616 | break; | 614 | break; |
| @@ -647,7 +645,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 30 unmodified lines | |||
| 647 | #ifdef TCC_TARGET_X86_64 | 645 | #ifdef TCC_TARGET_X86_64 |
| 648 | /* XXX the autosize should rather be zero, to not have to adjust this | 646 | /* XXX the autosize should rather be zero, to not have to adjust this |
| 649 | all the time. */ | 647 | all the time. */ |
| 650 | if ((pa->instr_type & OPC_WLQ) != OPC_WLQ) | 648 | if ((pa->instr_type & OPC_BWLQ) == OPC_B) |
| 651 | autosize = NBWLX-2; | 649 | autosize = NBWLX-2; |
| 652 | #endif | 650 | #endif |
| 653 | if (s == autosize) { | 651 | if (s == autosize) { |
| @@ -657,7 +655,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode) · 3 unmodified lines | |||
| 657 | } | 655 | } |
| 658 | if (s == autosize) { | 656 | if (s == autosize) { |
| 659 | if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) && | 657 | 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))) |
| 661 | s = 2; | 659 | s = 2; |
| 662 | else | 660 | else |
| 663 | tcc_error("cannot infer opcode suffix"); | 661 | tcc_error("cannot infer opcode suffix"); |
| @@ -610,7 +610,7 @@ typedef struct CachedInclude { · 609 unmodified lines | |||
| 610 | 610 | ||
| 611 | #ifdef CONFIG_TCC_ASM | 611 | #ifdef CONFIG_TCC_ASM |
| 612 | typedef struct ExprValue { | 612 | typedef struct ExprValue { |
| 613 | uint32_t v; | 613 | uint64_t v; |
| 614 | Sym *sym; | 614 | Sym *sym; |
| 615 | } ExprValue; | 615 | } ExprValue; |
| 616 | 616 | ||
| @@ -41,7 +41,8 @@ static Sym sym_dot; · 40 unmodified lines | |||
| 41 | static void asm_expr_unary(TCCState *s1, ExprValue *pe) | 41 | static void asm_expr_unary(TCCState *s1, ExprValue *pe) |
| 42 | { | 42 | { |
| 43 | Sym *sym; | 43 | Sym *sym; |
| 44 | int op, n, label; | 44 | int op, label; |
| 45 | long n; | ||
| 45 | const char *p; | 46 | const char *p; |
| 46 | 47 | ||
| 47 | switch(tok) { | 48 | switch(tok) { |
| @@ -46,6 +46,16 @@ movl %eax, 0x100(%ebx,%edx,2) · 45 unmodified lines | |||
| 46 | movl 0x100(%ebx,%edx,2), %edx | 46 | movl 0x100(%ebx,%edx,2), %edx |
| 47 | movw %ax, 0x100(%ebx,%edx,2) | 47 | movw %ax, 0x100(%ebx,%edx,2) |
| 48 | 48 | ||
| 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 | |||
| 49 | mov %eax, 0x12(,%edx,2) | 59 | mov %eax, 0x12(,%edx,2) |
| 50 | 60 | ||
| 51 | #ifdef __i386__ | 61 | #ifdef __i386__ |
| @@ -97,7 +97,13 @@ ALT(DEF_ASM_OP2(movb, 0xa0, 0, OPC_BWLQ, OPT_ADDR, OPT_EAX)) · 96 unmodified lines | |||
| 97 | ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLQ, OPT_EAX, OPT_ADDR)) */ | 97 | ALT(DEF_ASM_OP2(movb, 0xa2, 0, OPC_BWLQ, OPT_EAX, OPT_ADDR)) */ |
| 98 | ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) | 98 | ALT(DEF_ASM_OP2(movb, 0x88, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) |
| 99 | ALT(DEF_ASM_OP2(movb, 0x8a, 0, OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG)) | 99 | 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. */ | ||
| 100 | ALT(DEF_ASM_OP2(movb, 0xb0, 0, OPC_REG | OPC_BWLQ, OPT_IM, OPT_REG)) | 104 | 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)) | ||
| 101 | ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_REG | OPT_EA)) | 107 | ALT(DEF_ASM_OP2(movb, 0xc6, 0, OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_REG | OPT_EA)) |
| 102 | 108 | ||
| 103 | ALT(DEF_ASM_OP2(movw, 0x8c, 0, OPC_MODRM | OPC_WLQ, OPT_SEG, OPT_EA | OPT_REG)) | 109 | 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 | |||
| 156 | /* arith */ | 162 | /* arith */ |
| 157 | ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ | 163 | ALT(DEF_ASM_OP2(addb, 0x00, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) /* XXX: use D bit ? */ |
| 158 | ALT(DEF_ASM_OP2(addb, 0x02, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG)) | 164 | 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)) | 165 | ALT(DEF_ASM_OP2(addb, 0x04, 0, OPC_ARITH | OPC_BWLQ, OPT_IM, OPT_EAX)) |
| 160 | ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_IMNO64, OPT_EA | OPT_REG)) | 166 | ALT(DEF_ASM_OP2(addb, 0x80, 0, OPC_ARITH | OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_EA | OPT_REG)) |
| 161 | ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLQ, OPT_IM8S, OPT_EA | OPT_REG)) | 167 | ALT(DEF_ASM_OP2(addw, 0x83, 0, OPC_ARITH | OPC_MODRM | OPC_WLQ, OPT_IM8S, OPT_EA | OPT_REG)) |
| 162 | 168 | ||
| 163 | ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) | 169 | ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLQ, OPT_REG, OPT_EA | OPT_REG)) |
| 164 | ALT(DEF_ASM_OP2(testb, 0x84, 0, OPC_MODRM | OPC_BWLQ, OPT_EA | OPT_REG, OPT_REG)) | 170 | 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)) | 171 | ALT(DEF_ASM_OP2(testb, 0xa8, 0, OPC_BWLQ, OPT_IM, OPT_EAX)) |
| 166 | ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLQ, OPT_IMNO64, OPT_EA | OPT_REG)) | 172 | ALT(DEF_ASM_OP2(testb, 0xf6, 0, OPC_MODRM | OPC_BWLQ, OPT_IM, OPT_EA | OPT_REG)) |
| 167 | 173 | ||
| 168 | ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA)) | 174 | ALT(DEF_ASM_OP1(incb, 0xfe, 0, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA)) |
| 169 | ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA)) | 175 | ALT(DEF_ASM_OP1(decb, 0xfe, 1, OPC_MODRM | OPC_BWLQ, OPT_REG | OPT_EA)) |