unit kern_jit_ops_sse;

{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}

interface

implementation

uses
 kern_thr,
 x86_fpdbgdisas,
 x86_jit,
 kern_jit_ops,
 kern_jit_asm,
 kern_jit_ctx;

var
 _SSE4aSupport:Boolean=False;

procedure _ins_op(var op:DWORD;i:Byte); inline;
begin
 case op of
  $00..$FF:
   begin
    op:=op or (DWORD(i) shl 8);
   end;
  $100..$FFFF:
   begin
    op:=op or (DWORD(i) shl 16);
   end;
  else
   begin
    op:=op or (DWORD(i) shl 24);
   end;
 end;
end;

procedure _ins_op(var desc:t_op_desc;i:Byte); inline;
begin
 _ins_op(desc.mem_reg.op,i);
 _ins_op(desc.reg_mem.op,i);
 _ins_op(desc.reg_imm.op,i);
 _ins_op(desc.reg_im8.op,i);
end;

procedure op_emit2_simd(var ctx:t_jit_context2;const desc:t_op_desc);
var
 tmp:t_op_desc;
begin
 tmp:=desc;

 case ctx.dis.SimdOpcode of
  soNone:;
    so66:_ins_op(tmp,$66);
    soF2:_ins_op(tmp,$F2);
    soF3:_ins_op(tmp,$F3);
  else
    Assert(False);
 end;

 op_emit2(ctx,tmp);
end;

procedure op_emit2_simd_mem_reg(var ctx:t_jit_context2;hint:t_op_hint);
const
 desc:t_op_desc=(
  mem_reg:(op:0;opt:[not_os8,not_prefix]);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:0;opt:[not_os8,not_prefix]);
  hint:[his_mri8,his_unbs]; //TODO: check balanced
 );
var
 tmp:t_op_desc;
begin
 tmp:=desc;
 tmp.mem_reg.op:=ctx.dis.opcode;
 tmp.reg_im8.op:=ctx.dis.opcode;
 tmp.hint:=tmp.hint+hint;

 op_emit2_simd(ctx,tmp);
end;

procedure op_emit2_simd_reg_mem(var ctx:t_jit_context2;hint:t_op_hint);
const
 desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:0;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:0;opt:[not_os8,not_prefix]);
  hint:[his_unbs]; //TODO: check balanced
 );
var
 tmp:t_op_desc;
begin
 tmp:=desc;
 tmp.reg_mem.op:=ctx.dis.opcode;
 tmp.reg_im8.op:=ctx.dis.opcode;
 tmp.hint:=tmp.hint+hint;

 op_emit2_simd(ctx,tmp);
end;

//

