///|
/// x86_64 instruction encoding helpers used by the target emitter.

///|
fn emit_u32_le(mc : CodeBuffer, v : Int) -> Unit {
  mc.emit_byte(v & 255)
  mc.emit_byte((v >> 8) & 255)
  mc.emit_byte((v >> 16) & 255)
  mc.emit_byte((v >> 24) & 255)
}

///|
fn emit_u64_le(mc : CodeBuffer, v : Int64) -> Unit {
  // Emit in little-endian order.
  let mut x = v
  for _i in 0..<8 {
    mc.emit_byte((x & 0xFFL).to_int())
    x = x >> 8
  }
}

///|
fn emit_rex_w(mc : CodeBuffer, r : Int, b : Int) -> Unit {
  // REX prefix: 0100WRXB. We only need W=1 and R/B for now.
  let rex = 0x48 | ((r & 1) << 2) | (b & 1)
  mc.emit_byte(rex)
}

///|
fn emit_rex(mc : CodeBuffer, r : Int, b : Int) -> Unit {
  // REX prefix without W bit (used by some SSE encodings).
  let rex = 0x40 | ((r & 1) << 2) | (b & 1)
  mc.emit_byte(rex)
}

///|
fn validate_reg_idx_0_15(kind : String, idx : Int) -> Unit {
  guard idx >= 0 && idx < 16 else {
    abort("x86_64 encode: invalid \{kind} reg idx \{idx} (expected 0..15)")
  }
}

///|
fn emit_modrm(mc : CodeBuffer, mod_ : Int, reg : Int, rm : Int) -> Unit {
  validate_reg_idx_0_15("modrm.reg", reg)
  validate_reg_idx_0_15("modrm.rm", rm)
  let b = ((mod_ & 3) << 6) | ((reg & 7) << 3) | (rm & 7)
  mc.emit_byte(b)
}

///|
fn emit_sib(mc : CodeBuffer, scale : Int, index : Int, base : Int) -> Unit {
  validate_reg_idx_0_15("sib.index", index)
  validate_reg_idx_0_15("sib.base", base)
  let b = ((scale & 3) << 6) | ((index & 7) << 3) | (base & 7)
  mc.emit_byte(b)
}

///|
fn emit_disp32(mc : CodeBuffer, disp : Int) -> Unit {
  emit_u32_le(mc, disp)
}

///|
fn CodeBuffer::x86_emit_mov_imm64(
  self : CodeBuffer,
  dst : Int,
  imm : Int64,
) -> Unit {
  // mov r64, imm64: REX.W + B8+rd, imm64
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xB8 + (dst & 7))
  emit_u64_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_add_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // add r/m64, r64: REX.W + 01 /r (dst += src)
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x01)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_add_r_imm8(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // add r/m64, imm8: REX.W + 83 /0 ib (sign-extended imm8)
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0x83)
  // /0 in reg field.
  emit_modrm(self, 3, 0, dst)
  self.emit_byte(imm & 255)
}

///|
fn CodeBuffer::x86_emit_add_r_imm32(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // add r/m64, imm32: REX.W + 81 /0 id (imm32 sign-extended to 64-bit).
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0x81)
  emit_modrm(self, 3, 0, dst)
  emit_u32_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_add_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // add r/m32, r32: 01 /r (dst += src), zero-extends to 64-bit.
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x01)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_sub_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // sub r/m64, r64: REX.W + 29 /r (dst -= src)
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x29)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_sub_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // sub r/m32, r32: 29 /r (dst -= src), zero-extends to 64-bit.
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x29)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_and_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // and r/m64, r64: REX.W + 21 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x21)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_and_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // and r/m32, r32: 21 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x21)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_or_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // or r/m64, r64: REX.W + 09 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x09)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_or_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // or r/m32, r32: 09 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x09)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_xor_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // xor r/m64, r64: REX.W + 31 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x31)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_xor_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // xor r/m32, r32: 31 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x31)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_imul_rr(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // imul r64, r/m64: REX.W + 0F AF /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xAF)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_imul_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // imul r32, r/m32: 0F AF /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xAF)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_not_r64(self : CodeBuffer, reg : Int) -> Unit {
  // not r/m64: REX.W + F7 /2
  let b = (reg >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 2, reg)
}

///|
fn CodeBuffer::x86_emit_neg_r64(self : CodeBuffer, reg : Int) -> Unit {
  // neg r/m64: REX.W + F7 /3
  let b = (reg >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 3, reg)
}

///|
fn CodeBuffer::x86_emit_not_r32(self : CodeBuffer, reg : Int) -> Unit {
  // not r/m32: F7 /2
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 2, reg)
}

///|
fn CodeBuffer::x86_emit_neg_r32(self : CodeBuffer, reg : Int) -> Unit {
  // neg r/m32: F7 /3
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 3, reg)
}

///|
fn CodeBuffer::x86_emit_shl_r_cl(self : CodeBuffer, dst : Int) -> Unit {
  // shl r/m64, cl: REX.W + D3 /4
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 4, dst)
}

///|
fn CodeBuffer::x86_emit_shl_r32_cl(self : CodeBuffer, dst : Int) -> Unit {
  // shl r/m32, cl: D3 /4
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 4, dst)
}

///|
fn CodeBuffer::x86_emit_shr_r_cl(self : CodeBuffer, dst : Int) -> Unit {
  // shr r/m64, cl: REX.W + D3 /5
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 5, dst)
}

///|
fn CodeBuffer::x86_emit_shr_r32_cl(self : CodeBuffer, dst : Int) -> Unit {
  // shr r/m32, cl: D3 /5
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 5, dst)
}

///|
fn CodeBuffer::x86_emit_sar_r_cl(self : CodeBuffer, dst : Int) -> Unit {
  // sar r/m64, cl: REX.W + D3 /7
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 7, dst)
}

