void Assembler::cmp(Indirect mem, Immediate imm) { int64_t val = imm.val; assert((-1L << 31) <= val && val < (1L << 31) - 1); int src_idx = mem.base.regnum; int rex = REX_W; if (src_idx >= 8) { rex |= REX_B; src_idx -= 8; } assert(src_idx >= 0 && src_idx < 8); emitRex(rex); emitByte(0x81); assert(-0x80 <= mem.offset && mem.offset < 0x80); if (mem.offset == 0) { emitModRM(0b00, 7, src_idx); } else { emitModRM(0b01, 7, src_idx); emitByte(mem.offset); } emitInt(val, 4); }
void Assembler::cmp(Indirect mem, Register reg) { int mem_idx = mem.base.regnum; int reg_idx = reg.regnum; int rex = REX_W; if (mem_idx >= 8) { rex |= REX_B; mem_idx -= 8; } if (reg_idx >= 8) { rex |= REX_R; reg_idx -= 8; } assert(mem_idx >= 0 && mem_idx < 8); assert(reg_idx >= 0 && reg_idx < 8); emitRex(rex); emitByte(0x3B); assert(-0x80 <= mem.offset && mem.offset < 0x80); if (mem.offset == 0) { emitModRM(0b00, reg_idx, mem_idx); } else { emitModRM(0b01, reg_idx, mem_idx); emitByte(mem.offset); } }
void Assembler::emitArith(Immediate imm, Register r, int opcode, MovType type) { // assert(r != RSP && "This breaks unwinding, please don't use."); int64_t amount = imm.val; RELEASE_ASSERT(fitsInto<int32_t>(amount), ""); assert(0 <= opcode && opcode < 8); assert(type == MovType::Q || type == MovType::L); int rex = type == MovType::Q ? REX_W : 0; int reg_idx = r.regnum; if (reg_idx >= 8) { rex |= REX_B; reg_idx -= 8; } if (rex) emitRex(rex); if (-0x80 <= amount && amount < 0x80) { emitByte(0x83); emitModRM(0b11, opcode, reg_idx); emitByte(amount); } else { emitByte(0x81); emitModRM(0b11, opcode, reg_idx); emitInt(amount, 4); } }
void Assembler::incq(Indirect mem) { int src_idx = mem.base.regnum; int rex = REX_W; if (src_idx >= 8) { rex |= REX_B; src_idx -= 8; } assert(src_idx >= 0 && src_idx < 8); bool needssib = (src_idx == 0b100); if (rex) emitRex(rex); emitByte(0xff); assert(-0x80 <= mem.offset && mem.offset < 0x80); if (mem.offset == 0) { emitModRM(0b00, 0, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); } else { emitModRM(0b01, 0, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); emitByte(mem.offset); } }
void Assembler::emitArith(Immediate imm, Register r, int opcode) { // assert(r != RSP && "This breaks unwinding, please don't use."); int64_t amount = imm.val; RELEASE_ASSERT((-1L << 31) <= amount && amount < (1L << 31) - 1, ""); assert(0 <= opcode && opcode < 8); int rex = REX_W; int reg_idx = r.regnum; if (reg_idx >= 8) { rex |= REX_B; reg_idx -= 8; } emitRex(rex); if (-0x80 <= amount && amount < 0x80) { emitByte(0x83); emitModRM(0b11, opcode, reg_idx); emitByte(amount); } else { emitByte(0x81); emitModRM(0b11, opcode, reg_idx); emitInt(amount, 4); } }
void Assembler::mov(Register src, Indirect dest) { int rex = REX_W; int src_idx = src.regnum; int dest_idx = dest.base.regnum; assert(src_idx != dest_idx && "while valid this is almost certainly a register allocator bug"); if (src_idx >= 8) { rex |= REX_R; src_idx -= 8; } if (dest_idx >= 8) { rex |= REX_B; dest_idx -= 8; } emitRex(rex); emitByte(0x89); bool needssib = (dest_idx == 0b100); int mode = getModeFromOffset(dest.offset); emitModRM(mode, src_idx, dest_idx); if (needssib) emitSIB(0b00, 0b100, dest_idx); if (mode == 0b01) { emitByte(dest.offset); } else if (mode == 0b10) { emitInt(dest.offset, 4); } }
void Assembler::movq(Immediate src, Indirect dest) { int64_t src_val = src.val; assert((-1L << 31) <= src_val && src_val < (1L << 31) - 1); int rex = REX_W; int dest_idx = dest.base.regnum; if (dest_idx >= 8) { rex |= REX_B; dest_idx -= 8; } emitRex(rex); emitByte(0xc7); bool needssib = (dest_idx == 0b100); int mode = getModeFromOffset(dest.offset); emitModRM(mode, 0, dest_idx); if (needssib) emitSIB(0b00, 0b100, dest_idx); if (mode == 0b01) { emitByte(dest.offset); } else if (mode == 0b10) { emitInt(dest.offset, 4); } emitInt(src_val, 4); }
void Assembler::movsd(XMMRegister src, Indirect dest) { int rex = 0; int src_idx = src.regnum; int dest_idx = dest.base.regnum; if (src_idx >= 8) { rex |= REX_R; src_idx -= 8; } if (dest_idx >= 8) { trap(); rex |= REX_B; dest_idx -= 8; } emitByte(0xf2); if (rex) emitRex(rex); emitByte(0x0f); emitByte(0x11); bool needssib = (dest_idx == 0b100); int mode = getModeFromOffset(dest.offset); emitModRM(mode, src_idx, dest_idx); if (needssib) emitSIB(0b00, 0b100, dest_idx); if (mode == 0b01) { emitByte(dest.offset); } else if (mode == 0b10) { emitInt(dest.offset, 4); } }
void Assembler::jmp(Indirect dest) { int reg_idx = dest.base.regnum; assert(reg_idx >= 0 && reg_idx < 8 && "not yet implemented"); emitByte(0xFF); if (dest.offset == 0) { emitModRM(0b00, 0b100, reg_idx); } else if (-0x80 <= dest.offset && dest.offset < 0x80) { emitModRM(0b01, 0b100, reg_idx); emitByte(dest.offset); } else { assert((-1L << 31) <= dest.offset && dest.offset < (1L << 31) - 1); emitModRM(0b10, 0b100, reg_idx); emitInt(dest.offset, 4); } }
void Assembler::lea(Indirect mem, Register reg) { int mem_idx = mem.base.regnum; int reg_idx = reg.regnum; int rex = REX_W; if (mem_idx >= 8) { rex |= REX_B; mem_idx -= 8; } if (reg_idx >= 8) { rex |= REX_R; reg_idx -= 8; } assert(mem_idx >= 0 && mem_idx < 8); assert(reg_idx >= 0 && reg_idx < 8); emitRex(rex); emitByte(0x8D); bool needssib = (mem_idx == 0b100); int mode = getModeFromOffset(mem.offset); emitModRM(mode, reg_idx, mem_idx); if (needssib) emitSIB(0b00, 0b100, mem_idx); if (mode == 0b01) { emitByte(mem.offset); } else if (mode == 0b10) { assert((-1L << 31) <= mem.offset && mem.offset < (1L << 31) - 1); emitInt(mem.offset, 4); } }
void Assembler::clear_reg(Register reg) { int reg_idx = reg.regnum; // we don't need to generate a REX_W because 32bit instructions will clear the upper 32bits. if (reg_idx >= 8) { emitRex(REX_R | REX_B); reg_idx -= 8; } emitByte(0x31); emitModRM(0b11, reg_idx, reg_idx); }
void Assembler::cmp(Indirect mem, Immediate imm, MovType type) { int64_t val = imm.val; assert(fitsInto<int32_t>(val)); int src_idx = mem.base.regnum; assert(type == MovType::Q || type == MovType::L); int rex = type == MovType::Q ? REX_W : 0; if (src_idx >= 8) { rex |= REX_B; src_idx -= 8; } assert(src_idx >= 0 && src_idx < 8); bool needssib = (src_idx == 0b100); if (rex) emitRex(rex); emitByte(0x81); if (mem.offset == 0) { emitModRM(0b00, 7, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); } else if (-0x80 <= mem.offset && mem.offset < 0x80) { emitModRM(0b01, 7, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); emitByte(mem.offset); } else { assert(fitsInto<int32_t>(mem.offset)); emitModRM(0b10, 7, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); emitInt(mem.offset, 4); } emitInt(val, 4); }
void Assembler::jmpq(Register dest) { int reg_idx = dest.regnum; if (reg_idx >= 8) { emitRex(REX_B); reg_idx -= 8; } assert(0 <= reg_idx && reg_idx < 8); emitByte(0xff); emitModRM(0b11, 0b100, reg_idx); }
void Assembler::emitArith(Immediate imm, Indirect mem, int opcode) { int64_t amount = imm.val; assert(fitsInto<int32_t>(amount)); assert(0 <= opcode && opcode < 8); int rex = REX_W; int mem_idx = mem.base.regnum; if (mem_idx >= 8) { rex |= REX_B; mem_idx -= 8; } emitRex(rex); bool needssib = (mem_idx == 0b100); assert(!needssib && "untested"); int mode = getModeFromOffset(mem.offset, mem_idx); assert(mode != 0b10 && "not yet supported"); if (-0x80 <= amount && amount < 0x80) { emitByte(0x83); if (needssib) emitSIB(0b00, 0b100, mem_idx); emitModRM(mode, opcode, mem_idx); if (mode == 0b01) emitByte(mem.offset); emitByte(amount); } else { emitByte(0x81); if (needssib) emitSIB(0b00, 0b100, mem_idx); emitModRM(mode, opcode, mem_idx); if (mode == 0b01) emitByte(mem.offset); emitInt(amount, 4); } }
void Assembler::decl(Indirect mem) { int src_idx = mem.base.regnum; int rex = 0; if (src_idx >= 8) { rex |= REX_B; src_idx -= 8; } assert(src_idx >= 0 && src_idx < 8); if (rex) emitRex(rex); emitByte(0xff); assert(-0x80 <= mem.offset && mem.offset < 0x80); if (mem.offset == 0) { emitModRM(0b00, 1, src_idx); } else { emitModRM(0b01, 1, src_idx); emitByte(mem.offset); } }
void Assembler::set_cond(Register reg, ConditionCode condition) { int reg_idx = reg.regnum; assert(0 <= reg_idx && reg_idx < 8); int rex = 0; // Have to emit a blank REX when accessing RSP/RBP/RDI/RSI, // since without it this instruction will refer to ah/bh/ch/dh. if (reg_idx >= 4 || rex) emitRex(rex); emitByte(0x0f); emitByte(0x90 + condition); emitModRM(0b11, 0, reg_idx); }
void Assembler::cmp(Register reg, Immediate imm) { int64_t val = imm.val; assert((-1L << 31) <= val && val < (1L << 31) - 1); int reg_idx = reg.regnum; int rex = REX_W; if (reg_idx > 8) { rex |= REX_B; reg_idx -= 8; } assert(0 <= reg_idx && reg_idx < 8); emitRex(rex); emitByte(0x81); emitModRM(0b11, 7, reg_idx); emitInt(val, 4); }
void Assembler::movsd(Indirect src, XMMRegister dest) { int rex = 0; int src_idx = src.base.regnum; int dest_idx = dest.regnum; if (src_idx >= 8) { trap(); rex |= REX_R; src_idx -= 8; } if (dest_idx >= 8) { trap(); rex |= REX_B; dest_idx -= 8; } emitByte(0xf2); if (rex) emitRex(rex); emitByte(0x0f); emitByte(0x10); bool needssib = (src_idx == 0b100); int mode; if (src.offset == 0) mode = 0b00; else if (-0x80 <= src.offset && src.offset < 0x80) mode = 0b01; else mode = 0b10; emitModRM(mode, dest_idx, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); if (mode == 0b01) { emitByte(src.offset); } else if (mode == 0b10) { emitInt(src.offset, 4); } }
void Assembler::cmp(Register reg1, Register reg2) { int reg1_idx = reg1.regnum; int reg2_idx = reg2.regnum; int rex = REX_W; if (reg1_idx >= 8) { rex |= REX_R; reg1_idx -= 8; } if (reg2_idx >= 8) { rex |= REX_B; reg2_idx -= 8; } assert(reg1_idx >= 0 && reg1_idx < 8); assert(reg2_idx >= 0 && reg2_idx < 8); emitRex(rex); emitByte(0x39); emitModRM(0b11, reg1_idx, reg2_idx); }
void Assembler::mov(Register src, Register dest) { ASSERT(src != dest, "probably better to avoid calling this?"); int src_idx = src.regnum; int dest_idx = dest.regnum; uint8_t rex = REX_W; if (dest_idx >= 8) { rex |= REX_B; dest_idx -= 8; } if (src_idx >= 8) { rex |= REX_R; src_idx -= 8; } assert(0 <= src_idx && src_idx < 8); assert(0 <= dest_idx && dest_idx < 8); emitRex(rex); emitByte(0x89); emitModRM(0b11, src_idx, dest_idx); }
void Assembler::movsd(XMMRegister src, XMMRegister dest) { int rex = 0; int src_idx = src.regnum; int dest_idx = dest.regnum; if (src_idx >= 8) { trap(); rex |= REX_R; src_idx -= 8; } if (dest_idx >= 8) { trap(); rex |= REX_B; dest_idx -= 8; } emitByte(0xf2); if (rex) emitRex(rex); emitByte(0x0f); emitByte(0x10); emitModRM(0b11, src_idx, dest_idx); }
void Assembler::mov_generic(Indirect src, Register dest, MovType type) { int rex; switch (type) { case MovType::Q: case MovType::ZBQ: case MovType::SBQ: case MovType::ZWQ: case MovType::SWQ: case MovType::SLQ: rex = REX_W; break; case MovType::L: case MovType::B: case MovType::ZBL: case MovType::SBL: case MovType::ZWL: case MovType::SWL: rex = 0; break; default: RELEASE_ASSERT(false, "unrecognized MovType"); } int src_idx = src.base.regnum; int dest_idx = dest.regnum; if (src_idx >= 8) { rex |= REX_B; src_idx -= 8; } if (dest_idx >= 8) { rex |= REX_R; dest_idx -= 8; } if (rex) emitRex(rex); // opcode switch (type) { case MovType::Q: case MovType::L: emitByte(0x8b); break; case MovType::B: emitByte(0x8a); break; case MovType::ZBQ: case MovType::ZBL: emitByte(0x0f); emitByte(0xb6); break; case MovType::SBQ: case MovType::SBL: emitByte(0x0f); emitByte(0xbe); break; case MovType::ZWQ: case MovType::ZWL: emitByte(0x0f); emitByte(0xb7); break; case MovType::SWQ: case MovType::SWL: emitByte(0x0f); emitByte(0xbf); break; case MovType::SLQ: emitByte(0x63); break; default: RELEASE_ASSERT(false, "unrecognized MovType"); } bool needssib = (src_idx == 0b100); int mode; if (src.offset == 0) mode = 0b00; else if (-0x80 <= src.offset && src.offset < 0x80) mode = 0b01; else mode = 0b10; emitModRM(mode, dest_idx, src_idx); if (needssib) emitSIB(0b00, 0b100, src_idx); if (mode == 0b01) { emitByte(src.offset); } else if (mode == 0b10) { emitInt(src.offset, 4); } }