x86-64-asm: Clean up 64bit immediate support

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).
This commit is contained in:
Michael Matz
2016-05-11 23:47:02 +02:00
parent f3cee9ceff
commit b9f01dffc6
5 changed files with 39 additions and 24 deletions

View File

@ -83,13 +83,10 @@ enum {
OPT_INDIR, /* *(expr) */
/* composite types */
OPT_COMPOSITE_FIRST,
OPT_IM, /* IM8 | IM16 | IM32 | IM64 */
OPT_IM, /* IM8 | IM16 | IM32 */
OPT_REG, /* REG8 | REG16 | REG32 | REG64 */
OPT_REGW, /* REG16 | REG32 | REG64 */
OPT_IMW, /* IM16 | IM32 | IM64 */
#ifdef TCC_TARGET_X86_64
OPT_IMNO64, /* IM16 | IM32 */
#endif
OPT_IMW, /* IM16 | IM32 */
/* can be ored with any OPT_xxx */
OPT_EA = 0x80
};
@ -128,12 +125,10 @@ enum {
#define OP_REG (OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64)
#ifdef TCC_TARGET_X86_64
# define OP_IM OP_IM64
# define TREG_XAX TREG_RAX
# define TREG_XCX TREG_RCX
# define TREG_XDX TREG_RDX
#else
# define OP_IM OP_IM32
# define TREG_XAX TREG_EAX
# define TREG_XCX TREG_ECX
# define TREG_XDX TREG_EDX
@ -347,7 +342,7 @@ static void parse_operand(TCCState *s1, Operand *op)
/* constant value */
next();
asm_expr(s1, &e);
op->type = OP_IM;
op->type = OP_IM32;
op->e.v = e.v;
op->e.sym = e.sym;
if (!op->e.sym) {
@ -358,8 +353,8 @@ static void parse_operand(TCCState *s1, Operand *op)
if (op->e.v == (uint16_t)op->e.v)
op->type |= OP_IM16;
#ifdef TCC_TARGET_X86_64
if (op->e.v == (uint32_t)op->e.v)
op->type |= OP_IM32;
if (op->e.v != (uint32_t)op->e.v)
op->type = OP_IM64;
#endif
}
} else {
@ -587,6 +582,14 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
}
if (pa->nb_ops != nb_ops)
continue;
#ifdef TCC_TARGET_X86_64
/* Special case for moves. Selecting the IM64->REG64 form
should only be done if we really have an >32bit imm64, and that
is hardcoded. Ignore it here. */
if (pa->opcode == 0xb0 && ops[0].type != OP_IM64
&& ops[1].type == OP_REG64)
continue;
#endif
/* now decode and check each operand */
alltypes = 0;
for(i = 0; i < nb_ops; i++) {
@ -595,7 +598,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
op2 = op1 & 0x1f;
switch(op2) {
case OPT_IM:
v = OP_IM8 | OP_IM16 | OP_IM32 | OP_IM64;
v = OP_IM8 | OP_IM16 | OP_IM32;
break;
case OPT_REG:
v = OP_REG8 | OP_REG16 | OP_REG32 | OP_REG64;
@ -604,13 +607,8 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
v = OP_REG16 | OP_REG32 | OP_REG64;
break;
case OPT_IMW:
v = OP_IM16 | OP_IM32 | OP_IM64;
break;
#ifdef TCC_TARGET_X86_64
case OPT_IMNO64:
v = OP_IM16 | OP_IM32;
break;
#endif
default:
v = 1 << op2;
break;
@ -647,7 +645,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
#ifdef TCC_TARGET_X86_64
/* XXX the autosize should rather be zero, to not have to adjust this
all the time. */
if ((pa->instr_type & OPC_WLQ) != OPC_WLQ)
if ((pa->instr_type & OPC_BWLQ) == OPC_B)
autosize = NBWLX-2;
#endif
if (s == autosize) {
@ -657,7 +655,7 @@ ST_FUNC void asm_opcode(TCCState *s1, int opcode)
}
if (s == autosize) {
if ((opcode == TOK_ASM_push || opcode == TOK_ASM_pop) &&
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32 | OP_IM64)))
(ops[0].type & (OP_SEG | OP_IM8S | OP_IM32)))
s = 2;
else
tcc_error("cannot infer opcode suffix");