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