{
Label label = (Label) o1;
boolean isShortJump = (code.ordinal() >= INST_J_SHORT.ordinal() && code.ordinal() <= INST_JMP_SHORT.ordinal());
final HINT hint = o2.isImm() ? HINT.valueOf((int) ((Immediate) o2).value()) : HINT.HINT_NONE;
// Emit jump hint if configured for that.
if (hint == HINT_TAKEN || hint == HINT_NOT_TAKEN
&& (_properties & (1 << PROPERTY_X86_JCC_HINTS)) != 0)
{
_emitByte(hint.value());
}
if (label.isBound())
{
final int rel8_size = 2;
final int rel32_size = 6;
final int offs = label.position() - offset();
assert(offs <= 0);
if (isInt8(offs - rel8_size))
{
_emitByte(0x70 | (id.opCode1 & 0xff));
_emitByte((byte) (offs - rel8_size));
}
else
{
if (isShortJump && _logger != null)
{
_logger.log("; WARNING: Emitting long conditional jump, but short jump instruction forced!");
}
_emitByte(0x0F);
_emitByte(0x80 | (id.opCode1 & 0xff));
_emitInt32((int) (offs - rel32_size));
}
}
else
{
if (isShortJump)
{
_emitByte(0x70 | (id.opCode1 & 0xff));
_emitDisplacement(label, -1, 1);
}
else
{
_emitByte(0x0F);
_emitByte(0x80 | (id.opCode1 & 0xff));
_emitDisplacement(label, -4, 4);
}
}
return;
}
break;
}
case I_JMP:
{
if (o1.isRegMem())
{
final Operand dst = o1;
_emitX86RM(0xFF,
false,
false, 4, dst,
0);
return;
}
if (o1.isImm())
{
final Immediate imm = (Immediate) o1;
_emitByte(0xE9);
_emitJmpOrCallReloc(I_JMP, imm.value());
return;
}
if (o1.isLabel())
{
Label label = (Label) o1;
boolean isShortJump = (code == INST_JMP_SHORT);
if (label.isBound())
{
final int rel8_size = 2;
final int rel32_size = 5;
final int offs = label.position() - offset();
if (isInt8(offs - rel8_size))
{
_emitByte(0xEB);
_emitByte((byte) (offs - rel8_size));
}
else
{
if (isShortJump && _logger != null)
{
_logger.log("; WARNING: Emitting long jump, but short jump instruction forced!");
}
_emitByte(0xE9);
_emitInt32((int)(offs - rel32_size));
}
}
else
{
if (isShortJump)
{
_emitByte(0xEB);
_emitDisplacement(label, -1, 1);
}
else
{
_emitByte(0xE9);
_emitDisplacement(label, -4, 4);
}
}
return;
}
break;
}
case I_LEA:
{
if (o1.isReg() && o2.isMem())
{
final Register dst = (Register) o1;
final Mem src = (Mem) o2;
_emitX86RM(0x8D,
dst.isRegType(REG_GPW),
dst.isRegType(REG_GPQ), dst.code(), src,
0);
return;
}
break;
}
case I_M:
{
if (o1.isMem())
{
_emitX86RM(id.opCode1, false, (byte) id.opCode2, id.opCodeR, (Mem) o1, 0);
return;
}
break;
}
case I_MOV:
{
final Operand dst = o1;
final Operand src = o2;
switch (dst.op() << 4 | src.op())
{
// Reg <- Reg/Mem
case (OP_REG << 4) | OP_REG:
{
assert(src.isRegType(REG_GPB) || src.isRegType(REG_GPW) ||
src.isRegType(REG_GPD) || src.isRegType(REG_GPQ));
// ... fall through ...
}
case (OP_REG << 4) | OP_MEM:
{
assert(dst.isRegType(REG_GPB) || dst.isRegType(REG_GPW) ||
dst.isRegType(REG_GPD) || dst.isRegType(REG_GPQ));
_emitX86RM(0x0000008A + intValue(!dst.isRegType(REG_GPB)),
dst.isRegType(REG_GPW),
dst.isRegType(REG_GPQ),
((Register) dst).code(),
src,
0);
return;
}
// Reg <- Imm
case (OP_REG << 4) | OP_IMM:
{
final Immediate isrc = (Immediate) o2;
// in 64 bit mode immediate can be 8 byte long!
int immSize = dst.size();
// Optimize instruction size by using 32 bit immediate if value can
// fit to it
if (is64() && immSize == 8 && isInt32(isrc.value()) && isrc.relocMode() == RELOC_NONE)
{
_emitX86RM(0xC7,
dst.isRegType(REG_GPW),
dst.isRegType(REG_GPQ),
0,
dst,
0);
immSize = 4;
}
else
{
_emitX86Inl((dst.size() == 1 ? 0xB0 : 0xB8),
dst.isRegType(REG_GPW),
dst.isRegType(REG_GPQ),
((Register) dst).code());
}
_emitImmediate(isrc, immSize);
return;
}
// Mem <- Reg
case (OP_MEM << 4) | OP_REG:
{
assert(src.isRegType(REG_GPB) || src.isRegType(REG_GPW) ||
src.isRegType(REG_GPD) || src.isRegType(REG_GPQ));
_emitX86RM(0x88 + intValue(!src.isRegType(REG_GPB)),
src.isRegType(REG_GPW),
src.isRegType(REG_GPQ),
((Register) src).code(),
dst,
0);
return;
}
// Mem <- Imm
case (OP_MEM << 4) | OP_IMM:
{
int immSize = dst.size() <= 4 ? dst.size() : 4;
_emitX86RM(0xC6 + intValue(dst.size() != 1),
dst.size() == 2,
dst.size() == 8,
0,
dst,
immSize);
_emitImmediate((Immediate) src,
immSize);
return;
}
}
break;
}
case I_MOV_PTR:
{
if ((o1.isReg() && o2.isImm()) || (o1.isImm() && o2.isReg()))
{
boolean reverse = o1.op() == OP_REG;
int opCode = !reverse ? 0xA0 : 0xA2;
final Register reg = (Register)(!reverse ? o1 : o2);
final Immediate imm = (Immediate)(!reverse ? o2 : o1);
if (reg.index() != 0) throw new IllegalStateException("reg.index() != 0");
if (reg.isRegType(REG_GPW)) _emitByte(0x66);
if (is64()) {
_emitRexR(reg.size() == 8, 0, 0);
}
_emitByte(opCode + intValue(reg.size() != 1));
_emitImmediate(imm, is64() ? 8 : 4);
return;
}
break;
}
case I_MOVSX_MOVZX:
{
if (o1.isReg() && o2.isRegMem())
{
final Register dst = (Register)(o1);
final Operand src = (o2);
if (dst.isRegType(REG_GPB)) throw new IllegalArgumentException("not gpb");
if (src.size() != 1 && src.size() != 2) throw new IllegalArgumentException("src.size !=1 && src.size != 2");
if (src.size() == 2 && dst.isRegType(REG_GPW)) throw new IllegalArgumentException("not gpw");
_emitX86RM(id.opCode1 + intValue(src.size() != 1),
dst.isRegType(REG_GPW),
dst.isRegType(REG_GPQ),
dst.code(),
src,
0);
return;
}
break;
}
case I_MOVSXD:
{
if (!is64()) {
throw new IllegalStateException("illegal instruction");
}
if (o1.isReg() && o2.isRegMem())
{
final Register dst = (Register)(o1);
final Operand src = (o2);
_emitX86RM(0x00000063,
false,
1, dst.code(), src,
0);
return;
}
break;
}
case I_PUSH:
{
// This section is only for immediates, memory/register operands are handled in I_POP.
if (o1.isImm())
{
final Immediate imm = (Immediate)(o1);
if (isInt8(imm.value()) && imm.relocMode() == RELOC_NONE)
{
_emitByte(0x6A);
_emitImmediate(imm, 1);
}
else
{
_emitByte(0x68);
_emitImmediate(imm, 4);
}
return;
}
// ... goto I_POP ...
}
case I_POP:
{
if (o1.isReg())
{
assert(o1.isRegType(REG_GPW) || o1.isRegType(is64() ? REG_GPQ : REG_GPD));
_emitX86Inl(id.opCode1, o1.isRegType(REG_GPW), 0, ((Register) o1).code());
return;
}
if (o1.isMem())
{
_emitX86RM(id.opCode2, o1.size() == 2, 0, id.opCodeR, (o1), 0);
return;
}
break;
}
case I_R_RM:
{
if (o1.isReg() && o2.isRegMem())
{
final Register dst = (Register)(o1);
assert(dst.type() != REG_GPB);
final Operand src = (o2);
_emitX86RM(id.opCode1,
dst.type() == REG_GPW,
dst.type() == REG_GPQ, dst.code(), src,
0);
return;
}
break;
}
case I_RM_B:
{
if (o1.isRegMem())
{
final Operand op = (o1);
_emitX86RM(id.opCode1, false, false, 0, op, 0);
return;
}
break;
}
case I_RM:
{
if (o1.isRegMem())
{
final Operand op = (o1);
_emitX86RM(id.opCode1 + intValue(op.size() != 1),
op.size() == 2,
op.size() == 8, id.opCodeR, op,
0);
return;
}
break;
}
case I_RM_R:
{
if (o1.isRegMem() && o2.isReg())
{
final Operand dst = (o1);
final Register src = (Register)(o2);
_emitX86RM(id.opCode1 + intValue(src.type() != REG_GPB),
src.type() == REG_GPW,
src.type() == REG_GPQ, src.code(), dst,
0);
return;
}
break;
}
case I_RET:
{
if (o1.isNone())
{
_emitByte(0xC3);
return;
}
else if (o1.isImm())
{
final Immediate imm = (Immediate)(o1);
assert(isUInt16(imm.value()));
if (imm.value() == 0 && imm.relocMode() == RELOC_NONE)
{
_emitByte(0xC3);
}
else
{
_emitByte(0xC2);
_emitImmediate(imm, 2);
}
return;
}
break;
}
case I_ROT:
{
if (o1.isRegMem() && (o2.isRegCode(REG_CL) || o2.isImm()))
{
// generate opcode. For these operations is base 0xC0 or 0xD0.
boolean useImm8 = (o2.isImm() &&
(((Immediate) o2).value() != 1 ||
((Immediate) o2).relocMode() != RELOC_NONE));
int opCode = useImm8 ? 0xC0 : 0xD0;
// size and operand type modifies the opcode
if (o1.size() != 1) opCode |= 0x01;
if (o2.op() == OP_REG) opCode |= 0x02;
_emitX86RM(opCode,
o1.size() == 2,
o1.size() == 8,
id.opCodeR, (o1),
intValue(useImm8));
if (useImm8)
_emitImmediate((Immediate)(o2), 1);
return;
}
break;
}
case I_SHLD_SHRD:
{
if (o1.isRegMem() && o2.isReg() && (o3.isImm() || (o3.isReg() && o3.isRegCode(REG_CL))))
{
final Operand dst = (o1);
final Register src1 = (Register)(o2);
final Operand src2 = (o3);
assert(dst.size() == src1.size());
_emitX86RM(id.opCode1 + intValue(src2.isReg()),
src1.isRegType(REG_GPW),
src1.isRegType(REG_GPQ),
src1.code(), dst,
intValue(src2.isImm()));
if (src2.isImm())
_emitImmediate((Immediate)(src2), 1);
return;
}
break;
}
case I_TEST:
{
if (o1.isRegMem() && o2.isReg())
{
assert(o1.size() == o2.size());
_emitX86RM(0x84 + intValue(o2.size() != 1),
o2.size() == 2, o2.size() == 8,
((BaseReg) o2).code(),
(o1),
0);
return;
}
if (o1.isRegIndex(0) && o2.isImm())
{
int immSize = o1.size() <= 4 ? o1.size() : 4;
if (o1.size() == 2) _emitByte(0x66); // 16 bit
if (is64()) {
_emitRexRM(o1.size() == 8, 0, (o1));
}
_emitByte(0xA8 + intValue(o1.size() != 1));
_emitImmediate((Immediate)(o2), immSize);
return;
}
if (o1.isRegMem() && o2.isImm())
{
int immSize = o1.size() <= 4 ? o1.size() : 4;
if (o1.size() == 2) _emitByte(0x66); // 16 bit
_emitSegmentPrefix((o1)); // segment prefix
if (is64()) _emitRexRM(o1.size() == 8, 0, (o1));
_emitByte(0xF6 + intValue(o1.size() != 1));
_emitModRM(0, (o1), immSize);
_emitImmediate((Immediate)(o2), immSize);
return;
}
break;
}
case I_XCHG:
{
if (o1.isRegMem() && o2.isReg())
{
final Operand dst = (o1);
final Register src = (Register)(o2);
if (src.isRegType(REG_GPW)) _emitByte(0x66); // 16 bit
_emitSegmentPrefix(dst); // segment prefix
if (is64()) _emitRexRM(src.isRegType(REG_GPQ), src.code(), dst);
// Special opcode for index 0 registers (AX, EAX, RAX vs register)
if ((dst.op() == OP_REG && dst.size() > 1) &&
(((Register) dst).code() == 0 ||
((Register) src).code() == 0))
{
int index = ((Register) dst).code() | src.code();
_emitByte((byte) (0x90 + index));
return;
}
_emitByte(0x86 + intValue(!src.isRegType(REG_GPB)));
_emitModRM(src.code(), dst, 0);
return;
}
break;
}
case I_MOVBE:
{
if (o1.isReg() && o2.isMem())
{
_emitX86RM(0x000F38F0,
o1.isRegType(REG_GPW),
o1.isRegType(REG_GPQ),
((Register) o1).code(),
(Mem)(o2),
0);
return;
}
if (o1.isMem() && o2.isReg())
{
_emitX86RM(0x000F38F1,
o2.isRegType(REG_GPW),
o2.isRegType(REG_GPQ),
((Register) o2).code(),
(Mem)(o1),
0);
return;
}
break;
}
case I_X87_FPU:
{
if (o1.isRegType(REG_X87))
{
int i1 = ((X87Register) o1).index();
int i2 = 0;
if (code != INST_FCOM && code != INST_FCOMP)
{
if (!o2.isRegType(REG_X87)) throw new IllegalArgumentException("not x87 reg");
i2 = ((X87Register) o2).index();
}
else if (i1 != 0 && i2 != 0)
{
throw new IllegalArgumentException("illegal instruction");
}
_emitByte(i1 == 0
? ((id.opCode1 & 0xFF000000) >> 24)
: ((id.opCode1 & 0x00FF0000) >> 16));
_emitByte(i1 == 0
? ((id.opCode1 & 0x0000FF00) >> 8) + i2
: ((id.opCode1 & 0x000000FF) ) + i1);
return;
}
if (o1.isMem() && (o1.size() == 4 || o1.size() == 8) && o2.isNone())
{
final Mem m = (Mem)(o1);
// segment prefix
_emitSegmentPrefix(m);
_emitByte(o1.size() == 4
? ((id.opCode1 & 0xFF000000) >> 24)
: ((id.opCode1 & 0x00FF0000) >> 16));
_emitModM(id.opCodeR, m, 0);
return;
}
break;
}
case I_X87_STI:
{
if (o1.isRegType(REG_X87))
{
int i = ((X87Register) o1).index();
_emitByte(((id.opCode1 & 0x0000FF00) >> 8));
_emitByte(((id.opCode1 & 0x000000FF) + i));
return;
}
break;
}
case I_X87_FSTSW:
{
if (o1.isReg() &&
((BaseReg) o1).type() <= REG_GPQ &&
((BaseReg) o1).index() == 0)
{
_emitOpCode(id.opCode2);
return;
}
if (o1.isMem())
{
_emitX86RM(id.opCode1, false, 0, id.opCodeR, (Mem)(o1), 0);
return;
}
break;
}
case I_X87_MEM_STI:
{
if (o1.isRegType(REG_X87))
{
_emitByte(((id.opCode2 & 0xFF000000) >> 24));
_emitByte(((id.opCode2 & 0x00FF0000) >> 16) +
((X87Register) o1).index());
return;
}
// ... fall through to I_X87_MEM ...
}
case I_X87_MEM:
{
if (!o1.isMem()) throw new IllegalArgumentException("not x87 mem");
final Mem m = (Mem)(o1);
int opCode = 0x00, mod = 0;
if (o1.size() == 2 && (id.o1Flags & O_FM_2) != 0)
{
opCode = ((id.opCode1 & 0xFF000000) >> 24);
mod = id.opCodeR;
}
if (o1.size() == 4 && (id.o1Flags & O_FM_4) != 0)
{
opCode = ((id.opCode1 & 0x00FF0000) >> 16);
mod = id.opCodeR;
}
if (o1.size() == 8 && (id.o1Flags & O_FM_8) != 0)
{
opCode = ((id.opCode1 & 0x0000FF00) >> 8);
mod = ((id.opCode1 & 0x000000FF) );
}
if (opCode != 0)
{
_emitSegmentPrefix(m);
_emitByte(opCode);
_emitModM(mod, m, 0);
return;
}
break;
}
case I_MMU_MOV:
{
assert(id.o1Flags != 0);
assert(id.o2Flags != 0);
// Check parameters (X)MM|GP32_64 <- (X)MM|GP32_64|Mem|Imm
if ((o1.isMem() && (id.o1Flags & O_MEM) == 0) ||
(o1.isRegType(REG_MM ) && (id.o1Flags & O_MM ) == 0) ||
(o1.isRegType(REG_XMM) && (id.o1Flags & O_XMM) == 0) ||
(o1.isRegType(REG_GPD) && (id.o1Flags & O_G32) == 0) ||
(o1.isRegType(REG_GPQ) && (id.o1Flags & O_G64) == 0) ||
(o2.isRegType(REG_MM ) && (id.o2Flags & O_MM ) == 0) ||
(o2.isRegType(REG_XMM) && (id.o2Flags & O_XMM) == 0) ||
(o2.isRegType(REG_GPD) && (id.o2Flags & O_G32) == 0) ||
(o2.isRegType(REG_GPQ) && (id.o2Flags & O_G64) == 0) ||
(o2.isMem() && (id.o2Flags & O_MEM) == 0) )
{
throw new IllegalArgumentException("illegal instruction");
}
// Illegal
if (o1.isMem() && o2.isMem()) throw new IllegalArgumentException("illegal instruction");
int rexw = ((id.o1Flags|id.o2Flags) & O_NOREX) != 0
? 0
: intValue(o1.isRegType(REG_GPQ) || o1.isRegType(REG_GPQ));
// (X)MM|Reg <- (X)MM|Reg
if (o1.isReg() && o2.isReg())
{
_emitMmu(id.opCode1, rexw,
((BaseReg) o1).code(),
(BaseReg)(o2),
0);
return;
}
// (X)MM|Reg <- Mem
if (o1.isReg() && o2.isMem())
{
_emitMmu(id.opCode1, rexw,
((BaseReg) o1).code(),
(Mem)(o2),
0);
return;
}
// Mem <- (X)MM|Reg
if (o1.isMem() && o2.isReg())
{
_emitMmu(id.opCode2, rexw,
((BaseReg) o2).code(),
(Mem)(o1),
0);
return;
}
break;
}
case I_MMU_MOVD:
{
if ((o1.isRegType(REG_MM) || o1.isRegType(REG_XMM)) && (o2.isRegType(REG_GPD) || o2.isMem()))
{
_emitMmu(o1.isRegType(REG_XMM) ? 0x66000F6E : 0x00000F6E, 0,
((BaseReg) o1).code(),
(o2),
0);
return;
}
if ((o1.isRegType(REG_GPD) || o1.isMem()) && (o2.isRegType(REG_MM) || o2.isRegType(REG_XMM)))
{
_emitMmu(o2.isRegType(REG_XMM) ? 0x66000F7E : 0x00000F7E, 0,
((BaseReg) o2).code(),
(o1),
0);
return;
}
break;
}
case I_MMU_MOVQ:
{
if (o1.isRegType(REG_MM) && o2.isRegType(REG_MM))
{
_emitMmu(0x00000F6F, 0,
((MMRegister) o1).code(),
(MMRegister)(o2),
0);
return;
}
if (o1.isRegType(REG_XMM) && o2.isRegType(REG_XMM))
{
_emitMmu(0xF3000F7E, 0,
((XMMRegister) o1).code(),
(XMMRegister)(o2),
0);
return;
}
// Convenience - movdq2q
if (o1.isRegType(REG_MM) && o2.isRegType(REG_XMM))
{
_emitMmu(0xF2000FD6, 0,
((MMRegister) o1).code(),
(XMMRegister)(o2),
0);
return;
}
// Convenience - movq2dq
if (o1.isRegType(REG_XMM) && o2.isRegType(REG_MM))
{
_emitMmu(0xF3000FD6, 0,
((XMMRegister) o1).code(),
(MMRegister)(o2),
0);
return;
}
if (o1.isRegType(REG_MM) && o2.isMem())
{
_emitMmu(0x00000F6F, 0,
((MMRegister) o1).code(),
(Mem)(o2),
0);
return;
}
if (o1.isRegType(REG_XMM) && o2.isMem())
{
_emitMmu(0xF3000F7E, 0,
((XMMRegister) o1).code(),
(Mem)(o2),
0);
return;
}
if (o1.isMem() && o2.isRegType(REG_MM))
{
_emitMmu(0x00000F7F, 0,
((MMRegister) o2).code(),
(Mem)(o1),
0);
return;
}
if (o1.isMem() && o2.isRegType(REG_XMM))
{
_emitMmu(0x66000FD6, 0,
((XMMRegister) o2).code(),
(Mem)(o1),
0);
return;
}
if (is64()) {
if ((o1.isRegType(REG_MM) || o1.isRegType(REG_XMM)) && (o2.isRegType(REG_GPQ) || o2.isMem()))
{
_emitMmu(o1.isRegType(REG_XMM) ? 0x66000F6E : 0x00000F6E, 1,
((BaseReg) o1).code(),
(o2),
0);
return;
}
if ((o1.isRegType(REG_GPQ) || o1.isMem()) && (o2.isRegType(REG_MM) || o2.isRegType(REG_XMM)))
{
_emitMmu(o2.isRegType(REG_XMM) ? 0x66000F7E : 0x00000F7E, 1,
((BaseReg) o2).code(),
(o1),
0);
return;
}
}
break;
}
case I_MMU_PREFETCH:
{
if (o1.isMem() && o2.isImm())
{
final Mem mem = (Mem)(o1);
final Immediate hint = (Immediate)(o2);
_emitMmu(0x00000F18, 0, (int) hint.value(), mem, 0);
return;
}
break;
}