procedure op_reg_mem_rw(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_reg_mem(ctx,[his_rw]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_reg_mem_wo(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_reg_mem(ctx,[his_wo]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_mem_reg_wo(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_mem_reg(ctx,[his_wo]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_reg_mem_ro(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_reg_mem(ctx,[his_ro]);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

procedure op_mem_reg_mov_wo(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_mem_reg(ctx,[his_mov,his_wo]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_reg_mem_mov_wo(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2_simd_reg_mem(ctx,[his_mov,his_wo]);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 movsd_desc:t_op_desc=(
  mem_reg:(op:$F20F11;opt:[not_os8,not_prefix]);
  reg_mem:(op:$F20F10;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_unbs];
 );

procedure op_movsd(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2(ctx,movsd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 movss_desc:t_op_desc=(
  mem_reg:(op:$F30F11;opt:[not_os8,not_prefix]);
  reg_mem:(op:$F30F10;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_unbs];
 );

procedure op_movss(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2(ctx,movss_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 mov_dq_desc:t_op_desc=(
  mem_reg:(op:$0F7F;opt:[not_os8,not_prefix]);
  reg_mem:(op:$0F6F;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

 //NP 0F 6E         /r MOVD mm, r/m32
 //NP REX.W + 0F 6E /r MOVQ mm, r/m64
 //NP 0F 7E         /r MOVD r/m32, mm
 //NP REX.W + 0F 7E /r MOVQ r/m64, mm
 //66 0F 6E         /r MOVD xmm, r/m32
 //66 REX.W 0F 6E   /r MOVQ xmm, r/m64
 //66 0F 7E         /r MOVD r/m32, xmm
 //66 REX.W 0F 7E   /r MOVQ r/m64, xmm

 //NP 0F 6F /r MOVQ mm, mm/m64
 //NP 0F 7F /r MOVQ mm/m64, mm

 //F3 0F 7E /r MOVQ xmm1, xmm2/m64
 //66 0F D6 /r MOVQ xmm2/m64, xmm1

procedure op_movd_dq(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin

  case ctx.dis.opcode of
   $0F6E:op_emit2_simd_reg_mem(ctx,[his_mov,his_wo]);
   $0F7F:op_emit2_simd(ctx,mov_dq_desc); //mem_reg
   $0F6F:op_emit2_simd(ctx,mov_dq_desc); //reg_mem;
   $0FD6:op_emit2_simd_mem_reg(ctx,[his_mov,his_wo]);

   $0F7E:
    if (ctx.dis.SimdOpcode=soF3) then
    begin
     op_emit2_simd_reg_mem(ctx,[his_mov,his_wo]);
    end else
    begin
     op_emit2_simd_mem_reg(ctx,[his_mov,his_wo]);
    end;

   else
    Assert(false);
  end;

 end else
 begin
  add_orig(ctx);
 end;
end;

const
 movdqa_desc:t_op_desc=(
  mem_reg:(op:$660F7F;opt:[not_os8,not_prefix]);
  reg_mem:(op:$660F6F;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_align];
 );

procedure op_movdqa(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2(ctx,movdqa_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 movdqu_desc:t_op_desc=(
  mem_reg:(op:$F30F7F;opt:[not_os8,not_prefix]);
  reg_mem:(op:$F30F6F;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

procedure op_movdqu(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2(ctx,movdqu_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 movu_ps_pd_desc:t_op_desc=(
  mem_reg:(op:$0F11;opt:[not_os8,not_prefix]);
  reg_mem:(op:$0F10;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

procedure op_movu_ps_pd(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2_simd(ctx,movu_ps_pd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 mova_ps_pd_desc:t_op_desc=(
  mem_reg:(op:$0F29;opt:[not_os8,not_prefix]);
  reg_mem:(op:$0F28;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_align];
 );

procedure op_mova_ps_pd(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2_simd(ctx,mova_ps_pd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 movntdqa_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$660F382A;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_align];
 );

procedure op_movntdqa(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2(ctx,movntdqa_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//SSE4a

{
AMD64 Architecture
Programmer’s Manual
Volume 4:
128-Bit and 256-Bit
Media Instructions
}

procedure op_movnt_sd_ss(var ctx:t_jit_context2);
begin
 op_emit2_simd_mem_reg(ctx,[his_mov,his_wo]);
end;

{
 note: xmm0[64:127] -> will be cleared so that temp values can be saved

 a = xmm0[0:63]
 b = xmm1[0:63]

 mask = 0xFFFFFFFFFFFFFFFF;

 m = mask shl (64 - len);
 m = m    shr (64 - len);
 m = m    shl idx;

 b = b shl idx;
 b = b and m;

 a = (not m) and a;
 a = a or b;

 xmm0[0  :63] = a;
 xmm0[64:127] = 0;
}

procedure op_insertq(var ctx:t_jit_context2);
var
 imm:Int64;
 len,idx:Byte;
 mask:QWORD;
 xmm_a,xmm_b:TRegValue;
 a,b,m,s,ta:TRegValue;

 procedure clear_hi; inline;
 begin
  with ctx.builder do
  begin
   //clear hi 64bit
   ta:=new_reg_size(a,os32);
   xorq(ta,ta);
   pinsrq(xmm_a,a,1);
  end;
 end;

 procedure save_flags; inline;
 begin
  with ctx.builder do
  begin
   movq  (a,rax);       // save rax
   laxf;                // ax = flags
   pinsrq(xmm_a,rax,1); // xmm_a[64:127] = rax
   movq  (rax,a);       // restore rax
  end;
 end;

 procedure restore_flags; inline;
 begin
  with ctx.builder do
  begin
   movq  (a,rax);         // save rax
   pextrq(rax,xmm_a,1);   // rax = xmm_a[64:127]
   sahf;                  // flags = ax
   movq  (rax,a);         // restore rax
  end;
 end;

begin

 xmm_a:=new_reg(ctx.din.Operand[1]);
 xmm_b:=new_reg(ctx.din.Operand[2]);

 a:=r_tmp0;
 b:=r_tmp1;
 m:=r_thrd;

 with ctx.builder do
 begin

  if (ctx.din.OperCnt=4) then
  begin
   //insertq xmm0,xmm1,$10,$30

   imm:=0;
   GetTargetOfs(ctx.din,ctx.code,3,imm);
   len:=imm;

   imm:=0;
   GetTargetOfs(ctx.din,ctx.code,4,imm);
   idx:=imm;

   mask:=QWORD($FFFFFFFFFFFFFFFF);
   //shift automatically masks at [0:5]
   mask:=mask shl (64 - len); //clear hi
   mask:=mask shr (64 - len); //restore
   mask:=mask shl idx;        //shift

   if (mask=0) then
   begin
    //special case

    clear_hi;

    //nop
    Exit;
   end;

   if (mask=QWORD($FFFFFFFFFFFFFFFF)) then
   begin
    //special case

    //b = xmm1[0:63]
    movqx(b,xmm_b);

    //xmm0[0:63] = b;
    pinsrq(xmm_a,b,0);

    clear_hi;

    Exit;
   end;

   save_flags;

   op_set_reg_imm(ctx,m,mask);

   //b = xmm1[0:63]
   movqx(b,xmm_b);

   if (idx<>0) then
   begin
    shli8(b,idx); // b = b shl idx
   end;

  end else
  begin
   //insertq xmm0,xmm1

   save_flags;

   //save rcx
   s:=a;
   a:=rcx;
   movq   (s,a);

   //PEXTRQ r/m64, xmm2, imm8
   pextrq (a,xmm_b,1); // a:=xmm_b[64:127]; -> len:[0:5] pos:[8:13]

   ta:=new_reg_size(a,os8);

   notq     (ta);        // a[0:7] = -len-1
   addi     (ta,65);     // a[0:7] = ((-len-1) + 1 + 64)

   movi   (m,-1);      // m = 0xFFFFFFFFFFFFFFFF  (sign extended to 64-bit)

   shl_cl (m);         // m = m shl a:(64 - len):[0:5]
   shr_cl (m);         // m = m shr a:(64 - len):[0:5]

   shri8  (a,8);       // len:[0:5] pos:[8:13] -> pos:[0:5]

   shl_cl (m);         // m = m shl pos:[0:5]

   //b = xmm1[0:63]
   movqx  (b,xmm_b);

   shl_cl (b);         // b = b shl idx:[0:5]

   //restore rcx
   movq   (a,s);
   a:=s;

  end;

  //input: b->shifted value xmm1
  //input: m->shifted mask

  //a = xmm0[0:63]
  movqx(a,xmm_a);

  andq(b,m);
  notq(m);
  andq(a,m);
  orq (a,b);

  //xmm0[0:63] = a;
  //PINSRQ xmm1, r/m64, imm8
  pinsrq(xmm_a,a,0);

  restore_flags;

  clear_hi;

  //restore jit_frame
  movq(r13,[GS +teb_thread]);
  leaq(r13,[r13+jit_frame_offset]);
 end;

end;

{
 note: xmm0[64:127] -> will be cleared so that temp values can be saved

 a = xmm0[0:63]

 mask = 0xFFFFFFFFFFFFFFFF;

 m = mask shl (64 - len);
 m = m    shr (64 - len);
 m = m    shl idx;

 a = a and m;
 a = a shr idx;

 xmm0[0  :63] = a;
 xmm0[64:127] = 0;
}

procedure op_extrq(var ctx:t_jit_context2);
var
 imm:Int64;
 len,idx:Byte;
 mask:QWORD;
 xmm_a,xmm_b:TRegValue;
 a,b,m,s,ta:TRegValue;

 procedure clear_hi; inline;
 begin
  with ctx.builder do
  begin
   //clear hi 64bit
   ta:=new_reg_size(a,os32);
   xorq(ta,ta);
   pinsrq(xmm_a,a,1);
  end;
 end;

 procedure save_flags; inline;
 begin
  with ctx.builder do
  begin
   movq  (a,rax);       // save rax
   laxf;                // ax = flags
   pinsrq(xmm_a,rax,1); // xmm_a[64:127] = rax
   movq  (rax,a);       // restore rax
  end;
 end;

 procedure restore_flags; inline;
 begin
  with ctx.builder do
  begin
   movq  (a,rax);         // save rax
   pextrq(rax,xmm_a,1);   // rax = xmm_a[64:127]
   sahf;                  // flags = ax
   movq  (rax,a);         // restore rax
  end;
 end;

begin

 with ctx.builder do
 begin

  if (ctx.din.OperCnt=3) then
  begin
   //extrq xmm0,$10,$30

   xmm_a:=new_reg(ctx.din.Operand[1]);

   a:=r_tmp0;
   m:=r_tmp1;

   imm:=0;
   GetTargetOfs(ctx.din,ctx.code,2,imm);
   len:=imm;

   imm:=0;
   GetTargetOfs(ctx.din,ctx.code,3,imm);
   idx:=imm;

   mask:=QWORD($FFFFFFFFFFFFFFFF);
   //shift automatically masks at [0:5]
   mask:=mask shl (64 - len); //clear hi
   mask:=mask shr (64 - len); //restore
   mask:=mask shl idx;        //shift

   if (mask=QWORD($FFFFFFFFFFFFFFFF)) then
   begin
    //special case

    clear_hi;

    //nop
    Exit;
   end;

   save_flags;

   op_set_reg_imm(ctx,m,mask);

   //a = xmm1[0:63]
   movqx(a,xmm_a);

   andq (a,m);    //a = a and m;

   if (idx<>0) then
   begin
    shri8(a,idx); // a = a shr idx;
   end;

   //xmm0[0:63] = a;
   pinsrq(xmm_a,a,0);

   restore_flags;

   clear_hi;

  end else
  begin
   //extrq xmm0,xmm1

   xmm_a:=new_reg(ctx.din.Operand[1]);
   xmm_b:=new_reg(ctx.din.Operand[2]);

   a:=r_tmp0;
   b:=r_tmp1;
   m:=r_thrd;

   save_flags;

   //save rcx
   s:=a;
   a:=rcx;
   movq   (s,a);

   //PEXTRQ r/m64, xmm2, imm8
   pextrq (a,xmm_b,0); // a:=xmm_b[0:63]; -> len:[0:5] pos:[8:13]

   ta:=new_reg_size(a,os8);

   notq   (ta);        // a[0:7] = -len-1
   addi   (ta,65);     // a[0:7] = ((-len-1) + 1 + 64)

   movi   (m,-1);      // m = 0xFFFFFFFFFFFFFFFF  (sign extended to 64-bit)

   shl_cl (m);         // m = m shl a:(64 - len):[0:5]
   shr_cl (m);         // m = m shr a:(64 - len):[0:5]

   shri8  (a,8);       // len:[0:5] pos:[8:13] -> pos:[0:5]

   shl_cl (m);         // m = m shl pos:[0:5]

   //b = xmm0[0:63]
   movqx  (b,xmm_a);

   andq   (b,m);       // b = b and m;

   shr_cl (b);         // b = b shr idx;

   //restore rcx
   movq   (a,s);
   a:=s;

   //xmm0[0:63] = b;
   pinsrq(xmm_a,b,0);

   restore_flags;

   clear_hi;

   //restore jit_frame
   movq(r13,[GS +teb_thread]);
   leaq(r13,[r13+jit_frame_offset]);

  end;

 end;

end;

//SSE4a

const
 movl_ps_pd_desc:t_op_desc=(
  mem_reg:(op:$0F13;opt:[not_os8,not_prefix]);
  reg_mem:(op:$0F12;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_unbs];
 );

procedure op_movl_ps_pd(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2_simd(ctx,movl_ps_pd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 movh_ps_pd_desc:t_op_desc=(
  mem_reg:(op:$0F17;opt:[not_os8,not_prefix]);
  reg_mem:(op:$0F16;opt:[not_os8,not_prefix]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo,his_unbs];
 );

procedure op_movh_ps_pd(var ctx:t_jit_context2);
begin
 if is_memory(ctx.din) then
 begin
  op_emit2_simd(ctx,movh_ps_pd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_maskmov(var ctx:t_jit_context2);
begin
 if jit_memory_guard then
 begin
  with ctx.builder do
  begin
   //save
   movq(r_tmp1,rdi);

   op_uplift(ctx,rdi,os64,[not_use_r_tmp1]); //in/out:rdi

   add_orig(ctx);

   //restore
   movq(rdi,r_tmp1);
  end;
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 ldmxcsr_desc:t_op_type=(
  op:$0FAE;index:2;opt:[not_os8,not_prefix];
 );

procedure op_ldmxcsr(var ctx:t_jit_context2);
begin
 op_emit1(ctx,ldmxcsr_desc,[his_ro]);
end;

const
 stmxcsr_desc:t_op_type=(
  op:$0FAE;index:3;opt:[not_os8,not_prefix];
 );

procedure op_stmxcsr(var ctx:t_jit_context2);
begin
 op_emit1(ctx,stmxcsr_desc,[his_wo]);
end;

procedure op_pextrw(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  if (ctx.dis.opcode=$0F3A15) then
  begin
   //PEXTRW reg/m16, xmm, imm8
   op_emit2_simd_mem_reg(ctx,[his_wo]);
  end else
  begin
   //PEXTRW reg,  mm, imm8
   //PEXTRW reg, xmm, imm8
   op_emit2_simd_reg_mem(ctx,[his_wo]);
  end;
 end else
 begin
  add_orig(ctx);
 end;
end;

//REX.W
//CVTSD2SI
//CVTSI2SD
//CVTSI2SS
//CVTSS2SI
//CVTTSD2SI
//CVTTSS2SI

//

procedure init_cbs_sse;
begin
 jit_cbs[OPPnone,OPmov  ,OPSx_sd]:=@op_movsd;
 jit_cbs[OPPnone,OPmov  ,OPSx_ss]:=@op_movss;

 jit_cbs[OPPnone,OPmov  ,OPSx_d ]:=@op_movd_dq;
 jit_cbs[OPPnone,OPmov  ,OPSx_q ]:=@op_movd_dq;

 jit_cbs[OPPnone,OPmov,OPSx_dqa]:=@op_movdqa;
 jit_cbs[OPPnone,OPmov,OPSx_dqu]:=@op_movdqu;

 jit_cbs[OPPnone,OPlddqu,OPSnone]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPmovu,OPSx_ps]:=@op_movu_ps_pd;
 jit_cbs[OPPnone,OPmovu,OPSx_pd]:=@op_movu_ps_pd;

 jit_cbs[OPPnone,OPmova,OPSx_ps]:=@op_mova_ps_pd;
 jit_cbs[OPPnone,OPmova,OPSx_pd]:=@op_mova_ps_pd;

 jit_cbs[OPPnone,OPmovl,OPSx_ps]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPmovl,OPSx_pd]:=@op_reg_mem_mov_wo;

 jit_cbs[OPPnone,OPmovh,OPSx_ps]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPmovh,OPSx_pd]:=@op_reg_mem_mov_wo;

 jit_cbs[OPPnone,OPmovhlps,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPmovlh,OPSx_ps]:=@add_orig;

 jit_cbs[OPPnone,OPmovsldup,OPSnone]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPmovshdup,OPSnone]:=@op_reg_mem_mov_wo;

 jit_cbs[OPPnone,OPmovnt,OPSx_dqa]:=@op_movntdqa;
 jit_cbs[OPPnone,OPmovnt,OPSx_dq ]:=@op_mem_reg_mov_wo;
 jit_cbs[OPPnone,OPmovnt,OPSx_i  ]:=@op_mem_reg_mov_wo;
 jit_cbs[OPPnone,OPmovnt,OPSx_ps ]:=@op_mem_reg_mov_wo;
 jit_cbs[OPPnone,OPmovnt,OPSx_pd ]:=@op_mem_reg_mov_wo;
 jit_cbs[OPPnone,OPmovnt,OPSx_q  ]:=@op_mem_reg_mov_wo;

 jit_cbs[OPPnone,OPmovdq2q,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPmovq2dq,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPmovddup,OPSnone]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPmovl,OPSx_ps]:=@op_movl_ps_pd;
 jit_cbs[OPPnone,OPmovl,OPSx_pd]:=@op_movl_ps_pd;

 jit_cbs[OPPnone,OPmovh,OPSx_ps]:=@op_movh_ps_pd;
 jit_cbs[OPPnone,OPmovh,OPSx_pd]:=@op_movh_ps_pd;

 jit_cbs[OPPnone,OPpmovsx,OPSv_bw]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovsx,OPSv_bd]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovsx,OPSv_bq]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovsx,OPSv_wd]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovsx,OPSv_wq]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovsx,OPSv_dq]:=@op_reg_mem_mov_wo;

 jit_cbs[OPPnone,OPpmovzx,OPSv_bw]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovzx,OPSv_bd]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovzx,OPSv_bq]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovzx,OPSv_wd]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovzx,OPSv_wq]:=@op_reg_mem_mov_wo;
 jit_cbs[OPPnone,OPpmovzx,OPSv_dq]:=@op_reg_mem_mov_wo;

 jit_cbs[OPPnone,OPmovmsk  ,OPSx_ps]:=@op_reg_mem_mov_wo; //reg reg
 jit_cbs[OPPnone,OPmovmsk  ,OPSx_pd]:=@op_reg_mem_mov_wo; //reg reg
 jit_cbs[OPPnone,OPpmovmskb,OPSnone]:=@op_reg_mem_mov_wo; //reg reg

 jit_cbs[OPPnone,OPmaskmov,OPSx_q  ]:=@op_maskmov;
 jit_cbs[OPPnone,OPmaskmov,OPSx_dqu]:=@op_maskmov;

 jit_cbs[OPPnone,OPcomi ,OPSx_ss]:=@op_reg_mem_ro;
 jit_cbs[OPPnone,OPcomi ,OPSx_sd]:=@op_reg_mem_ro;

 jit_cbs[OPPnone,OPucomi,OPSx_ss]:=@op_reg_mem_ro;
 jit_cbs[OPPnone,OPucomi,OPSx_sd]:=@op_reg_mem_ro;

 jit_cbs[OPPnone,OPxor,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPxor,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpxor,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPor ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPor ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpor,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPand  ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPand  ,OPSx_pd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPandn ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPandn ,OPSx_pd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpand ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpandn,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpcmpeq,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpeq,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpeq,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpeq,OPSx_q ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpcmpgt,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpgt,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpgt,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpgt,OPSx_q ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpcmpestrm,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpestri,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpistrm,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpcmpistri,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPsub   ,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPsub   ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPsub   ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPsub   ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub  ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub  ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub  ,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub  ,OPSx_q ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsubs ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsubs ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsubus,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsubus,OPSx_w ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPadd   ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPadd   ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPadd   ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPadd   ,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_q ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadds ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadds ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpaddus,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpaddus,OPSx_w ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPphadd ,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPphadd ,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPaddsub,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPaddsub,OPSx_ps]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPdiv ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPdiv ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPdiv ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPdiv ,OPSx_sd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPmul ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmul ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmul ,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmul ,OPSx_ss]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmull ,OPSx_d]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmull ,OPSx_w]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmuludq ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmulhuw ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmulhrsw,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmulhw  ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmuldq  ,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPadd   ,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPadd   ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadd  ,OPSx_q ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadds ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpadds ,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpaddus,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpaddus,OPSx_w ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPsub ,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPsub ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsub,OPSx_d ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmaddubsw,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmaddwd  ,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPcvtsi2 ,OPSx_ss]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtsi2 ,OPSx_sd]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtss2 ,OPSx_sd]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtss2 ,OPSx_si]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtsd2 ,OPSx_ss]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtsd2 ,OPSx_si]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvttps2,OPSx_dq]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvttps2,OPSx_pi]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvttpd2,OPSx_dq]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvttpd2,OPSx_pi]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtdq2 ,OPSx_ps]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtdq2 ,OPSx_pd]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvttss2,OPSx_si]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvttsd2,OPSx_si]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtpd2 ,OPSx_ps]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtpd2 ,OPSx_dq]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtpd2 ,OPSx_pi]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtps2 ,OPSx_pd]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtps2 ,OPSx_dq]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtps2 ,OPSx_pi]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPcvtpi2 ,OPSx_pd]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPcvtpi2 ,OPSx_ps]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPpextr,OPSx_b]:=@op_mem_reg_wo;
 jit_cbs[OPPnone,OPpextr,OPSx_d]:=@op_mem_reg_wo;
 jit_cbs[OPPnone,OPpextr,OPSx_q]:=@op_mem_reg_wo;
 jit_cbs[OPPnone,OPpextr,OPSx_w]:=@op_pextrw;

 jit_cbs[OPPnone,OPsqrt,OPSx_ps]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPsqrt,OPSx_pd]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPsqrt,OPSx_sd]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPsqrt,OPSx_ss]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPrsqrt,OPSx_ps]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPrsqrt,OPSx_ss]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPrcp ,OPSx_ps]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPrcp ,OPSx_ss]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPpshuf,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf,OPSx_hw]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf,OPSx_lw]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf,OPSx_w ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpsra,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsra,OPSx_d ]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpsrl,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsrl,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsrl,OPSx_q ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsrl,OPSx_dq]:=@add_orig;

 jit_cbs[OPPnone,OPpsll,OPSx_w ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsll,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsll,OPSx_q ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsll,OPSx_dq]:=@add_orig;

 jit_cbs[OPPnone,OPpminu,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpminu,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpminu,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmins,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmins,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmins,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPmin ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmin ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmin ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmin ,OPSx_sd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmaxu,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmaxu,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmaxu,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpmaxs,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmaxs,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpmaxs,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPmax ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmax ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmax ,OPSx_ss]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPmax ,OPSx_sd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpinsr,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpinsr,OPSx_d]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpinsr,OPSx_q]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpinsr,OPSx_w]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpacksswb,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpackssdw,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpackusdw,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpackuswb,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpunpcklbw ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpcklwd ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpckldq ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpcklqdq,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpunpckhbw ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpckhwd ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpckhdq ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpunpckhqdq,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPunpckl    ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPunpckl    ,OPSx_ps]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPunpckh    ,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPunpckh    ,OPSx_ps]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpalignr,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpsign,OPSx_b]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsign,OPSx_w]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpsign,OPSx_d]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPcmp,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPcmp,OPSx_pd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPcmp,OPSx_sd]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPcmp,OPSx_ss]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPpshuf ,OPSx_b ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf ,OPSx_d ]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf ,OPSx_hw]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPpshuf ,OPSx_lw]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPshuf  ,OPSx_ps]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPshuf  ,OPSx_pd]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPldmxcsr,OPSnone]:=@op_ldmxcsr;
 jit_cbs[OPPnone,OPstmxcsr,OPSnone]:=@op_stmxcsr;

 if _SSE4aSupport then
 begin
  jit_cbs[OPPnone,OPmovnt ,OPSx_sd]:=@op_movnt_sd_ss;
  jit_cbs[OPPnone,OPmovnt ,OPSx_ss]:=@op_movnt_sd_ss;
  jit_cbs[OPPnone,OPinsert,OPSx_q ]:=@add_orig;
  jit_cbs[OPPnone,OPextrq ,OPSnone]:=@add_orig;
 end else
 begin
  jit_cbs[OPPnone,OPmovnt ,OPSx_sd]:=@op_movsd;
  jit_cbs[OPPnone,OPmovnt ,OPSx_ss]:=@op_movss;
  jit_cbs[OPPnone,OPinsert,OPSx_q ]:=@op_insertq;
  jit_cbs[OPPnone,OPextrq ,OPSnone]:=@op_extrq;
 end;

 jit_cbs[OPPnone,OPpavg,OPSx_b]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPpavg,OPSx_w]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPaeskeygenassist,OPSnone]:=@op_reg_mem_wo;
 jit_cbs[OPPnone,OPaesimc         ,OPSnone]:=@op_reg_mem_wo;

 jit_cbs[OPPnone,OPaesenc    ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPaesenclast,OPSnone]:=@op_reg_mem_rw;

 jit_cbs[OPPnone,OPaesdec    ,OPSnone]:=@op_reg_mem_rw;
 jit_cbs[OPPnone,OPaesdeclast,OPSnone]:=@op_reg_mem_rw;

end;

procedure SetupSupport;
var
 _ecx:longint;
begin
 asm
    movl $0x80000001,%eax
    cpuid
    movl %ecx,_ecx
 end ['rax','rbx','rcx','rdx'];
 _SSE4aSupport:=(_ecx and $40)<>0;
end;

initialization
 SetupSupport;
 init_cbs_sse;

end.