///|
fn CodeBuffer::x86_emit_sar_r32_cl(self : CodeBuffer, dst : Int) -> Unit {
  // sar r/m32, cl: D3 /7
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 7, dst)
}

///|
fn CodeBuffer::x86_emit_ror_r_cl(self : CodeBuffer, dst : Int) -> Unit {
  // ror r/m64, cl: REX.W + D3 /1
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 1, dst)
}

///|
fn CodeBuffer::x86_emit_ror_r32_cl(self : CodeBuffer, dst : Int) -> Unit {
  // ror r/m32, cl: D3 /1
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xD3)
  emit_modrm(self, 3, 1, dst)
}

///|
fn CodeBuffer::x86_emit_shl_r_imm8(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // shl r/m64, imm8: REX.W + C1 /4 ib
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xC1)
  emit_modrm(self, 3, 4, dst)
  self.emit_byte(imm & 255)
}

///|
fn CodeBuffer::x86_emit_shl_r32_imm8(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // shl r/m32, imm8: C1 /4 ib
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xC1)
  emit_modrm(self, 3, 4, dst)
  self.emit_byte(imm & 255)
}

///|
fn CodeBuffer::x86_emit_shr_r_imm8(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // shr r/m64, imm8: REX.W + C1 /5 ib
  let b = (dst >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xC1)
  emit_modrm(self, 3, 5, dst)
  self.emit_byte(imm & 255)
}

///|
fn CodeBuffer::x86_emit_shr_r32_imm8(
  self : CodeBuffer,
  dst : Int,
  imm : Int,
) -> Unit {
  // shr r/m32, imm8: C1 /5 ib
  let b = (dst >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xC1)
  emit_modrm(self, 3, 5, dst)
  self.emit_byte(imm & 255)
}

///|
fn CodeBuffer::x86_emit_mov_rr(self : CodeBuffer, dst : Int, src : Int) -> Unit {
  // mov r/m64, r64: REX.W + 89 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x89)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_mov_rr32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // mov r/m32, r32: 89 /r
  let r = (src >> 3) & 1
  let b = (dst >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x89)
  emit_modrm(self, 3, src, dst)
}

///|
fn CodeBuffer::x86_emit_movsxd_r64_r32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movsxd r64, r/m32: REX.W + 63 /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x63)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_movsx_r32_r8(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movsx r32, r/m8: 0F BE /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 || (src & 7) >= 4 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xBE)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_movsx_r64_r8(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movsx r64, r/m8: REX.W + 0F BE /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xBE)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_movsx_r32_r16(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movsx r32, r/m16: 0F BF /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xBF)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_movsx_r64_r16(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movsx r64, r/m16: REX.W + 0F BF /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xBF)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_push_r64(self : CodeBuffer, reg : Int) -> Unit {
  // push r64: 50+rd, with optional REX.B for r8-r15.
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x50 + (reg & 7))
}

///|
fn CodeBuffer::x86_emit_pop_r64(self : CodeBuffer, reg : Int) -> Unit {
  // pop r64: 58+rd, with optional REX.B for r8-r15.
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x58 + (reg & 7))
}

///|
fn CodeBuffer::x86_emit_call_r64(self : CodeBuffer, reg : Int) -> Unit {
  // call r/m64: FF /2
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xFF)
  // /2 in reg field.
  emit_modrm(self, 3, 2, reg)
}

///|
fn CodeBuffer::x86_emit_jmp_r64(self : CodeBuffer, reg : Int) -> Unit {
  // jmp r/m64: FF /4
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xFF)
  // /4 in reg field.
  emit_modrm(self, 3, 4, reg)
}

