text: """ SSE2 instructions """
  
  import struct
  from ..isa import Isa
  from ..encoding import Operand, Syntax, Instruction, Constructor
  from .instructions import rm64_modes, rm32_modes, bits64  # , bits32
  from .instructions import OpcodeToken
  from .instructions import PrefixToken
  from .instructions import RexToken, ModRmToken, SibToken
  from .instructions import Imm32Token, Imm8Token
  from .instructions import RmMem, RmMemDisp, RmReg32, RmReg64, RmAbs, MovAdr
  from .instructions import Jb, Jbe, Ja, Jae, Je, Jne, Js, NearJump
  from .instructions import SubImm, AddImm
  from .registers import XmmRegisterSingle, XmmRegisterDouble
  from .registers import Register64, Register32, rsp, eax, rax
  from ..generic_instructions import ArtificialInstruction, RegisterUseDef
  
  
  sse1_isa = Isa()
  sse2_isa = Isa()
  
  
  class SseInstruction(Instruction):
      tokens = [
          PrefixToken,
          RexToken,
          OpcodeToken,
          ModRmToken,
          SibToken,
          Imm8Token,
          Imm32Token,
      ]
  
      def set_user_patterns(self, tokens):
          # TODO: Improve this way of setting 'r':
          tokens.set_field("r", (self.r.num & 8) >> 3)
          tokens.set_field("reg", self.r.num & 0x7)
  
      def encode(self):
          """ Use a custom encode... """
          # TODO: find a better way for this!
          # 1. Set patterns:
          tokens = self.get_tokens()
          self.set_all_patterns(tokens)
  
          # 2. Encode:
          r = bytes()
  
          # prefix:
          if tokens[0].prefix != 0:
              r += tokens[0].encode()
  
          # Rex prefix:
          if tokens[1][0:4] > 0:
              r += tokens[1].encode()
  
          # 0f:
          r += bytes([0x0F])
  
          # opcode:
          r += tokens[2].encode()
  
          # rm byte:
          r += tokens[3].encode()
  
          # Encode sib byte:
          if tokens[3].mod != 3 and tokens[3].rm == 4:
              r += tokens[4].encode()
  
          # Encode displacement bytes:
          if tokens[3].mod == 1:
              r += tokens[5].encode()
          if tokens[3].mod == 2:
              r += tokens[6].encode()
  
          # Rip relative addressing mode with disp32
          if tokens[3].mod == 0 and tokens[3].rm == 5:
              r += tokens[6].encode()
  
          # sib byte and ...
          if tokens[3].mod == 0 and tokens[3].rm == 4:
              if tokens[4].base == 5:
                  r += tokens[6].encode()
          return r
  
  
  class Sse1Instruction(SseInstruction):
      """ Sse1 instruction """
  
      isa = sse1_isa
  
  
  class Sse2Instruction(SseInstruction):
      """ Sse2 instruction """
  
      isa = sse2_isa
  
  
  class RmXmmReg(Constructor):
      """ Xmm register access """
  
      reg_rm = Operand("reg_rm", XmmRegisterDouble, read=True)
      syntax = Syntax([reg_rm])
      patterns = {"mod": 3}
  
      def set_user_patterns(self, tokens):
          # TODO: Improve this way of setting 'r':
          tokens.set_field("b", (self.reg_rm.num & 8) >> 3)
          tokens.set_field("rm", self.reg_rm.num & 0x7)
  
  
  RmXmmRegDouble = RmXmmReg
  
  
  class RmXmmRegSingle(Constructor):
      """ Xmm register access """
  
      reg_rm = Operand("reg_rm", XmmRegisterSingle, read=True)
      syntax = Syntax([reg_rm])
      patterns = {"mod": 3}
  
      def set_user_patterns(self, tokens):
          # TODO: Improve this way of setting 'r':
          tokens.set_field("b", (self.reg_rm.num & 8) >> 3)
          tokens.set_field("rm", self.reg_rm.num & 0x7)
  
  
  xmm_rm_modes = (RmXmmReg, RmMem, RmMemDisp, RmAbs)
  xmm_double_rm_modes = (RmXmmRegDouble, RmMem, RmMemDisp, RmAbs)
  xmm_single_rm_modes = (RmXmmRegSingle, RmMem, RmMemDisp, RmAbs)
  
  
  # TODO: packed single values
  # class Movups(Sse1Instruction):
  #     """ Move unaligned packed single-fp values """
  
  #     r = Operand("r", XmmRegister, write=True)
  #     rm = Operand("rm", xmm_rm_modes)
  #     syntax = Syntax(["movups", " ", r, ",", " ", rm])
  #     patterns = {"opcode": 0x10}
  
  
  class Movss(Sse1Instruction):
      """ Move scalar single-fp value """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_single_rm_modes)
      syntax = Syntax(["movss", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF3, "opcode": 0x10}
  
  
  # TODO: packed double values
  # class Movupd(Sse2Instruction):
  #     """ Move unaligned packed double-fp values """
  
  #     r = Operand("r", XmmRegister, write=True)
  #     rm = Operand("rm", xmm_rm_modes)
  #     syntax = Syntax(["movupd", " ", r, ",", " ", rm])
  #     patterns = {"prefix": 0x66, "opcode": 0x10}
  
  
  class Movsd(Sse2Instruction):
      """ Move scalar double-fp value """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_double_rm_modes)
      syntax = Syntax(["movsd", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF2, "opcode": 0x10}
  
  
  class Movss2(Sse1Instruction):
      """ Move scalar single-fp value """
  
      rm = Operand("rm", xmm_single_rm_modes)
      r = Operand("r", XmmRegisterSingle, read=True)
      syntax = Syntax(["movss", " ", rm, ",", " ", r], priority=1)
      patterns = {"prefix": 0xF3, "opcode": 0x11}
  
  
  class Movsd2(Sse2Instruction):
      """ Move scalar double-fp value """
  
      rm = Operand("rm", xmm_double_rm_modes)
      r = Operand("r", XmmRegisterDouble, read=True)
      syntax = Syntax(["movsd", " ", rm, ",", " ", r], priority=1)
      patterns = {"prefix": 0xF2, "opcode": 0x11}
  
  
  class Addss(Sse1Instruction):
      """ Add scalar single-fp value """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      patterns = {"prefix": 0xF3, "opcode": 0x58}
      syntax = Syntax(["addss", " ", r, ",", " ", rm])
  
  
  class Addsd(Sse2Instruction):
      """ Add scalar double-fp value """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      patterns = {"prefix": 0xF2, "opcode": 0x58}
      syntax = Syntax(["addsd", " ", r, ",", " ", rm])
  
  
  class Subss(Sse1Instruction):
      """ Sub scalar single-fp value """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      patterns = {"prefix": 0xF3, "opcode": 0x5C}
      syntax = Syntax(["subss", " ", r, ",", " ", rm])
  
  
  class Subsd(Sse2Instruction):
      """ Sub scalar double-fp value """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      patterns = {"prefix": 0xF2, "opcode": 0x5C}
      syntax = Syntax(["subsd", " ", r, ",", " ", rm])
  
  
  class Mulss(Sse1Instruction):
      """ Multiply scalar single-fp value """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      patterns = {"prefix": 0xF3, "opcode": 0x59}
      syntax = Syntax(["mulss", " ", r, ",", " ", rm])
  
  
  class Mulsd(Sse2Instruction):
      """ Multiply scalar double-fp value """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      patterns = {"prefix": 0xF2, "opcode": 0x59}
      syntax = Syntax(["mulsd", " ", r, ",", " ", rm])
  
  
  class Divss(Sse1Instruction):
      """ Divide scalar single-fp value """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      patterns = {"prefix": 0xF3, "opcode": 0x5E}
      syntax = Syntax(["divss", " ", r, ",", " ", rm])
  
  
  class Divsd(Sse2Instruction):
      """ Divide scalar double-fp value """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      patterns = {"prefix": 0xF2, "opcode": 0x5E}
      syntax = Syntax(["divsd", " ", r, ",", " ", rm])
  
  
  class Cvtss2si(Sse1Instruction):
      """ Convert scalar single-fp to integer """
  
      r = Operand("r", Register64, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      syntax = Syntax(["cvtss2si", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF3, "opcode": 0x2D, "w": 1}
  
  
  class Cvtss2si_32(Sse1Instruction):
      """ Convert scalar single-fp to integer """
  
      r = Operand("r", Register32, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      syntax = Syntax(["cvtss2si", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF3, "opcode": 0x2D, "w": 0}
  
  
  class Cvtsd2si(Sse2Instruction):
      """ Convert scalar double-fp to integer """
  
      r = Operand("r", Register64, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      syntax = Syntax(["cvtsd2si", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF2, "opcode": 0x2D, "w": 1}
  
  
  class Cvtsd2si_32(Sse2Instruction):
      """ Convert scalar double-fp to integer """
  
      r = Operand("r", Register32, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      syntax = Syntax(["cvtsd2si", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF2, "opcode": 0x2D, "w": 0}
  
  
  class Cvtsi2ss(Sse1Instruction):
      """ Convert integer to scalar single-fp """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", rm64_modes, read=True)
      syntax = Syntax(["cvtsi2ss", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF3, "opcode": 0x2A, "w": 1}
  
  
  class Cvtsi2ss_32(Sse1Instruction):
      """ Convert integer to scalar single-fp """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", rm32_modes, read=True)
      syntax = Syntax(["cvtsi2ss", " ", r, ",", " ", rm], priority=2)
      patterns = {"prefix": 0xF3, "opcode": 0x2A, "w": 0}
  
  
  class Cvtsi2sd(Sse2Instruction):
      """ Convert integer to scalar double-fp """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", rm64_modes, read=True)
      syntax = Syntax(["cvtsi2sd", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF2, "opcode": 0x2A, "w": 1}
  
  
  class Cvtsi2sd_32(Sse2Instruction):
      """ Convert integer to scalar double-fp """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", rm32_modes, read=True)
      syntax = Syntax(["cvtsi2sd", " ", r, ",", " ", rm], priority=2)
      patterns = {"prefix": 0xF2, "opcode": 0x2A, "w": 0}
  
  
  class Cvtss2sd(Sse2Instruction):
      """ Convert scalar single-fp to scalar double-fp """
  
      r = Operand("r", XmmRegisterDouble, write=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      syntax = Syntax(["cvtss2sd", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF3, "opcode": 0x5A}
  
  
  class Cvtsd2ss(Sse2Instruction):
      """ Convert scalar double-fp to scalar single-fp """
  
      r = Operand("r", XmmRegisterSingle, write=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      syntax = Syntax(["cvtsd2ss", " ", r, ",", " ", rm])
      patterns = {"prefix": 0xF2, "opcode": 0x5A}
  
  
  class Comiss(Sse1Instruction):
      """ Scalar compare single-fp values """
  
      r = Operand("r", XmmRegisterSingle, read=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      syntax = Syntax(["comiss", " ", r, ",", " ", rm])
      patterns = {"opcode": 0x2F}
  
  
  class Ucomiss(Sse1Instruction):
      """ Unordered scalar compare single-fp values """
  
      r = Operand("r", XmmRegisterSingle, read=True)
      rm = Operand("rm", xmm_single_rm_modes, read=True)
      syntax = Syntax(["ucomiss", " ", r, ",", " ", rm])
      patterns = {"opcode": 0x2E}
  
  
  class Ucomisd(Sse2Instruction):
      """ Unordered scalar compare double-fp values """
  
      r = Operand("r", XmmRegisterDouble, read=True)
      rm = Operand("rm", xmm_double_rm_modes, read=True)
      syntax = Syntax(["ucomisd", " ", r, ",", " ", rm])
      patterns = {"prefix": 0x66, "opcode": 0x2E}
  
  
  class SsePseudoInstruction(ArtificialInstruction):
      isa = sse1_isa
  
  
  class PushXmmRegisterDouble(SsePseudoInstruction):
      r = Operand("r", XmmRegisterDouble, read=True)
      syntax = Syntax(["push", " ", r])
  
      def render(self):
          # sub rsp, 8
          yield SubImm(rsp, 8)
  
          # movdqu [rsp], r
          yield Movsd2(RmMem(rsp), self.r)
  
  
  class PopXmmRegisterDouble(SsePseudoInstruction):
      r = Operand("r", XmmRegisterDouble, write=True)
      syntax = Syntax(["pop", " ", r])
  
      def render(self):
          # movdqu [rsp], r
          yield Movsd(self.r, RmMem(rsp))
  
          # add rsp, 8
          yield AddImm(rsp, 8)
  
  
  class PushXmmRegisterSingle(SsePseudoInstruction):
      r = Operand("r", XmmRegisterSingle, read=True)
      syntax = Syntax(["push", " ", r])
  
      def render(self):
          # sub rsp, 4
          yield SubImm(rsp, 4)
  
          # movdqu [rsp], r
          yield Movss2(RmMem(rsp), self.r)
  
  
  class PopXmmRegisterSingle(SsePseudoInstruction):
      r = Operand("r", XmmRegisterSingle, write=True)
      syntax = Syntax(["pop", " ", r])
  
      def render(self):
          # movdqu [rsp], r
          yield Movss(self.r, RmMem(rsp))
  
          # add rsp, 4
          yield AddImm(rsp, 4)
  
  
  @sse2_isa.pattern("regfp32", "F64TOF32(rmf64)", size=6, cycles=3, energy=3)
  def pattern_f64tof32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Cvtsd2ss(dst, c0))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "F32TOF64(rmf32)", size=6, cycles=3, energy=3)
  def pattern_f32tof64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Cvtss2sd(dst, c0))
      return dst
  
  
  # I64:
  @sse1_isa.pattern("reg64", "F32TOI64(rmf32)", size=6, cycles=2, energy=2)
  @sse1_isa.pattern("reg64", "F32TOU64(rmf32)", size=6, cycles=2, energy=2)
  def pattern_f32toi64(context, tree, c0):
      dst = context.new_reg(Register64)
      context.emit(Cvtss2si(dst, c0))
      return dst
  
  
  @sse2_isa.pattern("reg64", "F64TOI64(rmf64)", size=6, cycles=3, energy=3)
  @sse2_isa.pattern("reg64", "F64TOU64(rmf64)", size=6, cycles=3, energy=3)
  def pattern_f64toi64(context, tree, c0):
      dst = context.new_reg(Register64)
      context.emit(Cvtsd2si(dst, c0))
      return dst
  
  
  # See also: https://stackoverflow.com/questions/11406654/
  # how-to-convert-an-unsigned-integer-to-floating-point-in-x86-32-bit-assembly
  @sse1_isa.pattern("regfp32", "I64TOF32(reg64)", size=6, cycles=2, energy=2)
  def pattern_i64tof32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Cvtsi2ss(dst, RmReg64(c0)))
      return dst
  
  
  @sse1_isa.pattern("regfp32", "U64TOF32(reg64)", size=6, cycles=2, energy=2)
  def pattern_u64tof32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
      # Special case if value is bigger than 2**63.
      # Strategy:
      # Divide in half, convert to float and then double the value
      label_special = context.new_label()
      label_end = context.new_label()
      context.emit(bits64.TestRmReg(RmReg64(c0), c0))  # Check sign bit
      context.emit(Js(label_special.name))  # If larger than 2**63
  
      # Happy case:
      context.emit(Cvtsi2ss(dst, RmReg64(c0)))
      context.emit(NearJump(label_end.name))
  
      # Special case:
      context.emit(label_special)
      tmp = context.new_reg(Register64)
      context.move(tmp, c0)
      context.emit(bits64.ShrRm(RmReg64(tmp)))  # Divide in half
      context.emit(Cvtsi2ss(dst, RmReg64(tmp)))  # Convert
      context.emit(Addss(dst, RmXmmRegSingle(dst)))  # Double
      context.emit(label_end)
      return dst
  
  
  @sse2_isa.pattern("regfp64", "I64TOF64(reg64)", size=6, cycles=3, energy=3)
  def pattern_i64tof64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Cvtsi2sd(dst, RmReg64(c0)))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "U64TOF64(reg64)", size=6, cycles=3, energy=3)
  def pattern_u64tof64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
      # Special case if value is bigger than 2**63.
      # Strategy:
      # Divide in half, convert to float and then double the value
      label_special = context.new_label()
      label_end = context.new_label()
      context.emit(bits64.TestRmReg(RmReg64(c0), c0))  # Check sign bit
      context.emit(Js(label_special.name))  # If larger than 2**63
  
      # Happy case:
      context.emit(Cvtsi2sd(dst, RmReg64(c0)))
      context.emit(NearJump(label_end.name))
  
      # Special case:
      context.emit(label_special)
      tmp = context.new_reg(Register64)
      context.move(tmp, c0)
      context.emit(bits64.ShrRm(RmReg64(tmp)))  # Divide in half
      context.emit(Cvtsi2sd(dst, RmReg64(tmp)))  # Convert
      context.emit(Addsd(dst, RmXmmRegDouble(dst)))  # Double
      context.emit(label_end)
      return dst
  
  
  # I32:
  @sse1_isa.pattern("reg32", "F32TOI32(rmf32)", size=6, cycles=2, energy=2)
  @sse1_isa.pattern("reg32", "F32TOU32(rmf32)", size=6, cycles=2, energy=2)
  def pattern_f32toi32(context, tree, c0):
      dst = context.new_reg(Register32)
      context.emit(Cvtss2si_32(dst, c0))
      return dst
  
  
  @sse2_isa.pattern("reg32", "F64TOI32(rmf64)", size=6, cycles=3, energy=3)
  @sse2_isa.pattern("reg32", "F64TOU32(rmf64)", size=6, cycles=3, energy=3)
  def pattern_f64toi32(context, tree, c0):
      dst = context.new_reg(Register32)
      context.emit(Cvtsd2si_32(dst, c0))
      return dst
  
  
  @sse1_isa.pattern("regfp32", "I32TOF32(reg32)", size=6, cycles=2, energy=2)
  def pattern_i32tof32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Cvtsi2ss_32(dst, RmReg32(c0)))
      return dst
  
  
  @sse1_isa.pattern("regfp32", "U32TOF32(reg32)", size=6, cycles=2, energy=2)
  def pattern_u32tof32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
  
      # Special case for unsigned 32 bits integers
      context.emit(bits64.XorRmReg(RmReg64(rax), rax))
      context.move(eax, c0)
  
      defu2 = RegisterUseDef()
      defu2.add_use(eax)
      defu2.add_def(rax)
      context.emit(defu2)
  
      context.emit(Cvtsi2ss(dst, RmReg64(rax)))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "I32TOF64(reg32)", size=6, cycles=3, energy=3)
  def pattern_i32tof64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Cvtsi2sd_32(dst, RmReg32(c0)))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "U32TOF64(reg32)", size=6, cycles=3, energy=3)
  def pattern_u32tof64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
  
      # Special case for unsigned 32 bits integers
      context.emit(bits64.XorRmReg(RmReg64(rax), rax))
      context.move(eax, c0)
  
      defu2 = RegisterUseDef()
      defu2.add_use(eax)
      defu2.add_def(rax)
      context.emit(defu2)
  
      context.emit(Cvtsi2sd(dst, RmReg64(rax)))
      return dst
  
  
  @sse1_isa.pattern("regfp32", "CONSTF32", size=8, cycles=6, energy=2)
  def pattern_const_f32(context, tree):
      float_const = struct.pack("f", tree.value)
      const_label = context.frame.add_constant(float_const)
      label_addr = context.new_reg(Register64)
      context.emit(MovAdr(label_addr, const_label))
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Movss(dst, RmMem(label_addr)))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "CONSTF64", size=8, cycles=9, energy=4)
  def pattern_const_f64(context, tree):
      float_const = struct.pack("d", tree.value)
      const_label = context.frame.add_constant(float_const)
      label_addr = context.new_reg(Register64)
      context.emit(MovAdr(label_addr, const_label))
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, RmMem(label_addr)))
      return dst
  
  
  @sse2_isa.pattern("regfp64", "NEGF64(rmf64)", size=8, cycles=9, energy=4)
  def pattern_neg_f64(context, tree, c0):
      """ Multiply by -1 """
      float_const = struct.pack("d", -1)
      const_label = context.frame.add_constant(float_const)
      label_addr = context.new_reg(Register64)
      context.emit(MovAdr(label_addr, const_label))
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, c0))
      context.emit(Mulsd(dst, RmMem(label_addr)))
      return dst
  
  
  @sse1_isa.pattern("regfp32", "NEGF32(rmf32)", size=8, cycles=9, energy=4)
  def pattern_neg_f32(context, tree, c0):
      """ Multiply by -1 """
      float_const = struct.pack("f", -1)
      const_label = context.frame.add_constant(float_const)
      label_addr = context.new_reg(Register64)
      context.emit(MovAdr(label_addr, const_label))
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Movss(dst, c0))
      context.emit(Mulss(dst, RmMem(label_addr)))
      return dst
  
  
  @sse1_isa.pattern(
      "regfp32", "ADDF32(regfp32, rmf32)", size=6, cycles=2, energy=2
  )
  def pattern_addf32(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterSingle)
      context.move(dst, c0)
      context.emit(Addss(dst, c1))
      return dst
  
  
  @sse2_isa.pattern(
      "regfp64", "ADDF64(regfp64, rmf64)", size=6, cycles=4, energy=3
  )
  def pattern_addf64(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, RmXmmRegDouble(c0)))
      context.emit(Addsd(dst, c1))
      return dst
  
  
  @sse1_isa.pattern(
      "regfp32", "SUBF32(regfp32, rmf32)", size=6, cycles=2, energy=2
  )
  def pattern_sub_f32(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterSingle)
      context.move(dst, c0)
      context.emit(Subss(dst, c1))
      return dst
  
  
  @sse2_isa.pattern(
      "regfp64", "SUBF64(regfp64, rmf64)", size=6, cycles=3, energy=3
  )
  def pattern_sub_f64(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, RmXmmRegDouble(c0)))
      context.emit(Subsd(dst, c1))
      return dst
  
  
  @sse1_isa.pattern(
      "regfp32", "MULF32(regfp32, rmf32)", size=6, cycles=2, energy=2
  )
  def pattern_mul_f32(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterSingle)
      context.move(dst, c0)
      context.emit(Mulss(dst, c1))
      return dst
  
  
  @sse2_isa.pattern(
      "regfp64", "MULF64(regfp64, rmf64)", size=6, cycles=3, energy=3
  )
  def pattern_mul_f64(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, RmXmmRegDouble(c0)))
      context.emit(Mulsd(dst, c1))
      return dst
  
  
  @sse1_isa.pattern(
      "regfp32", "DIVF32(regfp32, rmf32)", size=6, cycles=2, energy=2
  )
  def pattern_div_f32(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterSingle)
      context.move(dst, c0)
      context.emit(Divss(dst, c1))
      return dst
  
  
  @sse2_isa.pattern(
      "regfp64", "DIVF64(regfp64, rmf64)", size=6, cycles=4, energy=3
  )
  def pattern_div_f64(context, tree, c0, c1):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, RmXmmRegDouble(c0)))
      context.emit(Divsd(dst, c1))
      return dst
  
  
  @sse1_isa.pattern("stm", "MOVF32(regfp32)", size=3, cycles=2, energy=2)
  def pattern_mov_f32(context, tree, c0):
      context.move(tree.value, c0)
  
  
  @sse2_isa.pattern("stm", "MOVF64(regfp64)", size=3, cycles=3, energy=3)
  def pattern_mov_f64(context, tree, c0):
      context.move(tree.value, c0)
  
  
  @sse2_isa.pattern("regfp64", "REGF64", size=0, cycles=0, energy=0)
  @sse1_isa.pattern("regfp32", "REGF32", size=0, cycles=0, energy=0)
  def pattern_reg_fp(context, tree):
      return tree.value
  
  
  @sse1_isa.pattern("stm", "STRF32(mem64, regfp32)", size=6, cycles=2, energy=2)
  def pattern_str_f32(context, tree, c0, c1):
      context.emit(Movss2(c0, c1))
  
  
  @sse2_isa.pattern("stm", "STRF64(mem64, regfp64)", size=6, cycles=3, energy=3)
  def pattern_str_f64(context, tree, c0, c1):
      context.emit(Movsd2(c0, c1))
  
  
  @sse1_isa.pattern("regfp32", "rmf32", size=6, cycles=2, energy=2)
  def pattern_ldr_f32(context, tree, c0):
      dst = context.new_reg(XmmRegisterSingle)
      context.emit(Movss(dst, c0))
      return dst
  
  
  @sse1_isa.pattern("rmf32", "LDRF32(mem64)", size=1, cycles=2, energy=2)
  def pattern_rmf32_ldr_f32(context, tree, c0):
      return c0
  
  
  @sse2_isa.pattern("rmf32", "regfp32", size=1, cycles=1, energy=1)
  def pattern_rmf32_f32(context, tree, c0):
      return RmXmmRegSingle(c0)
  
  
  @sse2_isa.pattern("regfp64", "rmf64", size=6, cycles=3, energy=3)
  def pattern_ldr_f64(context, tree, c0):
      dst = context.new_reg(XmmRegisterDouble)
      context.emit(Movsd(dst, c0))
      return dst
  
  
  @sse2_isa.pattern("rmf64", "LDRF64(mem64)", size=1, cycles=2, energy=2)
  def pattern_rmf64_ldr_f64(context, tree, c0):
      return c0
  
  
  @sse2_isa.pattern("rmf64", "regfp64", size=1, cycles=1, energy=1)
  def pattern_rmf64_f64(context, tree, c0):
      return RmXmmRegDouble(c0)
  
  
  jump_opnames = {"<": Jb, ">": Ja, "==": Je, "!=": Jne, ">=": Jae, "<=": Jbe}
  
  
  def pattern_cjmp(context, value):
      op, yes_label, no_label = value
      Bop = jump_opnames[op]
      jmp_ins = NearJump(no_label.name, jumps=[no_label])
      context.emit(Bop(yes_label.name, jumps=[yes_label, jmp_ins]))
      context.emit(jmp_ins)
  
  
  @sse1_isa.pattern(
      "stm", "CJMPF32(regfp32,regfp32)", size=6, cycles=3, energy=3
  )
  def pattern_cjmp_f32(context, tree, c0, c1):
      context.emit(Ucomiss(c0, RmXmmRegSingle(c1)))
      pattern_cjmp(context, tree.value)
  
  
  @sse1_isa.pattern(
      "stm", "CJMPF64(regfp64,regfp64)", size=6, cycles=3, energy=3
  )
  def pattern_cjmp_f64(context, tree, c0, c1):
      context.emit(Ucomisd(c0, RmXmmRegDouble(c1)))
      pattern_cjmp(context, tree.value)
  