Index: src/ia32/assembler-ia32.cc |
diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc |
index 01b366431b2753a2a8104aea1eb56815b43c4574..b1f51c0c5a13f07e152dc65926caaaf21bf06989 100644 |
--- a/src/ia32/assembler-ia32.cc |
+++ b/src/ia32/assembler-ia32.cc |
@@ -282,6 +282,50 @@ Operand::Operand(Register index, |
set_dispr(disp, rmode); |
} |
+Operand::Operand(const Operand& operand, int32_t offset) { |
+ DCHECK(operand.len_ >= 1); |
+ // Operand encodes REX ModR/M [SIB] [Disp]. |
+ byte modrm = operand.buf_[0]; |
+ DCHECK(modrm < 0xC0); // Disallow mode 3 (register target). |
+ bool has_sib = ((modrm & 0x07) == 0x04); |
+ byte mode = modrm & 0xC0; |
+ int disp_offset = has_sib ? 2 : 1; |
+ int base_reg = (has_sib ? operand.buf_[1] : modrm) & 0x07; |
+ // Mode 0 with rbp/r13 as ModR/M or SIB base register always has a 32-bit |
+ // displacement. |
+ bool is_baseless = (mode == 0) && (base_reg == 0x05); // No base or RIP base. |
+ int32_t disp_value = 0; |
+ if (mode == 0x80 || is_baseless) { |
+ // Mode 2 or mode 0 with rbp/r13 as base: Word displacement. |
+ disp_value = *bit_cast<const int32_t*>(&operand.buf_[disp_offset]); |
+ } else if (mode == 0x40) { |
+ // Mode 1: Byte displacement. |
+ disp_value = static_cast<signed char>(operand.buf_[disp_offset]); |
+ } |
+ |
+ // Write new operand with same registers, but with modified displacement. |
+ DCHECK(offset >= 0 ? disp_value + offset >= disp_value |
+ : disp_value + offset < disp_value); // No overflow. |
+ disp_value += offset; |
+ if (!is_int8(disp_value) || is_baseless) { |
+ // Need 32 bits of displacement, mode 2 or mode 1 with register rbp/r13. |
+ buf_[0] = (modrm & 0x3f) | (is_baseless ? 0x00 : 0x80); |
+ len_ = disp_offset + 4; |
+ Memory::int32_at(&buf_[disp_offset]) = disp_value; |
+ } else if (disp_value != 0 || (base_reg == 0x05)) { |
+ // Need 8 bits of displacement. |
+ buf_[0] = (modrm & 0x3f) | 0x40; // Mode 1. |
+ len_ = disp_offset + 1; |
+ buf_[disp_offset] = static_cast<byte>(disp_value); |
+ } else { |
+ // Need no displacement. |
+ buf_[0] = (modrm & 0x3f); // Mode 0. |
+ len_ = disp_offset; |
+ } |
+ if (has_sib) { |
+ buf_[1] = operand.buf_[1]; |
+ } |
+} |
bool Operand::is_reg(Register reg) const { |
return ((buf_[0] & 0xF8) == 0xC0) // addressing mode is register only. |
@@ -2864,6 +2908,155 @@ void Assembler::rorx(Register dst, const Operand& src, byte imm8) { |
EMIT(imm8); |
} |
+void Assembler::movups(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x10); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::movups(const Operand& dst, XMMRegister src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x11); |
+ emit_sse_operand(src, dst); |
+} |
+ |
+void Assembler::minps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x5D); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::maxps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x5F); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::rcpps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x53); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::rsqrtps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x52); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::sqrtps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x51); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::cvtdq2ps(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0x5B); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::paddd(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0xFE); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::psubd(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0xFA); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::pmulld(XMMRegister dst, const Operand& src) { |
+ DCHECK(IsEnabled(SSE4_1)); |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0x38); |
+ EMIT(0x40); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::pmuludq(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0xF4); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::punpackldq(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0x62); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::cvtps2dq(XMMRegister dst, const Operand& src) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0x5B); |
+ emit_sse_operand(dst, src); |
+} |
+ |
+void Assembler::cmpps(XMMRegister dst, XMMRegister src, int8_t cmp) { |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x0F); |
+ EMIT(0xC2); |
+ emit_sse_operand(dst, src); |
+ EMIT(cmp); |
+} |
+ |
+void Assembler::cmpeqps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x0); |
+} |
+ |
+void Assembler::cmpltps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x1); |
+} |
+ |
+void Assembler::cmpleps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x2); |
+} |
+ |
+void Assembler::cmpneqps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x4); |
+} |
+ |
+void Assembler::cmpnltps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x5); |
+} |
+ |
+void Assembler::cmpnleps(XMMRegister dst, XMMRegister src) { |
+ cmpps(dst, src, 0x6); |
+} |
+ |
+void Assembler::insertps(XMMRegister dst, XMMRegister src, byte imm8) { |
+ DCHECK(CpuFeatures::IsSupported(SSE4_1)); |
+ DCHECK(is_uint8(imm8)); |
+ EnsureSpace ensure_space(this); |
+ EMIT(0x66); |
+ EMIT(0x0F); |
+ EMIT(0x3A); |
+ EMIT(0x21); |
+ emit_sse_operand(dst, src); |
+ EMIT(imm8); |
+} |
void Assembler::emit_sse_operand(XMMRegister reg, const Operand& adr) { |
Register ireg = { reg.code() }; |