///|
fn CodeBuffer::x86_emit_sub_rsp_imm32(self : CodeBuffer, imm : Int) -> Unit {
  // sub rsp, imm32: 48 81 EC imm32
  self.emit_byte(0x48)
  self.emit_byte(0x81)
  self.emit_byte(0xEC)
  emit_u32_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_add_rsp_imm32(self : CodeBuffer, imm : Int) -> Unit {
  // add rsp, imm32: 48 81 C4 imm32
  self.emit_byte(0x48)
  self.emit_byte(0x81)
  self.emit_byte(0xC4)
  emit_u32_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_mov_r64_m64(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // mov r64, [base + disp32]: REX.W + 8B /r, modrm with mod=10 (disp32).
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x8B)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    // SIB required for rsp/r12 base.
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_mov_r32_m32(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // mov r32, [base + disp32]: 8B /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x8B)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_mov_m64_r64(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src : Int,
) -> Unit {
  // mov [base + disp32], r64: REX.W + 89 /r, modrm with mod=10 (disp32).
  let r = (src >> 3) & 1
  let b = (base >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x89)
  emit_modrm(self, 2, src, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_mov_m32_r32(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src : Int,
) -> Unit {
  // mov [base + disp32], r32: 89 /r
  let r = (src >> 3) & 1
  let b = (base >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x89)
  emit_modrm(self, 2, src, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_mov_m8_r8(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src : Int,
) -> Unit {
  // mov r/m8, r8: 88 /r
  //
  // Low 8-bit register forms SPL/BPL/SIL/DIL require a REX prefix, so we emit
  // a REX prefix whenever the src reg needs it (or when selecting r8b-r15b).
  let r = (src >> 3) & 1
  let b = (base >> 3) & 1
  if r != 0 || b != 0 || (src & 7) >= 4 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x88)
  emit_modrm(self, 2, src, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_mov_m16_r16(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src : Int,
) -> Unit {
  // mov r/m16, r16: 66 89 /r
  let r = (src >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x89)
  emit_modrm(self, 2, src, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movaps_xmm_xmm(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movaps xmm, xmm: 0F 28 /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x28)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_minps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // minps xmm, xmm/m128: 0F 5D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_minpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // minpd xmm, xmm/m128: 66 0F 5D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_maxps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // maxps xmm, xmm/m128: 0F 5F /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_maxpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // maxpd xmm, xmm/m128: 66 0F 5F /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_subps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // subps xmm, xmm/m128: 0F 5C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_subpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // subpd xmm, xmm/m128: 66 0F 5C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_addps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // addps xmm, xmm/m128: 0F 58 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x58)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_addpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // addpd xmm, xmm/m128: 66 0F 58 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x58)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_mulps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // mulps xmm, xmm/m128: 0F 59 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x59)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_mulpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // mulpd xmm, xmm/m128: 66 0F 59 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x59)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_divps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // divps xmm, xmm/m128: 0F 5E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_divpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // divpd xmm, xmm/m128: 66 0F 5E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_sqrtps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // sqrtps xmm, xmm/m128: 0F 51 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x51)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_sqrtpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // sqrtpd xmm, xmm/m128: 66 0F 51 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x51)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pslld_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pslld xmm, imm8: 66 0F 72 /6 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x72)
  emit_modrm(self, 3, 6, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psllq_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psllq xmm, imm8: 66 0F 73 /6 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x73)
  emit_modrm(self, 3, 6, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psllw_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psllw xmm, imm8: 66 0F 71 /6 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x71)
  emit_modrm(self, 3, 6, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psll_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psll{w,d,q} xmm, xmm/m128: 66 0F F1/F2/F3 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    H16 => self.emit_byte(0xF1)
    S32 => self.emit_byte(0xF2)
    D64 => self.emit_byte(0xF3)
    _ => abort("x86_64 psll: unsupported lane size \{lane_size}")
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psrl_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psrl{w,d,q} xmm, xmm/m128: 66 0F D1/D2/D3 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    H16 => self.emit_byte(0xD1)
    S32 => self.emit_byte(0xD2)
    D64 => self.emit_byte(0xD3)
    _ => abort("x86_64 psrl: unsupported lane size \{lane_size}")
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psra_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psra{w,d} xmm, xmm/m128: 66 0F E1/E2 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    H16 => self.emit_byte(0xE1)
    S32 => self.emit_byte(0xE2)
    _ => abort("x86_64 psra: unsupported lane size \{lane_size}")
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psrlw_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psrlw xmm, imm8: 66 0F 71 /2 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x71)
  emit_modrm(self, 3, 2, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psrad_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psrad xmm, imm8: 66 0F 72 /4 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x72)
  emit_modrm(self, 3, 4, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_cmpps_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // cmpps xmm, xmm/m128, imm8: 0F C2 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC2)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_cmppd_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // cmppd xmm, xmm/m128, imm8: 66 0F C2 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC2)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_roundps_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // roundps xmm, xmm/m128, imm8: 66 0F 3A 08 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x08)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_roundpd_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // roundpd xmm, xmm/m128, imm8: 66 0F 3A 09 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x09)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_roundss_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // roundss xmm, xmm/m32, imm8: 66 0F 3A 0A /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x0A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_roundsd_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // roundsd xmm, xmm/m64, imm8: 66 0F 3A 0B /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x0B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psrld_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psrld xmm, imm8: 66 0F 72 /2 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x72)
  emit_modrm(self, 3, 2, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_psrlq_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  imm8 : Int,
) -> Unit {
  // psrlq xmm, imm8: 66 0F 73 /2 ib
  let b = (dst_xmm >> 3) & 1
  self.emit_byte(0x66)
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x73)
  emit_modrm(self, 3, 2, dst_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_movss_xmm_m32(
  self : CodeBuffer,
  dst_xmm : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movss xmm, m32: F3 0F 10 /r
  let r = (dst_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x10)
  emit_modrm(self, 2, dst_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // movss xmm1, xmm2/m32: F3 0F 10 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x10)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_movss_m32_xmm(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src_xmm : Int,
) -> Unit {
  // movss m32, xmm: F3 0F 11 /r
  let r = (src_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x11)
  emit_modrm(self, 2, src_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsd_m64_xmm(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src_xmm : Int,
) -> Unit {
  // movsd m64, xmm: F2 0F 11 /r
  let r = (src_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x11)
  emit_modrm(self, 2, src_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsd_xmm_m64(
  self : CodeBuffer,
  dst_xmm : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movsd xmm, m64: F2 0F 10 /r
  let r = (dst_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x10)
  emit_modrm(self, 2, dst_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // movsd xmm1, xmm2/m64: F2 0F 10 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x10)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_movlhps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // movlhps xmm1, xmm2/m64: 0F 16 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x16)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_unpcklps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // unpcklps xmm1, xmm2/m128: 0F 14 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x14)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_ucomiss_xmm_xmm(
  self : CodeBuffer,
  lhs_xmm : Int,
  rhs_xmm : Int,
) -> Unit {
  // ucomiss xmm1, xmm2: 0F 2E /r
  let r = (lhs_xmm >> 3) & 1
  let b = (rhs_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2E)
  emit_modrm(self, 3, lhs_xmm, rhs_xmm)
}

///|
fn CodeBuffer::x86_emit_ucomisd_xmm_xmm(
  self : CodeBuffer,
  lhs_xmm : Int,
  rhs_xmm : Int,
) -> Unit {
  // ucomisd xmm1, xmm2: 66 0F 2E /r
  let r = (lhs_xmm >> 3) & 1
  let b = (rhs_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2E)
  emit_modrm(self, 3, lhs_xmm, rhs_xmm)
}

///|
fn CodeBuffer::x86_emit_pcmpeqd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pcmpeqd xmm, xmm/m128: 66 0F 76 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x76)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pand_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pand xmm, xmm/m128: 66 0F DB /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDB)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_por_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // por xmm, xmm/m128: 66 0F EB /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xEB)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pxor_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pxor xmm, xmm/m128: 66 0F EF /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xEF)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pandn_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pandn xmm, xmm/m128: 66 0F DF /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDF)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pinsrq_xmm_r64_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
  imm8 : Int,
) -> Unit {
  // pinsrq xmm, r/m64, imm8: 66 REX.W 0F 3A 22 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x22)
  emit_modrm(self, 3, dst_xmm, src)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pinsrd_xmm_r32_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
  imm8 : Int,
) -> Unit {
  // pinsrd xmm, r/m32, imm8: 66 0F 3A 22 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x22)
  emit_modrm(self, 3, dst_xmm, src)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pinsrw_xmm_r32_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
  imm8 : Int,
) -> Unit {
  // pinsrw xmm, r/m16, imm8: 66 0F C4 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC4)
  emit_modrm(self, 3, dst_xmm, src)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pinsrb_xmm_r32_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
  imm8 : Int,
) -> Unit {
  // pinsrb xmm, r/m8, imm8 (SSE4.1): 66 0F 3A 20 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  // Low 8-bit register forms SPL/BPL/SIL/DIL require a REX prefix.
  if r != 0 || b != 0 || (src & 7) >= 4 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x20)
  emit_modrm(self, 3, dst_xmm, src)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_insertps_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // insertps xmm1, xmm2/m32, imm8 (SSE4.1): 66 0F 3A 21 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x21)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_padd_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // padd{b,w,d,q}: 66 0F FC/FD/FE/D4 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    B8 => self.emit_byte(0xFC)
    H16 => self.emit_byte(0xFD)
    S32 => self.emit_byte(0xFE)
    D64 => self.emit_byte(0xD4)
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_phaddw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // phaddw (SSSE3): 66 0F 38 01 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x01)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psub_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psub{b,w,d,q}: 66 0F F8/F9/FA/FB /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    B8 => self.emit_byte(0xF8)
    H16 => self.emit_byte(0xF9)
    S32 => self.emit_byte(0xFA)
    D64 => self.emit_byte(0xFB)
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmullw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmullw: 66 0F D5 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xD5)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmulld_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmulld (SSE4.1): 66 0F 38 40 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x40)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pcmpeq_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pcmpeq{b,w,d,q}: 66 0F 74/75/76/38 29 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    B8 => {
      self.emit_byte(0x74)
      emit_modrm(self, 3, dst_xmm, src_xmm)
    }
    H16 => {
      self.emit_byte(0x75)
      emit_modrm(self, 3, dst_xmm, src_xmm)
    }
    S32 => {
      self.emit_byte(0x76)
      emit_modrm(self, 3, dst_xmm, src_xmm)
    }
    D64 =>
      // pcmpeqq is SSE4.1; avoid relying on it and use an emulation sequence at a higher level.
      abort("x86_64 pcmpeq.i64: use emulation sequence instead")
  }
}

///|
fn CodeBuffer::x86_emit_pcmpgt_xmm_xmm(
  self : CodeBuffer,
  lane_size : RawLaneSize,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pcmpgt{b,w,d}: 66 0F 64/65/66 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  match lane_size {
    B8 => self.emit_byte(0x64)
    H16 => self.emit_byte(0x65)
    S32 => self.emit_byte(0x66)
    D64 => abort("x86_64 pcmpgt.i64: use emulation sequence instead")
  }
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pshufd_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pshufd xmm1, xmm2/m128, imm8: 66 0F 70 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x70)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pshuflw_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pshuflw xmm1, xmm2/m128, imm8: F2 0F 70 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x70)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_shufps_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // shufps xmm1, xmm2/m128, imm8: 0F C6 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC6)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_shufpd_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // shufpd xmm1, xmm2/m128, imm8: 66 0F C6 /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC6)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_paddusb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // paddusb xmm, xmm/m128: 66 0F DC /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDC)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_paddsb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // paddsb xmm, xmm/m128: 66 0F EC /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xEC)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_paddsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // paddsw xmm, xmm/m128: 66 0F ED /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xED)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_paddusw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // paddusw xmm, xmm/m128: 66 0F DD /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDD)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psubsb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psubsb xmm, xmm/m128: 66 0F E8 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE8)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psubsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psubsw xmm, xmm/m128: 66 0F E9 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE9)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psubusb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psubusb xmm, xmm/m128: 66 0F D8 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xD8)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_psubusw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // psubusw xmm, xmm/m128: 66 0F D9 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xD9)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pavgb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pavgb xmm, xmm/m128: 66 0F E0 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE0)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pavgw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pavgw xmm, xmm/m128: 66 0F E3 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE3)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminub_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminub xmm, xmm/m128: 66 0F DA /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDA)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxub_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxub xmm, xmm/m128: 66 0F DE /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xDE)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminsw xmm, xmm/m128: 66 0F EA /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xEA)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxsw xmm, xmm/m128: 66 0F EE /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xEE)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminsb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminsb xmm, xmm/m128 (SSE4.1): 66 0F 38 38 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x38)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxsb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxsb xmm, xmm/m128 (SSE4.1): 66 0F 38 3C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminuw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminuw xmm, xmm/m128 (SSE4.1): 66 0F 38 3A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxuw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxuw xmm, xmm/m128 (SSE4.1): 66 0F 38 3E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminsd xmm, xmm/m128 (SSE4.1): 66 0F 38 39 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x39)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxsd xmm, xmm/m128 (SSE4.1): 66 0F 38 3D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pminud_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pminud xmm, xmm/m128 (SSE4.1): 66 0F 38 3B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaxud_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaxud xmm, xmm/m128 (SSE4.1): 66 0F 38 3F /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x3F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pabsb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pabsb xmm, xmm/m128 (SSSE3): 66 0F 38 1C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x1C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pabsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pabsw xmm, xmm/m128 (SSSE3): 66 0F 38 1D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x1D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pabsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pabsd xmm, xmm/m128 (SSSE3): 66 0F 38 1E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x1E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovsxbw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovsxbw xmm, xmm/m64 (SSE4.1): 66 0F 38 20 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x20)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovzxbw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovzxbw xmm, xmm/m64 (SSE4.1): 66 0F 38 30 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x30)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovsxwd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovsxwd xmm, xmm/m64 (SSE4.1): 66 0F 38 23 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x23)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovzxwd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovzxwd xmm, xmm/m64 (SSE4.1): 66 0F 38 33 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x33)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovsxdq_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovsxdq xmm, xmm/m64 (SSE4.1): 66 0F 38 25 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x25)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmovzxdq_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmovzxdq xmm, xmm/m64 (SSE4.1): 66 0F 38 35 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x35)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pshufb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  mask_xmm : Int,
) -> Unit {
  // pshufb xmm, xmm/m128 (SSSE3): 66 0F 38 00 /r
  let r = (dst_xmm >> 3) & 1
  let b = (mask_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x00)
  emit_modrm(self, 3, dst_xmm, mask_xmm)
}

///|
fn CodeBuffer::x86_emit_punpcklbw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // punpcklbw xmm, xmm/m128: 66 0F 60 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x60)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_punpckhbw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // punpckhbw xmm, xmm/m128: 66 0F 68 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x68)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_packsswb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // packsswb xmm, xmm/m128: 66 0F 63 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x63)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_packuswb_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // packuswb xmm, xmm/m128: 66 0F 67 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x67)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_packssdw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // packssdw xmm, xmm/m128: 66 0F 6B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x6B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_packusdw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // packusdw xmm, xmm/m128 (SSE4.1): 66 0F 38 2B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x2B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_palignr_xmm_xmm_imm8(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // palignr xmm, xmm/m128, imm8 (SSSE3): 66 0F 3A 0F /r ib
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x0F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pmaddwd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaddwd xmm, xmm/m128: 66 0F F5 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xF5)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmaddubsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmaddubsw xmm, xmm/m128 (SSSE3): 66 0F 38 04 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x04)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pmulhrsw_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // pmulhrsw xmm, xmm/m128 (SSSE3): 66 0F 38 0B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x38)
  self.emit_byte(0x0B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_pextrb_r32_xmm_imm8(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pextrb r32, xmm, imm8 (SSE4.1): 66 0F 3A 14 /r ib
  // ModRM.reg encodes the XMM source; ModRM.r/m encodes the GPR destination.
  let r = (src_xmm >> 3) & 1
  let b = (dst >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x14)
  emit_modrm(self, 3, src_xmm, dst)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pextrd_r32_xmm_imm8(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pextrd r32, xmm, imm8 (SSE4.1): 66 0F 3A 16 /r ib
  // ModRM.reg encodes the XMM source; ModRM.r/m encodes the GPR destination.
  let r = (src_xmm >> 3) & 1
  let b = (dst >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x16)
  emit_modrm(self, 3, src_xmm, dst)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pextrq_r64_xmm_imm8(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pextrq r64, xmm, imm8 (SSE4.1): 66 REX.W 0F 3A 16 /r ib
  // ModRM.reg encodes the XMM source; ModRM.r/m encodes the GPR destination.
  let r = (src_xmm >> 3) & 1
  let b = (dst >> 3) & 1
  self.emit_byte(0x66)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x3A)
  self.emit_byte(0x16)
  emit_modrm(self, 3, src_xmm, dst)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pextrw_r32_xmm_imm8(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
  imm8 : Int,
) -> Unit {
  // pextrw r32, xmm, imm8 (SSE2): 66 0F C5 /r ib
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xC5)
  emit_modrm(self, 3, dst, src_xmm)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_pmovmskb_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // pmovmskb r32, xmm: 66 0F D7 /r
  //
  // Note: Intel manual notes operand-size is 64-bit by default in 64-bit mode
  // but we only need 16 bits. Do not set REX.W.
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xD7)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_movmskps_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // movmskps r32, xmm: 0F 50 /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x50)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_movmskpd_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // movmskpd r32, xmm: 66 0F 50 /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x50)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_xorpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // xorpd xmm1, xmm2: 66 0F 57 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x57)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_xorps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // xorps xmm1, xmm2: 0F 57 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x57)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_subss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // subss xmm1, xmm2: F3 0F 5C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_subsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // subsd xmm1, xmm2: F2 0F 5C /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5C)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_addss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // addss xmm1, xmm2: F3 0F 58 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x58)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_addsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // addsd xmm1, xmm2: F2 0F 58 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x58)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_minss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // minss xmm1, xmm2: F3 0F 5D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_minsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // minsd xmm1, xmm2: F2 0F 5D /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5D)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_maxss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // maxss xmm1, xmm2: F3 0F 5F /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_maxsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // maxsd xmm1, xmm2: F2 0F 5F /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5F)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_mulss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // mulss xmm1, xmm2: F3 0F 59 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x59)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_mulsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // mulsd xmm1, xmm2: F2 0F 59 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x59)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_divss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // divss xmm1, xmm2: F3 0F 5E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_divsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // divsd xmm1, xmm2: F2 0F 5E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5E)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_sqrtss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // sqrtss xmm1, xmm2: F3 0F 51 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x51)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_sqrtsd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // sqrtsd xmm1, xmm2: F2 0F 51 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x51)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_andps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // andps xmm1, xmm2: 0F 54 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x54)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_andpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // andpd xmm1, xmm2: 66 0F 54 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x54)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_orps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // orps xmm1, xmm2: 0F 56 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x56)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_orpd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // orpd xmm1, xmm2: 66 0F 56 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x56)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttss2si_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // cvttss2si r32, xmm: F3 0F 2C /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2C)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttss2si_r64_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // cvttss2si r64, xmm: REX.W + F3 0F 2C /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x2C)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttsd2si_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // cvttsd2si r32, xmm: F2 0F 2C /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2C)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttsd2si_r64_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // cvttsd2si r64, xmm: REX.W + F2 0F 2C /r
  let r = (dst >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x2C)
  emit_modrm(self, 3, dst, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtsi2ss_xmm_r32(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // cvtsi2ss xmm, r/m32: F3 0F 2A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2A)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_cvtsi2ss_xmm_r64(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // cvtsi2ss xmm, r/m64: REX.W + F3 0F 2A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0xF3)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x2A)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_cvtsi2sd_xmm_r32(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // cvtsi2sd xmm, r/m32: F2 0F 2A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x2A)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_cvtsi2sd_xmm_r64(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // cvtsi2sd xmm, r/m64: REX.W + F2 0F 2A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0xF2)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x2A)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_cvtss2sd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtss2sd xmm1, xmm2: F3 0F 5A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtsd2ss_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtsd2ss xmm1, xmm2: F2 0F 5A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF2)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtdq2ps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtdq2ps xmm1, xmm2/m128: 0F 5B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttps2dq_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvttps2dq xmm1, xmm2/m128: F3 0F 5B /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5B)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvttpd2dq_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvttpd2dq xmm1, xmm2/m128: 66 0F E6 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE6)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtdq2pd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtdq2pd xmm1, xmm2/m64: F3 0F E6 /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xE6)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtps2pd_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtps2pd xmm1, xmm2/m64: 0F 5A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_cvtpd2ps_xmm_xmm(
  self : CodeBuffer,
  dst_xmm : Int,
  src_xmm : Int,
) -> Unit {
  // cvtpd2ps xmm1, xmm2/m128: 66 0F 5A /r
  let r = (dst_xmm >> 3) & 1
  let b = (src_xmm >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x5A)
  emit_modrm(self, 3, dst_xmm, src_xmm)
}

///|
fn CodeBuffer::x86_emit_movdqu_m128_xmm(
  self : CodeBuffer,
  base : Int,
  disp : Int,
  src_xmm : Int,
) -> Unit {
  // movdqu m128, xmm: F3 0F 7F /r
  let r = (src_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x7F)
  emit_modrm(self, 2, src_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movdqu_xmm_m128(
  self : CodeBuffer,
  dst_xmm : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movdqu xmm, m128: F3 0F 6F /r
  let r = (dst_xmm >> 3) & 1
  let b = (base >> 3) & 1
  self.emit_byte(0xF3)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x6F)
  emit_modrm(self, 2, dst_xmm, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsx_r64_m8(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movsx r64, m8: REX.W + 0F BE /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xBE)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movzx_r32_m8(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movzx r32, m8: 0F B6 /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xB6)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsx_r64_m16(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movsx r64, m16: REX.W + 0F BF /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xBF)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movzx_r32_m16(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movzx r32, m16: 0F B7 /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xB7)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_movsxd_r64_m32(
  self : CodeBuffer,
  dst : Int,
  base : Int,
  disp : Int,
) -> Unit {
  // movsxd r64, m32: REX.W + 63 /r
  let r = (dst >> 3) & 1
  let b = (base >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x63)
  emit_modrm(self, 2, dst, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, disp)
}

///|
fn CodeBuffer::x86_emit_ret(self : CodeBuffer) -> Unit {
  self.emit_byte(0xC3)
}

///|
fn CodeBuffer::x86_emit_fma213(
  self : CodeBuffer,
  scalar : Bool,
  f64 : Bool,
  operation : X64FloatTernary,
  destination : Int,
  multiplier : Int,
  addend : Int,
) -> Unit {
  let r = (destination >> 3) & 1
  let b = (addend >> 3) & 1
  self.emit_byte(0xC4)
  self.emit_byte(((r ^ 1) << 7) | 0x40 | ((b ^ 1) << 5) | 0x02)
  self.emit_byte(
    (if f64 { 0x80 } else { 0 }) | (((multiplier & 15) ^ 15) << 3) | 0x01,
  )
  let opcode = match (operation, scalar) {
    (Fmadd, true) => 0xA9
    (Fmadd, false) => 0xA8
    (Fmsub, true) => 0xAB
    (Fmsub, false) => 0xAA
    (Fnmadd, true) => 0xAD
    (Fnmadd, false) => 0xAC
    (Fnmsub, true) => 0xAF
    (Fnmsub, false) => 0xAE
  }
  self.emit_byte(opcode)
  emit_modrm(self, 3, destination, addend)
}

///|
fn CodeBuffer::x86_emit_jmp_rel32(
  self : CodeBuffer,
  target_block : Int,
) -> Unit {
  // jmp rel32: E9 disp32
  self.emit_byte(0xE9)
  let disp_offset = self.current_pos()
  emit_u32_le(self, 0)
  let next_ip_offset = self.current_pos()
  self.add_x86_rel32_fixup(target_block, disp_offset, next_ip_offset)
}

///|
fn x86_cond_to_jcc_opcode(cond : RawCondition) -> Int {
  match cond {
    // Signed/unsigned conditions match the usual interpretation after CMP.
    RawEq => 0x84 // JE
    RawNe => 0x85 // JNE
    RawHs => 0x83 // JAE/JNB
    RawLo => 0x82 // JB
    RawPl => 0x89 // JNS
    RawVs => 0x80 // JO
    // Parity conditions (x86_64-only; used after UCOMIS*).
    RawPs => 0x8A // JP/JPE (parity set)
    RawPc => 0x8B // JNP/JPO (parity clear)
    RawHi => 0x87 // JA
    RawLs => 0x86 // JBE
    RawGe => 0x8D // JGE
    RawLt => 0x8C // JL
    RawGt => 0x8F // JG
    RawLe => 0x8E // JLE
    RawAl => abort("x86_64 jcc: AL is not a conditional branch")
  }
}

///|
fn CodeBuffer::x86_emit_jcc_rel32(
  self : CodeBuffer,
  cond : RawCondition,
  target_block : Int,
) -> Unit {
  // jcc rel32: 0F 8? disp32
  self.emit_byte(0x0F)
  self.emit_byte(x86_cond_to_jcc_opcode(cond))
  let disp_offset = self.current_pos()
  emit_u32_le(self, 0)
  let next_ip_offset = self.current_pos()
  self.add_x86_rel32_fixup(target_block, disp_offset, next_ip_offset)
}

///|
fn CodeBuffer::x86_emit_setcc_r8(
  self : CodeBuffer,
  cond : RawCondition,
  dst : Int,
) -> Unit {
  // setcc r/m8: 0F 90+cc /r
  //
  // Note: low 8-bit register forms SPL/BPL/SIL/DIL require a REX prefix. We
  // always emit a REX prefix when needed to select those forms or r8b-r15b.
  let opcode = x86_cond_to_jcc_opcode(cond) + 0x10 // 0x90+cc
  let b = (dst >> 3) & 1
  if b != 0 || (dst & 7) >= 4 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(opcode)
  emit_modrm(self, 3, 0, dst)
}

///|
fn CodeBuffer::x86_emit_movzx_r32_r8(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // movzx r32, r/m8: 0F B6 /r (modrm mod=11 for register source)
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 || (src & 7) >= 4 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xB6)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_cqo(self : CodeBuffer) -> Unit {
  // cqo: sign-extend rax into rdx:rax (64-bit)
  self.emit_byte(0x48)
  self.emit_byte(0x99)
}

///|
fn CodeBuffer::x86_emit_cdq(self : CodeBuffer) -> Unit {
  // cdq: sign-extend eax into edx:eax (32-bit)
  self.emit_byte(0x99)
}

///|
fn CodeBuffer::x86_emit_idiv_r64(self : CodeBuffer, divisor : Int) -> Unit {
  // idiv r/m64: REX.W + F7 /7
  let b = (divisor >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 7, divisor)
}

///|
fn CodeBuffer::x86_emit_idiv_r32(self : CodeBuffer, divisor : Int) -> Unit {
  // idiv r/m32: F7 /7
  let b = (divisor >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 7, divisor)
}

///|
fn CodeBuffer::x86_emit_div_r64(self : CodeBuffer, divisor : Int) -> Unit {
  // div r/m64: REX.W + F7 /6
  let b = (divisor >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 6, divisor)
}

///|
fn CodeBuffer::x86_emit_div_r32(self : CodeBuffer, divisor : Int) -> Unit {
  // div r/m32: F7 /6
  let b = (divisor >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 6, divisor)
}

///|
fn CodeBuffer::x86_emit_mul_r64(self : CodeBuffer, src : Int) -> Unit {
  // mul r/m64: REX.W + F7 /4
  let b = (src >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 4, src)
}

///|
fn CodeBuffer::x86_emit_mul_r32(self : CodeBuffer, src : Int) -> Unit {
  let b = (src >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 4, src)
}

///|
fn CodeBuffer::x86_emit_imul1_r64(self : CodeBuffer, src : Int) -> Unit {
  // imul r/m64 (one-operand): REX.W + F7 /5
  let b = (src >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 5, src)
}

///|
fn CodeBuffer::x86_emit_imul1_r32(self : CodeBuffer, src : Int) -> Unit {
  let b = (src >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0xF7)
  emit_modrm(self, 3, 5, src)
}

///|
fn CodeBuffer::x86_emit_cmp_r_imm32(
  self : CodeBuffer,
  reg : Int,
  imm : Int,
) -> Unit {
  // cmp r/m64, imm32: REX.W + 81 /7 id
  let b = (reg >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0x81)
  emit_modrm(self, 3, 7, reg)
  emit_u32_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_cmp_r32_imm32(
  self : CodeBuffer,
  reg : Int,
  imm : Int,
) -> Unit {
  // cmp r/m32, imm32: 81 /7 id
  let b = (reg >> 3) & 1
  if b != 0 {
    emit_rex(self, 0, b)
  }
  self.emit_byte(0x81)
  emit_modrm(self, 3, 7, reg)
  emit_u32_le(self, imm)
}

///|
fn CodeBuffer::x86_emit_and_r_imm8_sxb64(
  self : CodeBuffer,
  reg : Int,
  imm8 : Int,
) -> Unit {
  // and r/m64, imm8: REX.W + 83 /4 ib (imm8 sign-extended)
  let b = (reg >> 3) & 1
  emit_rex_w(self, 0, b)
  self.emit_byte(0x83)
  emit_modrm(self, 3, 4, reg)
  self.emit_byte(imm8 & 255)
}

///|
fn CodeBuffer::x86_emit_cmovcc_rr(
  self : CodeBuffer,
  cond : RawCondition,
  dst : Int,
  src : Int,
) -> Unit {
  // cmovcc r64, r/m64: REX.W + 0F 40+cc /r
  let cc = x86_cond_to_jcc_opcode(cond) & 15
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x40 + cc)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_cmovcc_rr32(
  self : CodeBuffer,
  cond : RawCondition,
  dst : Int,
  src : Int,
) -> Unit {
  // cmovcc r32, r/m32: 0F 40+cc /r
  let cc = x86_cond_to_jcc_opcode(cond) & 15
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x40 + cc)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_movd_r32_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // movd r/m32, xmm: 66 0F 7E /r
  let r = (src_xmm >> 3) & 1
  let b = (dst >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x7E)
  emit_modrm(self, 3, src_xmm, dst)
}

///|
fn CodeBuffer::x86_emit_movd_xmm_r32(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // movd xmm, r/m32: 66 0F 6E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0x6E)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_movq_r64_xmm(
  self : CodeBuffer,
  dst : Int,
  src_xmm : Int,
) -> Unit {
  // movq r/m64, xmm: REX.W + 66 0F 7E /r
  let r = (src_xmm >> 3) & 1
  let b = (dst >> 3) & 1
  self.emit_byte(0x66)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x7E)
  emit_modrm(self, 3, src_xmm, dst)
}

///|
fn CodeBuffer::x86_emit_movq_xmm_r64(
  self : CodeBuffer,
  dst_xmm : Int,
  src : Int,
) -> Unit {
  // movq xmm, r/m64: REX.W + 66 0F 6E /r
  let r = (dst_xmm >> 3) & 1
  let b = (src >> 3) & 1
  self.emit_byte(0x66)
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0x6E)
  emit_modrm(self, 3, dst_xmm, src)
}

///|
fn CodeBuffer::x86_emit_cmp_rr(self : CodeBuffer, lhs : Int, rhs : Int) -> Unit {
  // cmp r/m64, r64: REX.W + 39 /r (cmp lhs, rhs)
  let r = (rhs >> 3) & 1
  let b = (lhs >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x39)
  emit_modrm(self, 3, rhs, lhs)
}

///|
fn CodeBuffer::x86_emit_cmp_rr32(
  self : CodeBuffer,
  lhs : Int,
  rhs : Int,
) -> Unit {
  // cmp r/m32, r32: 39 /r
  let r = (rhs >> 3) & 1
  let b = (lhs >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x39)
  emit_modrm(self, 3, rhs, lhs)
}

///|
fn CodeBuffer::x86_emit_test_rr(
  self : CodeBuffer,
  lhs : Int,
  rhs : Int,
) -> Unit {
  // test r/m64, r64: REX.W + 85 /r
  let r = (rhs >> 3) & 1
  let b = (lhs >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x85)
  emit_modrm(self, 3, rhs, lhs)
}

///|
fn CodeBuffer::x86_emit_test_rr32(
  self : CodeBuffer,
  lhs : Int,
  rhs : Int,
) -> Unit {
  // test r/m32, r32: 85 /r
  let r = (rhs >> 3) & 1
  let b = (lhs >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x85)
  emit_modrm(self, 3, rhs, lhs)
}

///|
fn CodeBuffer::x86_emit_bsr_r32_r32(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // bsr r32, r/m32: 0F BD /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  if r != 0 || b != 0 {
    emit_rex(self, r, b)
  }
  self.emit_byte(0x0F)
  self.emit_byte(0xBD)
  emit_modrm(self, 3, dst, src)
}

///|
fn CodeBuffer::x86_emit_bsr_r64_r64(
  self : CodeBuffer,
  dst : Int,
  src : Int,
) -> Unit {
  // bsr r64, r/m64: REX.W 0F BD /r
  let r = (dst >> 3) & 1
  let b = (src >> 3) & 1
  emit_rex_w(self, r, b)
  self.emit_byte(0x0F)
  self.emit_byte(0xBD)
  emit_modrm(self, 3, dst, src)
}

///|
/// Emit a trap instruction with a 16-bit payload.
///
/// Encoding: INT3 (0xCC) followed by imm16 (little-endian). The embedding trap
/// handler owns the payload policy.
fn CodeBuffer::x86_emit_trap_imm16(self : CodeBuffer, imm16 : Int) -> Unit {
  self.emit_byte(0xCC)
  self.emit_byte(imm16 & 255)
  self.emit_byte((imm16 >> 8) & 255)
}

///|
fn CodeBuffer::x86_emit_atomic_memory_prefix(
  self : CodeBuffer,
  width : @semantic.AccessWidth,
  reg : Int,
  base : Int,
) -> Unit {
  if width == W16 {
    self.emit_byte(0x66)
  }
  let r = (reg >> 3) & 1
  let b = (base >> 3) & 1
  if width == W64 {
    emit_rex_w(self, r, b)
  } else if r != 0 || b != 0 || (width == W8 && (reg & 7) >= 4) {
    emit_rex(self, r, b)
  }
}

///|
fn CodeBuffer::x86_emit_atomic_modrm(
  self : CodeBuffer,
  reg : Int,
  base : Int,
) -> Unit {
  emit_modrm(self, 2, reg, base)
  if (base & 7) == 4 {
    emit_sib(self, 0, 4, base)
  }
  emit_disp32(self, 0)
}

///|
fn CodeBuffer::x86_emit_lock_xadd(
  self : CodeBuffer,
  width : @semantic.AccessWidth,
  base : Int,
  reg : Int,
) -> Unit {
  self.emit_byte(0xF0)
  self.x86_emit_atomic_memory_prefix(width, reg, base)
  self.emit_byte(0x0F)
  self.emit_byte(if width == W8 { 0xC0 } else { 0xC1 })
  self.x86_emit_atomic_modrm(reg, base)
}

///|
fn CodeBuffer::x86_emit_xchg_memory(
  self : CodeBuffer,
  width : @semantic.AccessWidth,
  base : Int,
  reg : Int,
) -> Unit {
  self.x86_emit_atomic_memory_prefix(width, reg, base)
  self.emit_byte(if width == W8 { 0x86 } else { 0x87 })
  self.x86_emit_atomic_modrm(reg, base)
}

///|
fn CodeBuffer::x86_emit_lock_cmpxchg(
  self : CodeBuffer,
  width : @semantic.AccessWidth,
  base : Int,
  replacement : Int,
) -> Unit {
  self.emit_byte(0xF0)
  self.x86_emit_atomic_memory_prefix(width, replacement, base)
  self.emit_byte(0x0F)
  self.emit_byte(if width == W8 { 0xB0 } else { 0xB1 })
  self.x86_emit_atomic_modrm(replacement, base)
}

///|
fn CodeBuffer::x86_emit_mfence(self : CodeBuffer) -> Unit {
  self.emit_byte(0x0F)
  self.emit_byte(0xAE)
  self.emit_byte(0xF0)
}