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::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::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::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::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); } }