unit kern_jit_ops;

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

interface

uses
 x86_fpdbgdisas,
 x86_jit,
 kern_jit_ctx;

type
 t_jit_cb=procedure(var ctx:t_jit_context2);

 t_rep_op=(repOPins,repOPouts,repOPmovs,repOPlods,repOPstos,repOPcmps,repOPscas,repOPret);

var
 jit_cbs:array[TOpcodePrefix,TOpCode,TOpCodeSuffix] of t_jit_cb;
 jit_rep_cbs:array[t_rep_op] of t_jit_cb;

implementation

//

procedure _op_rep_cmps(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;

 link_start:t_jit_i_link;
 link___end:t_jit_i_link;

 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 //(r_tmp1)r15 <-> rsi
 with ctx.builder do
 begin

  link_jmp0:=nil_link;
  link_jmp1:=nil_link;

  link_start:=ctx.builder.get_curr_label.after;

  //repeat
   link_jmp0:=jcxz(nil_link,ctx.dis.AddressSize);

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq(r_tmp1,rsi);
   op_uplift(ctx,r_tmp1,size,[not_use_r_tmp0]); //in/out:r15

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   _O($A7,Size);

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   leaq(rcx,[rcx-1]);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
    leaq(rsi,[rsi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
    leaq(rsi,[rsi-OPERAND_BYTES[size]]);
   end;

   if (ifPrefixRepE in ctx.din.Flags) then
   begin
    //if a[i]<>b[i] then exit
    link_jmp1:=jcc(OPSc_nz,nil_link,os8);
   end else
   if (ifPrefixRepNe in ctx.din.Flags) then
   begin
    //if a[i]=b[i] then exit
    link_jmp1:=jcc(OPSc_z,nil_link,os8);
   end;

  //until
  jmp(link_start,os8);

  //exit

  link___end:=ctx.builder.get_curr_label.after; //exit

  link_jmp0.target:=link___end;
  link_jmp1.target:=link___end;
 end;

end;

procedure op_rep_cmps(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  popfq(os64);
  _op_rep_cmps(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  popfq(os64);
  _op_rep_cmps(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

 end;
end;

///

procedure _op_rep_stos(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;

 new:TRegValue;

 link_start:t_jit_i_link;
 link___end:t_jit_i_link;

 link_jmp0:t_jit_i_link;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 with ctx.builder do
 begin

  link_jmp0:=nil_link;

  new:=new_reg_size(rax,size);

  link_start:=ctx.builder.get_curr_label.after;

  //repeat
   link_jmp0:=jcxz(nil_link,ctx.dis.AddressSize);

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq([r_tmp0],new); // mov [r14],rax

   leaq(rcx,[rcx-1]);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
   end;

  //until
  jmp(link_start,os8);

  //exit

  link___end:=ctx.builder.get_curr_label.after; //exit

  link_jmp0.target:=link___end;
 end;

end;

procedure op_rep_stos(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  _op_rep_stos(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  _op_rep_stos(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

  popfq(os64);

 end;
end;

//

procedure _op_rep_movs(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;

 link_start:t_jit_i_link;
 link___end:t_jit_i_link;

 link_jmp0:t_jit_i_link;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 //(r_tmp1)r15 <-> rsi
 with ctx.builder do
 begin

  link_jmp0:=nil_link;

  link_start:=ctx.builder.get_curr_label.after;

  //repeat
   link_jmp0:=jcxz(nil_link,ctx.dis.AddressSize);

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq(r_tmp1,rsi);
   op_uplift(ctx,r_tmp1,size,[not_use_r_tmp0]); //in/out:r15

   //[RSI] -> [RDI].

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   _O($A5,Size);

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   leaq(rcx,[rcx-1]);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
    leaq(rsi,[rsi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
    leaq(rsi,[rsi-OPERAND_BYTES[size]]);
   end;

  //until
  jmp(link_start,os8);

  //exit

  link___end:=ctx.builder.get_curr_label.after; //exit

  link_jmp0.target:=link___end;
 end;

end;

procedure op_rep_movs(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  _op_rep_movs(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  _op_rep_movs(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

  popfq(os64);

 end;
end;


//

procedure _op_cmps(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 //(r_tmp1)r15 <-> rsi
 with ctx.builder do
 begin

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq(r_tmp1,rsi);
   op_uplift(ctx,r_tmp1,size,[not_use_r_tmp0]); //in/out:r15

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   _O($A7,Size);

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
    leaq(rsi,[rsi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
    leaq(rsi,[rsi-OPERAND_BYTES[size]]);
   end;

 end;

end;

procedure op_cmps(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  popfq(os64);
  _op_cmps(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  popfq(os64);
  _op_cmps(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

 end;
end;

//

procedure _op_movs(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 //(r_tmp1)r15 <-> rsi
 with ctx.builder do
 begin

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq(r_tmp1,rsi);
   op_uplift(ctx,r_tmp1,size,[not_use_r_tmp0]); //in/out:r15

   //[RSI] -> [RDI].

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   _O($A5,Size);

   xchgq(rdi,r_tmp0);
   xchgq(rsi,r_tmp1);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
    leaq(rsi,[rsi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
    leaq(rsi,[rsi-OPERAND_BYTES[size]]);
   end;

 end;

end;

procedure op_movs(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  _op_movs(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  _op_movs(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

  popfq(os64);

 end;
end;

//

procedure _op_stos(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;

 new:TRegValue;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 with ctx.builder do
 begin

  new:=new_reg_size(rax,size);

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq([r_tmp0],new);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
   end;

 end;

end;

procedure op_stos(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  _op_stos(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  _op_stos(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

  popfq(os64);

 end;
end;

//

procedure _op_lods(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;

 new:TRegValue;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 with ctx.builder do
 begin

  new:=new_reg_size(rax,size);

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   movq(new,[r_tmp0]);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
   end;

 end;

end;

procedure op_lods(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  _op_lods(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  _op_lods(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

  popfq(os64);

 end;
end;

//

procedure _op_scas(var ctx:t_jit_context2;dflag:Integer);
var
 size:TOperandSize;
begin
 //rdi,rsi

 Assert(ctx.dis.AddressSize=as64,'prefix $67 TODO');

 case ctx.din.OpCode.Suffix of
  OPSx_b:size:=os8;
  OPSx_w:size:=os16;
  OPSx_d:size:=os32;
  OPSx_q:size:=os64;
  else;
   Assert(False);
 end;

 //(r_tmp0)r14 <-> rdi
 with ctx.builder do
 begin

   movq(r_tmp0,rdi);
   op_uplift(ctx,r_tmp0,size); //in/out:r14

   xchgq(rdi,r_tmp0);

   _O($AF,Size);

   xchgq(rdi,r_tmp0);

   if (dflag=0) then
   begin
    leaq(rdi,[rdi+OPERAND_BYTES[size]]);
   end else
   begin
    leaq(rdi,[rdi-OPERAND_BYTES[size]]);
   end;

 end;

end;

procedure op_scas(var ctx:t_jit_context2);
var
 link_jmp0:t_jit_i_link;
 link_jmp1:t_jit_i_link;
begin
 with ctx.builder do
 begin

  //get d flag
  pushfq(os64);
  bti8([rsp,os64],10); //bt [rsp], 10

  link_jmp0:=jcc(OPSc_b,nil_link,os8);

  popfq(os64);
  _op_scas(ctx,0);

  link_jmp1:=jmp(nil_link,os8);

  link_jmp0.target:=ctx.builder.get_curr_label.after;

  popfq(os64);
  _op_scas(ctx,1);

  link_jmp1.target:=ctx.builder.get_curr_label.after;

 end;
end;

//

const
 xor_desc:t_op_desc=(
  mem_reg:(op:$31;index:0);
  reg_mem:(op:$33;index:0);
  reg_imm:(op:$81;index:6);
  reg_im8:(op:$83;index:6);
  hint:[his_xor,his_rw];
 );

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

const
 or_desc:t_op_desc=(
  mem_reg:(op:$09;index:0);
  reg_mem:(op:$0B;index:0);
  reg_imm:(op:$81;index:1);
  reg_im8:(op:$83;index:1);
  hint:[his_rw];
 );

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

const
 and_desc:t_op_desc=(
  mem_reg:(op:$21;index:0);
  reg_mem:(op:$23;index:0);
  reg_imm:(op:$81;index:4);
  reg_im8:(op:$83;index:4);
  hint:[his_rw];
 );

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

const
 sub_desc:t_op_desc=(
  mem_reg:(op:$29;index:0);
  reg_mem:(op:$2B;index:0);
  reg_imm:(op:$81;index:5);
  reg_im8:(op:$83;index:5);
  hint:[his_rw];
 );

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

const
 sbb_desc:t_op_desc=(
  mem_reg:(op:$19;index:0);
  reg_mem:(op:$1B;index:0);
  reg_imm:(op:$81;index:3);
  reg_im8:(op:$83;index:3);
  hint:[his_rw];
 );

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

const
 add_desc:t_op_desc=(
  mem_reg:(op:$01;index:0);
  reg_mem:(op:$03;index:0);
  reg_imm:(op:$81;index:0);
  reg_im8:(op:$83;index:0);
  hint:[his_rw];
 );

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

const
 adc_desc:t_op_desc=(
  mem_reg:(op:$11;index:0);
  reg_mem:(op:$13;index:0);
  reg_imm:(op:$81;index:2);
  reg_im8:(op:$83;index:2);
  hint:[his_rw];
 );

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

const
 imul_desc1:t_op_type=(op:$F7;index:5);

 imul_desc2:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$0FAF;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_rw];
 );

 imul_desc3:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(opt:[not_impl]);
  reg_imm:(op:$69;index:0);
  reg_im8:(op:$6B;index:0);
  hint:[];
 );

procedure op_imul(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  case ctx.din.OperCnt of
   1:op_emit1(ctx,imul_desc1,[his_ro]); //R
   2:op_emit2(ctx,imul_desc2); //RM
   3:op_emit2(ctx,imul_desc3); //RMI
   else
    Assert(false);
  end;
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_gn(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8];

  op_emit1(ctx,tmp,[]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_gn_np(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8,not_prefix];

  op_emit1(ctx,tmp,[]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_ro(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8];

  op_emit1(ctx,tmp,[his_ro]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_ro_np(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8,not_prefix];

  op_emit1(ctx,tmp,[his_ro]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_rw(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8];

  op_emit1(ctx,tmp,[his_rw]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_rw_np(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8,not_prefix];

  op_emit1(ctx,tmp,[his_rw]);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_emit1_wo_np(var ctx:t_jit_context2);
var
 tmp:t_op_type;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=Default(t_op_type);

  tmp.op   :=ctx.dis.opcode;
  tmp.index:=ctx.dis.ModRM.Index;
  tmp.opt  :=[not_os8,not_prefix];

  op_emit1(ctx,tmp,[his_wo]);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 bt_desc:t_op_desc=(
  mem_reg:(op:$0FA3;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:$0FBA;index:4);
  hint:[his_ro,his_bt];
 );

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

const
 btc_desc:t_op_desc=(
  mem_reg:(op:$0FBB;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:$0FBA;index:7);
  hint:[his_rw,his_bt];
 );

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

const
 bts_desc:t_op_desc=(
  mem_reg:(op:$0FAB;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:$0FBA;index:5);
  hint:[his_rw,his_bt];
 );

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

const
 btr_desc:t_op_desc=(
  mem_reg:(op:$0FB3;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(op:$0FBA;index:6);
  hint:[his_rw,his_bt];
 );

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

//

const
 bsf_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$0FBC;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_wo];
 );

procedure op_bsf(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  //If the second operand contains 0,
  //the instruction sets ZF to 1
  //and does not change the contents
  //of the destination register.
  op_emit2(ctx,bsf_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 bsr_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$0FBD;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_wo];
 );

procedure op_bsr(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  //If the second operand contains 0,
  //the instruction sets ZF to 1
  //and does not change the contents
  //of the destination register.
  op_emit2(ctx,bsr_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;


//

const
 xchg_desc:t_op_desc=(
  mem_reg:(op:$87;index:0);
  reg_mem:(op:$87;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_xchg,his_rw];
 );

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

const
 mov_desc:t_op_desc=(
  mem_reg:(op:$89;index:0);
  reg_mem:(op:$8B;index:0);
  reg_imm:(op:$C7;index:0);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

procedure op_mov(var ctx:t_jit_context2);
type
 tdata16=array[0..15] of Byte;
var
 data:tdata16;
 Code:Pointer;
 Operand:TOperand;
 i:Byte;
begin
 if is_segment(ctx.din.Operand[1]) then
 begin
  Exit; //skip segment change
 end;

 if is_segment(ctx.din.Operand[2]) then
 begin
  if is_preserved(ctx.din) or is_memory(ctx.din) then
  begin
   i:=ctx.dis.CodeIdx;

   data:=Default(tdata16);
   Move(ctx.Code^,data,i);

   data[i+0]:=get_segment_value(ctx.din.Operand[2]);

   Code:=ctx.Code;
   Operand:=ctx.din.Operand[2];

   ctx.din.Operand[2].RegValue :=Default(TRegValues);
   ctx.din.Operand[2].Size     :=ctx.din.Operand[1].Size;
   ctx.din.Operand[2].ByteCount:=i;

   op_emit2(ctx,mov_desc);

   ctx.din.Operand[2]:=Operand;
   ctx.Code:=Code;
  end else
  begin
   //reg_imm
   ctx.builder.movi(new_reg(ctx.din.Operand[1]),get_segment_value(ctx.din.Operand[2]));
  end;

  Exit;
 end;

 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2(ctx,mov_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 CMOV_8:array[OPSc_o..OPSc_nle] of Byte=(
  $40,$41,$42,$43,$44,$45,$46,$47,
  $48,$49,$4A,$4B,$4C,$4D,$4E,$4F
 );

const
 cmov_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$00;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[];
 );

procedure op_cmov(var ctx:t_jit_context2);
var
 desc:t_op_desc;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  desc:=cmov_desc;
  desc.reg_mem.op:=$0F00 or CMOV_8[ctx.din.OpCode.Suffix];
  //
  op_emit2(ctx,desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 movx_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$00;opt:[not_os8,reg_size_pri]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

procedure op_movzx(var ctx:t_jit_context2);
var
 desc:t_op_desc;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  desc:=movx_desc;

  //
  case ctx.din.Operand[2].Size of
    os8:desc.reg_mem.op:=$0FB6;
   os16:desc.reg_mem.op:=$0FB7;
   else
    Assert(false);
  end;

  op_emit2(ctx,desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_movsx(var ctx:t_jit_context2);
var
 desc:t_op_desc;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  desc:=movx_desc;

  //
  case ctx.din.Operand[2].Size of
    os8:desc.reg_mem.op:=$0FBE;
   os16:desc.reg_mem.op:=$0FBF;
   else
    Assert(false);
  end;

  op_emit2(ctx,desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 movbe_desc:t_op_desc=(
  mem_reg:(op:$0F38F1;opt:[not_os8]);
  reg_mem:(op:$0F38F0;opt:[not_os8]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

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

const
 movsxd_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$63;opt:[not_os8,reg_size_pri]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_mov,his_wo];
 );

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

//

const
 test_desc:t_op_desc=(
  mem_reg:(op:$85;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(op:$F7;index:0);
  reg_im8:(opt:[not_impl]);
  hint:[his_ro];
 );

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

const
 cmp_desc:t_op_desc=(
  mem_reg:(op:$39;index:0);
  reg_mem:(op:$3B;index:0);
  reg_imm:(op:$81;index:7);
  reg_im8:(op:$83;index:7);
  hint:[his_ro];
 );

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

const
 cmpxchg_desc:t_op_desc=(
  mem_reg:(op:$0FB1;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_xchg,his_rw];
 );

procedure op_cmpxchg(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit2(ctx,cmpxchg_desc);
 end else
 with ctx.builder do
 begin
  add_orig(ctx);
 end;
end;

const
 cmpxchg_8b_16b_desc:t_op_type=(op:$0FC7;index:1);

procedure op_cmpxchg_8b_16b(var ctx:t_jit_context2);
begin
 op_emit1(ctx,cmpxchg_8b_16b_desc,[his_xchg,his_rw]);
end;

const
 xadd_desc:t_op_desc=(
  mem_reg:(op:$0FC1;index:0);
  reg_mem:(opt:[not_impl]);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_xchg,his_rw];
 );

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

const
 lzcnt_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$F30FBD;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_wo];
 );

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

const
 tzcnt_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$F30FBC;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_wo];
 );

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

const
 popcnt_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$F30FB8;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[his_wo];
 );

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

//

const
 crc32_desc:t_op_desc=(
  mem_reg:(opt:[not_impl]);
  reg_mem:(op:$F20F38F1;index:0);
  reg_imm:(opt:[not_impl]);
  reg_im8:(opt:[not_impl]);
  hint:[];
 );

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

//

procedure op_shift2_gen(var ctx:t_jit_context2);
const
 desc:t_op_shift=(
  reg_im8:(op:$C1;index:0);
  mem__cl:(op:$D3;index:0);
  mem_one:(op:$D1;index:0);
 );
var
 tmp:t_op_shift;
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  tmp:=desc;
  tmp.reg_im8.index:=ctx.dis.ModRM.Index;
  tmp.mem__cl.index:=ctx.dis.ModRM.Index;
  tmp.mem_one.index:=ctx.dis.ModRM.Index;
  //
  op_emit_shift2(ctx,tmp);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

const
 shld_desc:t_op_shift=(
  reg_im8:(op:$0FA4);
  mem__cl:(op:$0FA5);
  mem_one:(opt:[not_impl]);
 );

procedure op_shld(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit_shift3(ctx,shld_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

const
 shrd_desc:t_op_shift=(
  reg_im8:(op:$0FAC);
  mem__cl:(op:$0FAD);
  mem_one:(opt:[not_impl]);
 );

procedure op_shrd(var ctx:t_jit_context2);
begin
 if is_preserved(ctx.din) or is_memory(ctx.din) then
 begin
  op_emit_shift3(ctx,shrd_desc);
 end else
 begin
  add_orig(ctx);
 end;
end;

//

procedure op_bswap(var ctx:t_jit_context2);
var
 new:TRegValue;
begin
 if is_preserved(ctx.din) then
 begin
  with ctx.builder do
  begin
   new:=new_reg_size(r_tmp0,ctx.din.Operand[1]);

   op_load(ctx,new,1);

   bswap(new);

   op_save(ctx,1,fix_size(new));
  end;
 end else
 begin
  add_orig(ctx);
 end;
end;

procedure op_lea(var ctx:t_jit_context2);
var
 new:TRegValue;
begin
 if is_preserved(ctx.din) then
 begin
  if is_preserved(ctx.din.Operand[1]) then
  begin
   new:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
   build_lea(ctx,2,new,[not_use_segment]);
   //
   op_save(ctx,1,fix_size(new));
  end else
  begin
   new:=new_reg(ctx.din.Operand[1]);
   //
   if (new.ASize=os16) then
   begin
    //low part
    build_lea(ctx,2,r_tmp0);
    //
    ctx.builder.movq(new,r_tmp0);
   end else
   begin
    build_lea(ctx,2,new);
   end;
  end;
 end else
 begin
  add_orig(ctx);
 end;
end;

//

procedure init_cbs;
begin
 //

 if jit_memory_guard then
 begin
  jit_rep_cbs[repOPmovs]:=@op_rep_movs;
  jit_rep_cbs[repOPlods]:=nil;
  jit_rep_cbs[repOPstos]:=@op_rep_stos;
  jit_rep_cbs[repOPcmps]:=@op_rep_cmps;
  jit_rep_cbs[repOPscas]:=nil;

  jit_cbs[OPPnone,OPcmps,OPSx_b]:=@op_cmps;
  jit_cbs[OPPnone,OPcmps,OPSx_w]:=@op_cmps;
  jit_cbs[OPPnone,OPcmps,OPSx_d]:=@op_cmps;
  jit_cbs[OPPnone,OPcmps,OPSx_q]:=@op_cmps;

  jit_cbs[OPPnone,OPmovs,OPSx_b]:=@op_movs;
  jit_cbs[OPPnone,OPmovs,OPSx_w]:=@op_movs;
  jit_cbs[OPPnone,OPmovs,OPSx_d]:=@op_movs;
  jit_cbs[OPPnone,OPmovs,OPSx_q]:=@op_movs;

  jit_cbs[OPPnone,OPstos,OPSx_b]:=@op_stos;
  jit_cbs[OPPnone,OPstos,OPSx_w]:=@op_stos;
  jit_cbs[OPPnone,OPstos,OPSx_d]:=@op_stos;
  jit_cbs[OPPnone,OPstos,OPSx_q]:=@op_stos;

  jit_cbs[OPPnone,OPlods,OPSx_b]:=@op_lods;
  jit_cbs[OPPnone,OPlods,OPSx_w]:=@op_lods;
  jit_cbs[OPPnone,OPlods,OPSx_d]:=@op_lods;
  jit_cbs[OPPnone,OPlods,OPSx_q]:=@op_lods;

  jit_cbs[OPPnone,OPscas,OPSx_b]:=@op_scas;
  jit_cbs[OPPnone,OPscas,OPSx_w]:=@op_scas;
  jit_cbs[OPPnone,OPscas,OPSx_d]:=@op_scas;
  jit_cbs[OPPnone,OPscas,OPSx_q]:=@op_scas;
 end else
 begin
  jit_rep_cbs[repOPmovs]:=@add_orig;
  jit_rep_cbs[repOPlods]:=@add_orig;
  jit_rep_cbs[repOPstos]:=@add_orig;
  jit_rep_cbs[repOPcmps]:=@add_orig;
  jit_rep_cbs[repOPscas]:=@add_orig;

  jit_cbs[OPPnone,OPcmps,OPSx_b]:=@add_orig;
  jit_cbs[OPPnone,OPcmps,OPSx_w]:=@add_orig;
  jit_cbs[OPPnone,OPcmps,OPSx_d]:=@add_orig;
  jit_cbs[OPPnone,OPcmps,OPSx_q]:=@add_orig;

  jit_cbs[OPPnone,OPmovs,OPSx_b]:=@add_orig;
  jit_cbs[OPPnone,OPmovs,OPSx_w]:=@add_orig;
  jit_cbs[OPPnone,OPmovs,OPSx_d]:=@add_orig;
  jit_cbs[OPPnone,OPmovs,OPSx_q]:=@add_orig;

  jit_cbs[OPPnone,OPstos,OPSx_b]:=@add_orig;
  jit_cbs[OPPnone,OPstos,OPSx_w]:=@add_orig;
  jit_cbs[OPPnone,OPstos,OPSx_d]:=@add_orig;
  jit_cbs[OPPnone,OPstos,OPSx_q]:=@add_orig;

  jit_cbs[OPPnone,OPlods,OPSx_b]:=@add_orig;
  jit_cbs[OPPnone,OPlods,OPSx_w]:=@add_orig;
  jit_cbs[OPPnone,OPlods,OPSx_d]:=@add_orig;
  jit_cbs[OPPnone,OPlods,OPSx_q]:=@add_orig;

  jit_cbs[OPPnone,OPscas,OPSx_b]:=@add_orig;
  jit_cbs[OPPnone,OPscas,OPSx_w]:=@add_orig;
  jit_cbs[OPPnone,OPscas,OPSx_d]:=@add_orig;
  jit_cbs[OPPnone,OPscas,OPSx_q]:=@add_orig;
 end;

 //

 jit_cbs[OPPnone,OPxor ,OPSnone]:=@op_xor;
 jit_cbs[OPPnone,OPor  ,OPSnone]:=@op_or;
 jit_cbs[OPPnone,OPand ,OPSnone]:=@op_and;
 jit_cbs[OPPnone,OPsub ,OPSnone]:=@op_sub;
 jit_cbs[OPPnone,OPsbb ,OPSnone]:=@op_sbb;
 jit_cbs[OPPnone,OPadd ,OPSnone]:=@op_add;
 jit_cbs[OPPnone,OPadc ,OPSnone]:=@op_adc;

 jit_cbs[OPPnone,OPimul,OPSnone]:=@op_imul;
 jit_cbs[OPPnone,OPmul ,OPSnone]:=@op_emit1_ro;
 jit_cbs[OPPnone,OPidiv,OPSnone]:=@op_emit1_ro;
 jit_cbs[OPPnone,OPdiv ,OPSnone]:=@op_emit1_ro;

 jit_cbs[OPPnone,OPbt  ,OPSnone]:=@op_bt;
 jit_cbs[OPPnone,OPbtc ,OPSnone]:=@op_btc;
 jit_cbs[OPPnone,OPbts ,OPSnone]:=@op_bts;
 jit_cbs[OPPnone,OPbtr ,OPSnone]:=@op_btr;

 jit_cbs[OPPnone,OPbsf,OPSnone]:=@op_bsf;
 jit_cbs[OPPnone,OPbsr,OPSnone]:=@op_bsr;

 jit_cbs[OPPnone,OPxchg,OPSnone]:=@op_xchg;

 jit_cbs[OPPnone,OPmov ,OPSnone]:=@op_mov;

 jit_cbs[OPPnone,OPcmov__,OPSc_o  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_no ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_b  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_nb ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_z  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_nz ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_be ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_nbe]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_s  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_ns ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_p  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_np ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_l  ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_nl ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_le ]:=@op_cmov;
 jit_cbs[OPPnone,OPcmov__,OPSc_nle]:=@op_cmov;

 jit_cbs[OPPnone,OPmovzx,OPSnone]:=@op_movzx;
 jit_cbs[OPPnone,OPmovsx,OPSnone]:=@op_movsx;
 jit_cbs[OPPnone,OPmov  ,OPSc_be]:=@op_movbe;
 jit_cbs[OPPnone,OPmovsx,OPSx_d ]:=@op_movsxd;

 jit_cbs[OPPnone,OPtest,OPSnone]:=@op_test;
 jit_cbs[OPPnone,OPcmp ,OPSnone]:=@op_cmp;

 jit_cbs[OPPnone,OPcmpxchg,OPSnone ]:=@op_cmpxchg;
 jit_cbs[OPPnone,OPcmpxchg,OPSx_8b ]:=@op_cmpxchg_8b_16b;
 jit_cbs[OPPnone,OPcmpxchg,OPSx_16b]:=@op_cmpxchg_8b_16b;

 jit_cbs[OPPnone,OPxadd   ,OPSnone]:=@op_xadd;

 jit_cbs[OPPnone,OPlzcnt  ,OPSnone]:=@op_lzcnt;
 jit_cbs[OPPnone,OPtzcnt  ,OPSnone]:=@op_tzcnt;
 jit_cbs[OPPnone,OPpopcnt ,OPSnone]:=@op_popcnt;
 jit_cbs[OPPnone,OPcrc32  ,OPSnone]:=@op_crc32;

 jit_cbs[OPPnone,OProl ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPror ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPrcl ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPrcr ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPshl ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPshr ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPsar ,OPSnone]:=@op_shift2_gen;
 jit_cbs[OPPnone,OPsal ,OPSnone]:=@op_shift2_gen;

 jit_cbs[OPPnone,OPshl ,OPSx_d ]:=@op_shld;
 jit_cbs[OPPnone,OPshr ,OPSx_d ]:=@op_shrd;

 jit_cbs[OPPnone,OPset__,OPSc_o  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_no ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_b  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_nb ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_z  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_nz ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_be ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_nbe]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_s  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_ns ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_p  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_np ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_l  ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_nl ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_le ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPset__,OPSc_nle]:=@op_emit1_gn_np;

 jit_cbs[OPPnone,OPemms      ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfemms     ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPvzeroall  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPvzeroupper,OPSnone]:=@add_orig;

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

 jit_cbs[OPPnone,OPlfence,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPmfence,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPsfence,OPSnone]:=@add_orig;

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

 jit_cbs[OPPnone,OPcli ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPsti ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPclac,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPclc ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPcld ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPstc ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPstd ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPcwd ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPcdq ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPcqo ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPcbw ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPcwde,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPcdqe,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPgetbv,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPrdpmc,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPlea,OPSnone]:=@op_lea;

 jit_cbs[OPPnone,OPinc,OPSnone]:=@op_emit1_rw;
 jit_cbs[OPPnone,OPdec,OPSnone]:=@op_emit1_rw;
 jit_cbs[OPPnone,OPneg,OPSnone]:=@op_emit1_rw;
 jit_cbs[OPPnone,OPnot,OPSnone]:=@op_emit1_rw;

 jit_cbs[OPPnone,OPbswap,OPSnone]:=@op_bswap;

 jit_cbs[OPPnone,OPsahf,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPlahf,OPSnone]:=@add_orig;

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

 //fpu

 jit_cbs[OPPnone,OPfninit  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfrndint ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfchs    ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfxch    ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPfcmov__ ,OPSc_b  ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_e  ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_be ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_u  ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_nb ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_ne ]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_nbe]:=@add_orig;
 jit_cbs[OPPnone,OPfcmov__ ,OPSc_nu ]:=@add_orig;

 jit_cbs[OPPnone,OPfld1  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldl2e,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldl2t,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldlg2,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldln2,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldpi ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfldz  ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPfucom,OPSx_i ]:=@add_orig;
 jit_cbs[OPPnone,OPfucom,OPSx_ip]:=@add_orig;
 jit_cbs[OPPnone,OPfucom,OPSx_p ]:=@add_orig;

 jit_cbs[OPPnone,OPfcom,OPSx_i ]:=@add_orig;
 jit_cbs[OPPnone,OPfcom,OPSx_ip]:=@add_orig;
 jit_cbs[OPPnone,OPfcom,OPSx_p ]:=@add_orig;

 jit_cbs[OPPnone,OPfadd   ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfsub   ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfsubr  ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfmul   ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfdiv   ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfdivr  ,OPSx_p ]:=@add_orig;
 jit_cbs[OPPnone,OPfsqrt  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfabs   ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfscale ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfprem  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfprem1 ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfxtract,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfwait  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfnclex ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPfsin   ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfcos   ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfsincos,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfpatan ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfptan  ,OPSnone]:=@add_orig;

 jit_cbs[OPPnone,OPfyl2x  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfyl2xp1,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPf2xm1  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfdecstp,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPffree  ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfincstp,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPftst   ,OPSnone]:=@add_orig;
 jit_cbs[OPPnone,OPfxam   ,OPSnone]:=@add_orig;

 //

 jit_cbs[OPPnone,OPfldcw  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfld    ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfild   ,OPSnone]:=@op_emit1_ro_np;

 jit_cbs[OPPnone,OPfldenv ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfnstenv,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfnstcw ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfnstsw ,OPSnone]:=@op_emit1_gn_np;

 jit_cbs[OPPnone,OPfxsave ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfxrstor,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfst    ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfst    ,OPSx_p ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfist   ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfist   ,OPSx_p ]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfisttp ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfadd   ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfiadd  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfmul   ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfimul  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfsub   ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfsubr  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfisub  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfdiv   ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfdivr  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfidiv  ,OPSnone]:=@op_emit1_ro_np;
 jit_cbs[OPPnone,OPfidivr ,OPSnone]:=@op_emit1_ro_np;

 jit_cbs[OPPnone,OPclflush,OPSnone]:=@op_emit1_rw_np;

 jit_cbs[OPPnone,OPfnsave ,OPSnone]:=@op_emit1_gn_np;
 jit_cbs[OPPnone,OPfsave  ,OPSnone]:=@op_emit1_gn_np;

 //fpu

 jit_cbs[OPPnone,OPprefetch,OPSnone ]:=@op_emit1_rw_np;
 jit_cbs[OPPnone,OPprefetch,OPSp_w  ]:=@op_emit1_rw_np;
 jit_cbs[OPPnone,OPprefetch,OPSp_nta]:=@op_emit1_rw_np;
 jit_cbs[OPPnone,OPprefetch,OPSp_t0 ]:=@op_emit1_rw_np;
 jit_cbs[OPPnone,OPprefetch,OPSp_t1 ]:=@op_emit1_rw_np;
 jit_cbs[OPPnone,OPprefetch,OPSp_t2 ]:=@op_emit1_rw_np;

 jit_cbs[OPPnone,OPfbstp,OPSnone    ]:=@op_emit1_wo_np;

end;

initialization
 init_cbs;

end.

