mirror of https://github.com/red-prig/fpPS4.git
2645 lines
50 KiB
Plaintext
2645 lines
50 KiB
Plaintext
unit kern_jit2_ctx;
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
{$CALLING SysV_ABI_CDecl}
|
|
|
|
interface
|
|
|
|
uses
|
|
vmparam,
|
|
vm_pmap,
|
|
systm,
|
|
g_node_splay,
|
|
x86_fpdbgdisas,
|
|
x86_jit;
|
|
|
|
{
|
|
change: rsp,rbp,rip
|
|
rax?
|
|
|
|
eflahs? temp change?
|
|
|
|
change: push/pop
|
|
|
|
thread: r15
|
|
|
|
}
|
|
|
|
type
|
|
p_jit_frame=^jit_frame;
|
|
jit_frame=packed record
|
|
tf_rax:QWORD;
|
|
tf_rsp:QWORD;
|
|
tf_rbp:QWORD;
|
|
tf_r14:QWORD;
|
|
tf_r15:QWORD;
|
|
end;
|
|
|
|
p_jit_context2=^t_jit_context2;
|
|
t_jit_context2=object
|
|
type
|
|
p_forward_link=^t_forward_link;
|
|
t_forward_link=object
|
|
next :p_forward_link;
|
|
label_id:t_jit_i_link;
|
|
end;
|
|
|
|
t_forward_links=object
|
|
root:p_forward_link;
|
|
procedure Resolve(_label:t_jit_i_link);
|
|
end;
|
|
|
|
p_forward_point=^t_forward_point;
|
|
t_forward_point=object
|
|
pLeft :p_forward_point;
|
|
pRight:p_forward_point;
|
|
dst :Pointer;
|
|
links :t_forward_links;
|
|
function c(n1,n2:p_forward_point):Integer; static;
|
|
end;
|
|
t_forward_set=specialize TNodeSplay<t_forward_point>;
|
|
|
|
p_label=^t_label;
|
|
t_label=object
|
|
pLeft :p_label;
|
|
pRight :p_label;
|
|
src :Pointer;
|
|
label_id:t_jit_i_link;
|
|
function c(n1,n2:p_label):Integer; static;
|
|
end;
|
|
t_label_set=specialize TNodeSplay<t_label>;
|
|
var
|
|
forward_set:t_forward_set;
|
|
label_set :t_label_set;
|
|
|
|
text_start:QWORD;
|
|
text___end:QWORD;
|
|
|
|
max:QWORD;
|
|
|
|
Code :Pointer;
|
|
ptr_curr:Pointer;
|
|
ptr_next:Pointer;
|
|
|
|
dis:TX86Disassembler;
|
|
din:TInstruction;
|
|
|
|
builder:t_jit_builder;
|
|
|
|
procedure add_forward_link(node:p_forward_point;label_id:t_jit_i_link);
|
|
function add_forward_point(label_id:t_jit_i_link;dst:Pointer):p_forward_point;
|
|
function add_forward_point(dst:Pointer):p_forward_point;
|
|
function max_forward_point():Pointer;
|
|
function fetch_forward_point(var links:t_forward_links;var dst:Pointer):Boolean;
|
|
function add_label(src:Pointer;label_id:t_jit_i_link):p_label;
|
|
function find_label(src:Pointer):t_jit_i_link;
|
|
end;
|
|
|
|
const
|
|
r_thrd:TRegValue=(AType:regGeneral;ASize:os64;AIndex:15); //r15
|
|
r_tmp0:TRegValue=(AType:regGeneral;ASize:os64;AIndex: 0); //rax
|
|
r_tmp1:TRegValue=(AType:regGeneral;ASize:os64;AIndex:14); //r14
|
|
|
|
OPERAND_BYTES:array[TOperandSize] of Word=(0,1,2,4,8,6,10,16,32,64,512);
|
|
|
|
function GetFrameOffset(const RegValue:TRegValue):Integer;
|
|
function GetFrameOffset(const r:TOperand):Integer;
|
|
function GetTargetOfs(var din:TInstruction;Code:PByte;id:Byte;var ofs:Int64):Boolean;
|
|
function is_preserved(const r:TRegValue):Boolean;
|
|
function is_preserved(const r:TOperand):Boolean;
|
|
function is_preserved(const r:TInstruction):Boolean;
|
|
function is_memory(const r:TOperand):Boolean;
|
|
function is_memory(const r:TInstruction):Boolean;
|
|
function is_invalid(const r:TInstruction):Boolean;
|
|
|
|
//in/out:rax uses:r14
|
|
procedure uplift_jit; assembler;
|
|
|
|
//in:rax(addr),r14b:(mem_size) out:ZF
|
|
procedure page_test; assembler;
|
|
|
|
//in:rax(addr),r14b:(size)
|
|
procedure copyout_mov; assembler;
|
|
|
|
//in:rax(addr),r14b:(size) out:rax
|
|
procedure copyin_mov; assembler;
|
|
|
|
type
|
|
t_memop_type1=(mo_reg,
|
|
mo_mem,
|
|
mo_ctx
|
|
);
|
|
|
|
t_memop_type2=(mo_reg_reg,
|
|
mo_mem_reg,
|
|
mo_reg_mem,
|
|
mo_reg_imm,
|
|
mo_mem_imm,
|
|
|
|
mo_ctx_reg,
|
|
mo_reg_ctx,
|
|
mo_ctx_ctx,
|
|
|
|
mo_mem_ctx,
|
|
|
|
mo_ctx_mem,
|
|
mo_ctx_imm
|
|
);
|
|
|
|
t_memop_shift=(mo_mem_imm8,
|
|
mo_reg_imm8,
|
|
|
|
mo_mem_cl,
|
|
mo_reg_cl,
|
|
|
|
mo_mem_one,
|
|
mo_reg_one,
|
|
|
|
mo_ctx_imm8,
|
|
mo_ctx_cl,
|
|
mo_ctx_one
|
|
);
|
|
|
|
t_op_hint=Set of (his_mov,
|
|
his_xor,
|
|
his_xchg,
|
|
his_rax,
|
|
his_rd,
|
|
his_rw,
|
|
his_align);
|
|
|
|
t_op_desc=packed record
|
|
mem_reg:t_op_type; //reg_reg
|
|
reg_mem:t_op_type; //reg_reg
|
|
reg_imm:t_op_type; //mem_imm
|
|
reg_im8:t_op_type; //mem_im8
|
|
hint:t_op_hint;
|
|
end;
|
|
|
|
t_op_shift=packed record
|
|
reg_im8:t_op_type; //mem_im8
|
|
mem__cl:t_op_type; //reg__cl
|
|
mem_one:t_op_type; //reg_one
|
|
end;
|
|
|
|
procedure build_lea(var ctx:t_jit_context2;id:Byte;reg:TRegValue;use_r_tmp1:Boolean=True);
|
|
|
|
function cmp_reg(const r1,r2:TRegValue):Boolean;
|
|
function new_reg(const Operand:TOperand):TRegValue;
|
|
function new_reg_size(const r:TRegValue;ASize:TOperandSize):TRegValue;
|
|
function new_reg_size(const r:TRegValue;const RegValue:TRegValues):TRegValue;
|
|
function new_reg_size(const r:TRegValue;const Operand:TOperand):TRegValue;
|
|
function fix_size(const r:TRegValue):TRegValue;
|
|
function flags(const i:TInstruction):t_jit_reg;
|
|
function flags(const ctx:t_jit_context2):t_jit_reg;
|
|
|
|
procedure add_orig(var ctx:t_jit_context2);
|
|
procedure op_load_rax(var ctx:t_jit_context2;reg:TRegValue);
|
|
procedure op_save_rax(var ctx:t_jit_context2;reg:TRegValue);
|
|
procedure op_emit1(var ctx:t_jit_context2;const desc:t_op_type;hint:t_op_hint);
|
|
procedure op_emit2(var ctx:t_jit_context2;const desc:t_op_desc);
|
|
procedure op_emit_shift(var ctx:t_jit_context2;const desc:t_op_shift);
|
|
procedure op_emit_avx2(var ctx:t_jit_context2;const desc:t_op_desc);
|
|
procedure op_emit_avx3(var ctx:t_jit_context2;const desc:t_op_type);
|
|
procedure op_emit_avx3_imm8(var ctx:t_jit_context2;const desc:t_op_type);
|
|
procedure op_emit_avx_F3(var ctx:t_jit_context2;const desc:t_op_type);
|
|
procedure op_emit_bmi_rmr(var ctx:t_jit_context2;const desc:t_op_type);
|
|
procedure op_emit_bmi_rrm(var ctx:t_jit_context2;const desc:t_op_type);
|
|
|
|
procedure print_disassemble(addr:Pointer;vsize:Integer);
|
|
|
|
implementation
|
|
|
|
procedure print_disassemble(addr:Pointer;vsize:Integer);
|
|
var
|
|
proc:TDbgProcess;
|
|
adec:TX86AsmDecoder;
|
|
ptr,fin:Pointer;
|
|
ACodeBytes,ACode:RawByteString;
|
|
begin
|
|
ptr:=addr;
|
|
fin:=addr+vsize;
|
|
|
|
proc:=TDbgProcess.Create(dm64);
|
|
adec:=TX86AsmDecoder.Create(proc);
|
|
|
|
while (ptr<fin) do
|
|
begin
|
|
adec.Disassemble(ptr,ACodeBytes,ACode);
|
|
Writeln(ACodeBytes:32,' ',ACode);
|
|
end;
|
|
|
|
adec.Free;
|
|
proc.Free;
|
|
end;
|
|
|
|
|
|
function t_jit_context2.t_forward_point.c(n1,n2:p_forward_point):Integer;
|
|
begin
|
|
Result:=Integer(n1^.dst>n2^.dst)-Integer(n1^.dst<n2^.dst);
|
|
end;
|
|
|
|
function t_jit_context2.t_label.c(n1,n2:p_label):Integer;
|
|
begin
|
|
Result:=Integer(n1^.src>n2^.src)-Integer(n1^.src<n2^.src);
|
|
end;
|
|
|
|
procedure t_jit_context2.add_forward_link(node:p_forward_point;label_id:t_jit_i_link);
|
|
var
|
|
link:p_forward_link;
|
|
begin
|
|
if (node=nil) or (label_id=nil_link) then Exit;
|
|
link:=builder.Alloc(Sizeof(t_forward_link));
|
|
link^.label_id:=label_id;
|
|
link^.next:=node^.links.root;
|
|
node^.links.root:=link;
|
|
end;
|
|
|
|
function t_jit_context2.add_forward_point(label_id:t_jit_i_link;dst:Pointer):p_forward_point;
|
|
var
|
|
node:t_forward_point;
|
|
begin
|
|
if (dst=nil) then Exit;
|
|
|
|
node.dst:=dst;
|
|
Result:=forward_set.Find(@node);
|
|
if (Result=nil) then
|
|
begin
|
|
Result:=builder.Alloc(Sizeof(t_forward_point));
|
|
Result^.dst:=dst;
|
|
forward_set.Insert(Result);
|
|
end;
|
|
add_forward_link(Result,label_id);
|
|
end;
|
|
|
|
function t_jit_context2.add_forward_point(dst:Pointer):p_forward_point;
|
|
begin
|
|
Result:=add_forward_point(nil_link,dst);
|
|
end;
|
|
|
|
function t_jit_context2.max_forward_point():Pointer;
|
|
var
|
|
entry:p_forward_point;
|
|
begin
|
|
Result:=nil;
|
|
entry:=forward_set.Max;
|
|
if (entry=nil) then Exit;
|
|
Result:=entry^.dst;
|
|
end;
|
|
|
|
function t_jit_context2.fetch_forward_point(var links:t_forward_links;var dst:Pointer):Boolean;
|
|
var
|
|
min:p_forward_point;
|
|
begin
|
|
Result:=False;
|
|
min:=forward_set.Min;
|
|
if (min=nil) then Exit;
|
|
forward_set._Splay(min);
|
|
min:=forward_set.pRoot;
|
|
forward_set.Delete(min);
|
|
dst :=min^.dst;
|
|
links:=min^.links;
|
|
Result:=True;
|
|
end;
|
|
|
|
procedure t_jit_context2.t_forward_links.Resolve(_label:t_jit_i_link);
|
|
var
|
|
node:p_forward_link;
|
|
begin
|
|
node:=root;
|
|
While (node<>nil) do
|
|
begin
|
|
node^.label_id._label:=_label;
|
|
node:=node^.next;
|
|
end;
|
|
end;
|
|
|
|
function t_jit_context2.add_label(src:Pointer;label_id:t_jit_i_link):p_label;
|
|
var
|
|
node:t_label;
|
|
begin
|
|
if (src=nil) then Exit;
|
|
node.src:=src;
|
|
Result:=label_set.Find(@node);
|
|
if (Result<>nil) then Exit;
|
|
Result:=builder.Alloc(Sizeof(t_label));
|
|
Result^.label_id:=label_id;
|
|
Result^.src :=src;
|
|
label_set.Insert(Result);
|
|
end;
|
|
|
|
function t_jit_context2.find_label(src:Pointer):t_jit_i_link;
|
|
var
|
|
node:t_label;
|
|
entry:p_label;
|
|
begin
|
|
Result:=nil_link;
|
|
node.src:=src;
|
|
entry:=label_set.Find(@node);
|
|
if (entry=nil) then Exit;
|
|
Result:=entry^.label_id;
|
|
end;
|
|
|
|
//
|
|
|
|
function GetFrameOffset(const RegValue:TRegValue):Integer;
|
|
begin
|
|
Result:=-1;
|
|
|
|
case RegValue.AType of
|
|
regGeneral:
|
|
begin
|
|
case RegValue.ASize of
|
|
os8,
|
|
os16,
|
|
os32,
|
|
os64:
|
|
begin
|
|
case RegValue.AIndex of
|
|
0:Result:=Integer(@p_jit_frame(nil)^.tf_rax);
|
|
4:Result:=Integer(@p_jit_frame(nil)^.tf_rsp);
|
|
5:Result:=Integer(@p_jit_frame(nil)^.tf_rbp);
|
|
14:Result:=Integer(@p_jit_frame(nil)^.tf_r14);
|
|
15:Result:=Integer(@p_jit_frame(nil)^.tf_r15);
|
|
else;
|
|
end;
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
regGeneralH:
|
|
begin
|
|
case RegValue.ASize of
|
|
os8:
|
|
begin
|
|
case RegValue.AIndex of
|
|
0:Result:=Integer(@p_jit_frame(nil)^.tf_rax)+1;
|
|
else;
|
|
end;
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
Assert(Result<>-1,'GetFrameOffset');
|
|
end;
|
|
|
|
function GetFrameOffset(const r:TOperand):Integer; inline;
|
|
begin
|
|
Result:=GetFrameOffset(r.RegValue[0])
|
|
end;
|
|
|
|
function GetTargetOfs(var din:TInstruction;Code:PByte;id:Byte;var ofs:Int64):Boolean;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Result:=True;
|
|
i:=din.Operand[id].CodeIndex;
|
|
case din.Operand[id].ByteCount of
|
|
1: ofs:=PShortint(@Code[i])^;
|
|
2: ofs:=PSmallint(@Code[i])^;
|
|
4: ofs:=PInteger (@Code[i])^;
|
|
8: ofs:=PInt64 (@Code[i])^;
|
|
else
|
|
Result:=False;
|
|
end;
|
|
end;
|
|
|
|
function is_preserved(const r:TRegValue):Boolean;
|
|
begin
|
|
Result:=False;
|
|
|
|
case r.AType of
|
|
regRip:Result:=True;
|
|
regGeneral:
|
|
begin
|
|
case r.AIndex of
|
|
0, //rax
|
|
4, //rsp
|
|
5, //rbp
|
|
14, //r14
|
|
15: //r15
|
|
Result:=True;
|
|
else;
|
|
end;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
end;
|
|
|
|
function is_preserved(const r:TRegValues):Boolean; inline;
|
|
begin
|
|
Result:=is_preserved(r[0]) or is_preserved(r[1]);
|
|
end;
|
|
|
|
function is_preserved(const r:TOperand):Boolean; inline;
|
|
begin
|
|
Result:=is_preserved(r.RegValue);
|
|
end;
|
|
|
|
function is_preserved(const r:TInstruction):Boolean;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Result:=False;
|
|
if (r.OperCnt<>0) then
|
|
For i:=1 to r.OperCnt do
|
|
begin
|
|
Result:=is_preserved(r.Operand[i]);
|
|
if Result then Exit;
|
|
end;
|
|
end;
|
|
|
|
function is_rip(const r:TRegValue):Boolean; inline;
|
|
begin
|
|
Result:=False;
|
|
case r.AType of
|
|
regRip:Result:=True;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function is_memory(const r:TOperand):Boolean; inline;
|
|
begin
|
|
Result:=ofMemory in r.Flags;
|
|
end;
|
|
|
|
function is_memory(const r:TInstruction):Boolean;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Result:=False;
|
|
if (r.OperCnt<>0) then
|
|
For i:=1 to r.OperCnt do
|
|
begin
|
|
Result:=is_memory(r.Operand[i]);
|
|
if Result then Exit;
|
|
end;
|
|
end;
|
|
|
|
function is_cl(const r:TRegValue):Boolean; inline;
|
|
begin
|
|
Result:=False;
|
|
if (r.ASize=os8) then
|
|
case r.AType of
|
|
regGeneral:
|
|
case r.AIndex of
|
|
1:Result:=True;
|
|
else;
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function is_one(const r:TRegValue):Boolean; inline;
|
|
begin
|
|
Result:=False;
|
|
case r.AType of
|
|
regOne:Result:=True;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function cmp_reg(const r1,r2:TRegValue):Boolean; inline;
|
|
begin
|
|
Result:=(r1.AType =r2.AType) and
|
|
(r1.ASize =r2.ASize) and
|
|
(r1.AIndex=r2.AIndex);
|
|
end;
|
|
|
|
function new_reg(const Operand:TOperand):TRegValue; inline;
|
|
begin
|
|
Result:=Operand.RegValue[0];
|
|
end;
|
|
|
|
function new_reg_size(const r:TRegValue;ASize:TOperandSize):TRegValue; inline;
|
|
begin
|
|
Result:=r;
|
|
Result.ASize:=ASize;
|
|
end;
|
|
|
|
function new_reg_size(const r:TRegValue;const RegValue:TRegValues):TRegValue; inline;
|
|
begin
|
|
Result:=new_reg_size(r,RegValue[0].ASize);
|
|
end;
|
|
|
|
function new_reg_size(const r:TRegValue;const Operand:TOperand):TRegValue; inline;
|
|
begin
|
|
Result:=new_reg_size(r,Operand.RegValue[0].ASize);
|
|
end;
|
|
|
|
function fix_size(const r:TRegValue):TRegValue; inline;
|
|
begin
|
|
Result:=r;
|
|
if (Result.ASize=os32) then
|
|
begin
|
|
Result.ASize:=os64;
|
|
end;
|
|
end;
|
|
|
|
function flags(const i:TInstruction):t_jit_reg;
|
|
begin
|
|
Result:=Default(t_jit_reg);
|
|
|
|
if (ifPrefixLock in i.Flags) then
|
|
begin
|
|
Result:=Result+t_jit_builder.LOCK;
|
|
end;
|
|
|
|
if (ifPrefixRep in i.Flags) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
if (ifPrefixRepE in i.Flags) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
if (ifPrefixRepNe in i.Flags) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
case i.SegmentReg of
|
|
4:Result:=Result+t_jit_builder.FS;
|
|
5:Result:=Result+t_jit_builder.GS;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
function flags(const ctx:t_jit_context2):t_jit_reg; inline;
|
|
begin
|
|
Result:=flags(ctx.din);
|
|
end;
|
|
|
|
procedure add_orig(var ctx:t_jit_context2);
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
Move(ctx.code^,ji.AData,ctx.dis.CodeIdx);
|
|
|
|
ji.ASize:=ctx.dis.CodeIdx;
|
|
|
|
ctx.builder._add(ji);
|
|
end;
|
|
|
|
function is_invalid(const r:TOperand):Boolean; inline;
|
|
begin
|
|
Result:=(r.RegValue[0].AType=regInvalid) or
|
|
(r.RegValue[1].AType=regInvalid);
|
|
end;
|
|
|
|
function is_invalid(const r:TInstruction):Boolean;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Result:=False;
|
|
if (r.OperCnt<>0) then
|
|
For i:=1 to r.OperCnt do
|
|
begin
|
|
Result:=is_invalid(r.Operand[i]);
|
|
if Result then Exit;
|
|
end;
|
|
end;
|
|
|
|
//in/out:rax uses:r14
|
|
procedure uplift_jit; assembler; nostackframe;
|
|
label
|
|
_exit;
|
|
asm
|
|
pushfq
|
|
push %r14
|
|
//
|
|
//low addr (r14)
|
|
mov %rax,%r14
|
|
and PAGE_MASK,%r14
|
|
//high addr (rax)
|
|
shr PAGE_SHIFT ,%rax
|
|
and PAGE_MAP_MASK,%rax
|
|
//uplift (rax)
|
|
mov PAGE_MAP,%rax
|
|
mov (%rax,%rax,4),%edi
|
|
//filter (rax)
|
|
and PAGE_OFS_MASK,%rax
|
|
jz _exit
|
|
//combine (rax|r14)
|
|
shl PAGE_SHIFT,%rax
|
|
or %r14,%rax
|
|
_exit:
|
|
//
|
|
pop %r14
|
|
popfq
|
|
end;
|
|
|
|
//in:rax(addr),r14b:(mem_size) out:ZF
|
|
procedure page_test; assembler; nostackframe;
|
|
label
|
|
_exit;
|
|
asm
|
|
push %rdi
|
|
push %rsi
|
|
//
|
|
mov %rax,%rdi
|
|
movzbq %r14b,%rsi
|
|
sub $1,%rsi
|
|
//addr2:=addr+mem_high (rsi)
|
|
add %rdi,%rsi
|
|
//high addr (rdi,rsi)
|
|
shr PAGE_SHIFT ,%rdi
|
|
shr PAGE_SHIFT ,%rsi
|
|
and PAGE_MAP_MASK,%rdi
|
|
and PAGE_MAP_MASK,%rsi
|
|
//
|
|
cmp %rdi,%rsi
|
|
je _exit
|
|
//uplift (rdi,rsi)
|
|
lea (,%rdi,4),%rdi
|
|
lea (,%rsi,4),%rsi
|
|
//
|
|
add PAGE_MAP,%rdi
|
|
add PAGE_MAP,%rsi
|
|
//
|
|
mov (%rdi),%edi
|
|
mov (%rsi),%esi
|
|
//filter (rdi,rsi)
|
|
and PAGE_OFS_MASK,%rdi
|
|
and PAGE_OFS_MASK,%rsi
|
|
//
|
|
cmp %rdi,%rsi
|
|
_exit:
|
|
//
|
|
pop %rsi
|
|
pop %rdi
|
|
end;
|
|
|
|
//in:rax(addr),r14b:(size)
|
|
procedure copyout_mov; assembler;
|
|
label
|
|
_simple;
|
|
var
|
|
data:array[0..31] of Byte;
|
|
asm
|
|
pushfq
|
|
//
|
|
call page_test
|
|
je _simple
|
|
|
|
popfq //restore flags before call
|
|
|
|
push %rdi
|
|
push %rsi
|
|
push %rdx
|
|
push %rcx
|
|
push %r8
|
|
push %r9
|
|
push %r10
|
|
push %r11
|
|
|
|
push %rax
|
|
|
|
mov data,%rax
|
|
|
|
mov 8(%rbp) ,%rdi //ret addr
|
|
lea (,%rdi,2),%rdi //jmp near
|
|
|
|
call %rdi //reg->data
|
|
|
|
pop %rsi //vaddr
|
|
mov data,%rdi //data
|
|
movzbq %r14b,%rdx //size
|
|
|
|
pushfq
|
|
|
|
call copyout
|
|
|
|
popfq
|
|
|
|
pop %r11
|
|
pop %r10
|
|
pop %r9
|
|
pop %r8
|
|
pop %rcx
|
|
pop %rdx
|
|
pop %rsi
|
|
pop %rdi
|
|
|
|
ret
|
|
_simple:
|
|
|
|
call uplift_jit
|
|
|
|
mov 8(%rbp) ,%r14 //ret addr
|
|
lea (,%r14,2),%r14 //jmp near
|
|
|
|
popfq //restore flags before call
|
|
|
|
call %r14 //reg->data
|
|
|
|
end;
|
|
|
|
//in:rax(addr),r14b:(size) out:rax
|
|
procedure copyin_mov; assembler;
|
|
label
|
|
_simple,
|
|
_exit;
|
|
var
|
|
data:array[0..31] of Byte;
|
|
asm
|
|
pushfq
|
|
//
|
|
call page_test
|
|
je _simple
|
|
|
|
push %rdi
|
|
push %rsi
|
|
push %rdx
|
|
push %rcx
|
|
push %r8
|
|
push %r9
|
|
push %r10
|
|
push %r11
|
|
|
|
mov %rax,%rdi //vaddr
|
|
mov data,%rsi //data
|
|
movzbq %r14b,%rdx //size
|
|
|
|
call copyin
|
|
|
|
pop %r11
|
|
pop %r10
|
|
pop %r9
|
|
pop %r8
|
|
pop %rcx
|
|
pop %rdx
|
|
pop %rsi
|
|
pop %rdi
|
|
|
|
mov data,%rax //vaddr:=data
|
|
|
|
jmp _exit
|
|
_simple:
|
|
|
|
call uplift_jit
|
|
|
|
_exit:
|
|
//
|
|
popfq
|
|
end;
|
|
|
|
procedure add_rip_entry(var ctx:t_jit_context2;ofs:Int64);
|
|
begin
|
|
if (ctx.max<>0) and
|
|
(ofs<=ctx.max) then
|
|
if ((pmap_get_raw(QWORD(ofs)) and PAGE_PROT_EXECUTE)<>0) then
|
|
begin
|
|
ctx.add_forward_point(Pointer(ofs));
|
|
end;
|
|
end;
|
|
|
|
procedure build_lea(var ctx:t_jit_context2;id:Byte;reg:TRegValue;use_r_tmp1:Boolean=True);
|
|
var
|
|
RegValue:TRegValues;
|
|
adr,new1,new2:TRegValue;
|
|
ofs:Int64;
|
|
i:Integer;
|
|
AScale:Byte;
|
|
begin
|
|
RegValue:=ctx.din.Operand[id].RegValue;
|
|
|
|
adr:=new_reg_size(reg,RegValue);
|
|
|
|
if (adr.ASize=os0) then
|
|
begin
|
|
adr.ASize:=os64;
|
|
end;
|
|
|
|
with ctx.builder do
|
|
begin
|
|
if (adr.ASize<>os64) then
|
|
begin
|
|
xorq(reg,reg);
|
|
end;
|
|
|
|
if (RegValue[0].AType=regNone) then //absolute offset
|
|
begin
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,id,ofs);
|
|
|
|
if (classif_offset_se64(ofs)=os64) then
|
|
begin
|
|
movi64(adr,ofs);
|
|
end else
|
|
begin
|
|
movi(adr,ofs);
|
|
end;
|
|
end else
|
|
if is_rip(RegValue[0]) then
|
|
begin
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,id,ofs);
|
|
ofs:=Int64(ctx.ptr_next)+ofs;
|
|
|
|
add_rip_entry(ctx,ofs);
|
|
|
|
if (classif_offset_se64(ofs)=os64) then
|
|
begin
|
|
movi64(adr,ofs);
|
|
end else
|
|
begin
|
|
movi(adr,ofs);
|
|
end;
|
|
end else
|
|
if is_preserved(RegValue) then
|
|
begin
|
|
|
|
if (RegValue[0].AType<>regNone) and
|
|
(RegValue[1].AType<>regNone) and
|
|
(not is_preserved(RegValue[0])) and
|
|
(is_preserved(RegValue[1])) and
|
|
(RegValue[0].AScale<=1) then
|
|
begin
|
|
//optimal swap
|
|
new1:=RegValue[0];
|
|
RegValue[0]:=RegValue[1];
|
|
RegValue[1]:=new1;
|
|
end;
|
|
|
|
AScale:=RegValue[0].AScale;
|
|
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,id,ofs);
|
|
|
|
if is_preserved(RegValue[0]) then
|
|
begin
|
|
i:=GetFrameOffset(RegValue[0]);
|
|
movq(adr,[r_thrd+i]);
|
|
|
|
if (AScale>1) or (ofs<>0) then
|
|
begin
|
|
leaq(adr,[adr*AScale+ofs]);
|
|
end;
|
|
end else
|
|
begin
|
|
new1:=RegValue[0];
|
|
//
|
|
//AScale in new
|
|
leaq(adr,[new1+ofs]);
|
|
end;
|
|
|
|
if (RegValue[1].AType<>regNone) then
|
|
begin
|
|
|
|
if is_preserved(RegValue[1]) then
|
|
begin
|
|
i:=GetFrameOffset(RegValue[1]);
|
|
|
|
if use_r_tmp1 then
|
|
begin
|
|
new2:=new_reg_size(r_tmp1,adr.ASize);
|
|
|
|
movq(new2,[r_thrd+i]);
|
|
leaq(adr,[adr+new2]);
|
|
end else
|
|
begin
|
|
pushfq(os64);
|
|
addq(adr,[r_thrd+i]);
|
|
popfq(os64);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
new1:=RegValue[1];
|
|
leaq(adr,[adr+new1]);
|
|
end;
|
|
|
|
end;
|
|
end else
|
|
begin
|
|
ofs:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,id,ofs);
|
|
|
|
new1:=RegValue[0];
|
|
|
|
if (RegValue[1].AType<>regNone) then
|
|
begin
|
|
new2:=RegValue[1];
|
|
//
|
|
//AScale in new
|
|
leaq(adr,[new1+new2+ofs]);
|
|
end else
|
|
begin
|
|
//AScale in new
|
|
leaq(adr,[new1+ofs]);
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
function get_lea_id(memop:t_memop_type2):Byte;
|
|
begin
|
|
case memop of
|
|
mo_mem_reg:Result:=1;
|
|
mo_reg_mem:Result:=2;
|
|
mo_mem_imm:Result:=1;
|
|
mo_mem_ctx:Result:=1;
|
|
mo_ctx_mem:Result:=2;
|
|
else
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
|
|
function classif_memop1(var din:TInstruction):t_memop_type1;
|
|
begin
|
|
if (ofMemory in din.Operand[1].Flags) then
|
|
begin
|
|
Result:=mo_mem;
|
|
end else
|
|
if is_preserved(din.Operand[1]) then
|
|
begin
|
|
Result:=mo_ctx;
|
|
end else
|
|
begin
|
|
Result:=mo_reg;
|
|
end;
|
|
end;
|
|
|
|
function classif_memop2(var din:TInstruction):t_memop_type2;
|
|
begin
|
|
if (ofMemory in din.Operand[1].Flags) then
|
|
begin
|
|
if (din.Operand[2].ByteCount<>0) then
|
|
begin
|
|
Result:=mo_mem_imm;
|
|
end else
|
|
if is_preserved(din.Operand[2]) then
|
|
begin
|
|
Result:=mo_mem_ctx;
|
|
end else
|
|
begin
|
|
Result:=mo_mem_reg;
|
|
end;
|
|
end else
|
|
if (ofMemory in din.Operand[2].Flags) then
|
|
begin
|
|
if is_preserved(din.Operand[1]) then
|
|
begin
|
|
Result:=mo_ctx_mem;
|
|
end else
|
|
begin
|
|
Result:=mo_reg_mem;
|
|
end;
|
|
end else
|
|
if (din.Operand[2].ByteCount<>0) then
|
|
begin
|
|
if is_preserved(din.Operand[1]) then
|
|
begin
|
|
Result:=mo_ctx_imm;
|
|
end else
|
|
begin
|
|
Result:=mo_reg_imm;
|
|
end;
|
|
end else
|
|
if is_preserved(din.Operand[1]) and
|
|
is_preserved(din.Operand[2]) then
|
|
begin
|
|
Result:=mo_ctx_ctx;
|
|
end else
|
|
if is_preserved(din.Operand[1]) then
|
|
begin
|
|
Result:=mo_ctx_reg;
|
|
end else
|
|
if is_preserved(din.Operand[2]) then
|
|
begin
|
|
Result:=mo_reg_ctx;
|
|
end else
|
|
begin
|
|
Result:=mo_reg_reg;
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
function classif_shift2(var din:TInstruction):t_memop_shift;
|
|
begin
|
|
if (ofMemory in din.Operand[1].Flags) then
|
|
begin
|
|
if (din.Operand[2].ByteCount<>0) then
|
|
begin
|
|
Assert(din.Operand[2].Size=os8);
|
|
Result:=mo_mem_imm8;
|
|
end else
|
|
if is_cl(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_mem_cl;
|
|
end else
|
|
if is_one(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_mem_one;
|
|
end else
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
end else
|
|
if is_preserved(din.Operand[1]) then
|
|
begin
|
|
if (din.Operand[2].ByteCount<>0) then
|
|
begin
|
|
Assert(din.Operand[2].Size=os8);
|
|
Result:=mo_ctx_imm8;
|
|
end else
|
|
if is_cl(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_ctx_cl;
|
|
end else
|
|
if is_one(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_ctx_one;
|
|
end else
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
end else
|
|
if (din.Operand[2].ByteCount<>0) then
|
|
begin
|
|
Assert(din.Operand[2].Size=os8);
|
|
Result:=mo_reg_imm8;
|
|
end else
|
|
if is_cl(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_reg_cl;
|
|
end else
|
|
if is_one(din.Operand[2].RegValue[0]) then
|
|
begin
|
|
Result:=mo_reg_one;
|
|
end else
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
end;
|
|
|
|
procedure op_load_rax(var ctx:t_jit_context2;reg:TRegValue);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
i:=GetFrameOffset(rax);
|
|
movq(reg,[r_thrd+i]);
|
|
end;
|
|
end;
|
|
|
|
procedure op_save_rax(var ctx:t_jit_context2;reg:TRegValue);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
i:=GetFrameOffset(rax);
|
|
movq([r_thrd+i],reg);
|
|
end;
|
|
end;
|
|
|
|
procedure op_emit1(var ctx:t_jit_context2;const desc:t_op_type;hint:t_op_hint);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_type1;
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
_M(desc,mem_size,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
end;
|
|
|
|
procedure mem_in_rax;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
movq(r_tmp1,r_tmp0);
|
|
|
|
op_load_rax(ctx,rax);
|
|
|
|
_M(desc,mem_size,[flags(ctx)+r_tmp1]);
|
|
|
|
op_save_rax(ctx,rax);
|
|
end;
|
|
end;
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
_M(desc,mem_size,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
memop:=classif_memop1(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem:
|
|
begin
|
|
|
|
if (his_rax in hint) then
|
|
begin
|
|
//RAX:=RAX X [mem]
|
|
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (mem_size=os8) or
|
|
(his_rw in hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in_rax;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in_rax;
|
|
end;
|
|
|
|
end else
|
|
if (his_rd in hint) then
|
|
begin
|
|
//DATA:=[mem]
|
|
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (mem_size=os8) or
|
|
(his_rw in hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
//[mem]:=DATA
|
|
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (mem_size=os8) or
|
|
(his_rw in hint) then
|
|
begin
|
|
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
mo_ctx:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
mem_size:=os64; //fix size
|
|
end;
|
|
|
|
if (his_rax in hint) then
|
|
begin
|
|
op_load_rax(ctx,rax);
|
|
end;
|
|
|
|
_M(desc,mem_size,[r_thrd+i]);
|
|
|
|
if (his_rax in hint) then
|
|
begin
|
|
op_save_rax(ctx,rax);
|
|
end;
|
|
end;
|
|
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_emit2(var ctx:t_jit_context2;const desc:t_op_desc);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_type2;
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
imm:Int64;
|
|
imm_size:TOperandSize;
|
|
|
|
new1,new2:TRegValue;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg(ctx.din.Operand[2]);
|
|
|
|
if (his_rax in desc.hint) then
|
|
begin
|
|
new2:=new_reg_size(rax,ctx.din.Operand[2]);
|
|
|
|
movq(r_tmp1,r_tmp0);
|
|
|
|
op_load_rax(ctx,fix_size(new2));
|
|
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r_tmp1]);
|
|
|
|
op_save_rax(ctx,fix_size(new2));
|
|
end else
|
|
begin
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
|
|
end;
|
|
mo_mem_imm:
|
|
begin
|
|
//input:rax
|
|
|
|
imm:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,2,imm);
|
|
|
|
imm_size:=ctx.din.Operand[2].Size;
|
|
|
|
Assert(imm_size<>os64);
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_MI8(desc.reg_im8,mem_size,[flags(ctx)+r_tmp0],imm);
|
|
end else
|
|
begin
|
|
_MI(desc.reg_imm,mem_size,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
|
|
end;
|
|
mo_mem_ctx:
|
|
begin
|
|
//input:rax
|
|
|
|
if (his_rax in desc.hint) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(new1,[r_thrd+i]);
|
|
|
|
push(r15);
|
|
|
|
op_load_rax(ctx,r15);
|
|
|
|
xchgq(r15,rax);
|
|
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r15]);
|
|
|
|
pop(r15);
|
|
|
|
op_save_rax(ctx,rax);
|
|
end else
|
|
begin
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(new1,[r_thrd+i]);
|
|
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r_tmp0]);
|
|
|
|
if (his_xchg in desc.hint) then
|
|
begin
|
|
movq([r_thrd+i],new1);
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_reg_mem:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RMI8(desc.reg_im8,new1,[flags(ctx)+r_tmp0],imm);
|
|
end else
|
|
begin
|
|
_RMI(desc.reg_imm,new1,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
_RM(desc.reg_mem,new1,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
|
|
end;
|
|
mo_ctx_mem:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
if (not (his_mov in desc.hint)) or
|
|
(new1.ASize in [os8,os16]) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq(fix_size(new1),[r_thrd+i]);
|
|
end;
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RMI8(desc.reg_im8,new1,[flags(ctx)+r_tmp0],imm);
|
|
end else
|
|
begin
|
|
_RMI(desc.reg_imm,new1,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
_RM(desc.reg_mem,new1,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
|
|
if not (his_rd in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
|
|
end;
|
|
|
|
//read only swapped
|
|
|
|
mo_mem_reg:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RMI8(desc.reg_im8,new1,[flags(ctx)+r_tmp0],imm);
|
|
end else
|
|
begin
|
|
_RMI(desc.reg_imm,new1,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
|
|
end;
|
|
|
|
mo_mem_ctx:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new1),[r_thrd+i]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RMI8(desc.reg_im8,new1,[flags(ctx)+r_tmp0],imm);
|
|
end else
|
|
begin
|
|
_RMI(desc.reg_imm,new1,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
_RM(desc.mem_reg,new1,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
|
|
end;
|
|
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
memop:=classif_memop2(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg,
|
|
mo_reg_mem,
|
|
mo_mem_imm,
|
|
mo_mem_ctx,
|
|
mo_ctx_mem:
|
|
begin
|
|
build_lea(ctx,get_lea_id(memop),r_tmp0);
|
|
mem_size:=ctx.din.Operand[get_lea_id(memop)].Size;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg,
|
|
mo_mem_imm,
|
|
mo_mem_ctx:
|
|
begin
|
|
if (his_rd in desc.hint) then
|
|
begin
|
|
|
|
if (mem_size=os8) or
|
|
(his_rw in desc.hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
|
|
end else
|
|
if (mem_size=os8) or
|
|
(his_rw in desc.hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
end;
|
|
|
|
mo_reg_mem,
|
|
mo_ctx_mem:
|
|
begin
|
|
if (mem_size=os8) or
|
|
(his_rw in desc.hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
end;
|
|
|
|
mo_ctx_reg:
|
|
begin
|
|
new1:=new_reg(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RRI8(desc.reg_im8,new1,new2,imm,mem_size); //swapped
|
|
end else
|
|
begin
|
|
_RRI(desc.reg_imm,new1,new2,imm,mem_size); //swapped
|
|
end;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new2));
|
|
|
|
end else
|
|
if (his_rax in desc.hint) then
|
|
begin
|
|
new2:=new_reg_size(rax,ctx.din.Operand[1]);
|
|
|
|
op_load_rax(ctx,fix_size(new2));
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
_RM(desc.mem_reg,new1,[r_thrd+i]);
|
|
|
|
op_save_rax(ctx,fix_size(new2));
|
|
end else
|
|
if (new1.ASize=os32) or
|
|
(not_impl in desc.mem_reg.opt) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
|
|
if (not (his_mov in desc.hint)) or
|
|
(his_rd in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
end;
|
|
|
|
mem_size:=ctx.din.Operand[1].RegValue[0].ASize;
|
|
|
|
if (not_impl in desc.mem_reg.opt) then
|
|
begin
|
|
_RR(desc.reg_mem,new1,new2,mem_size); //swapped
|
|
end else
|
|
begin
|
|
_RR(desc.mem_reg,new2,new1,mem_size);
|
|
end;
|
|
|
|
if not (his_rd in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new2));
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
_RM(desc.mem_reg,new1,[r_thrd+i]);
|
|
end;
|
|
|
|
end;
|
|
mo_reg_ctx:
|
|
begin
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RMI8(desc.reg_im8,new1,[r_thrd+i],imm);
|
|
end else
|
|
begin
|
|
_RMI(desc.reg_imm,new1,[r_thrd+i],imm);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
|
|
if (not_impl in desc.reg_mem.opt) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
|
|
mem_size:=ctx.din.Operand[1].RegValue[0].ASize;
|
|
|
|
_RR(desc.mem_reg,new1,new2,mem_size);
|
|
end else
|
|
begin
|
|
_RM(desc.reg_mem,new1,[r_thrd+i]);
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
mo_ctx_ctx:
|
|
begin
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,3,imm) then
|
|
begin
|
|
imm_size:=ctx.din.Operand[3].Size;
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_RRI8(desc.reg_im8,new2,new1,imm,mem_size); //swapped
|
|
end else
|
|
begin
|
|
_RRI(desc.reg_imm,new2,new1,imm,mem_size); //swapped
|
|
end;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end else
|
|
begin
|
|
|
|
if cmp_reg(ctx.din.Operand[1].RegValue[0],
|
|
ctx.din.Operand[2].RegValue[0]) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new1;
|
|
|
|
if not (his_xor in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq(fix_size(new1),[r_thrd+i]);
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
if (not (his_mov in desc.hint)) or
|
|
(his_rd in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq(fix_size(new1),[r_thrd+i]);
|
|
end;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
end;
|
|
|
|
mem_size:=ctx.din.Operand[1].RegValue[0].ASize;
|
|
|
|
if (his_mov in desc.hint) and
|
|
(not (not_impl in desc.mem_reg.opt)) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
_RM(desc.mem_reg,fix_size(new2),[r_thrd+i]);
|
|
end else
|
|
begin
|
|
if (not_impl in desc.mem_reg.opt) then
|
|
begin
|
|
_RR(desc.reg_mem,new2,new1,mem_size); //swapped
|
|
end else
|
|
begin
|
|
_RR(desc.mem_reg,new1,new2,mem_size);
|
|
end;
|
|
|
|
if not (his_rd in desc.hint) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
|
|
end;
|
|
mo_ctx_imm:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
imm:=0;
|
|
if not GetTargetOfs(ctx.din,ctx.code,2,imm) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
imm_size:=ctx.din.Operand[2].Size;
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
mem_size:=os64; //fix size
|
|
end;
|
|
|
|
if (imm_size=os8) and
|
|
(mem_size<>os8) and
|
|
(not (not_impl in desc.reg_im8.opt)) then
|
|
begin
|
|
_MI8(desc.reg_im8,mem_size,[r_thrd+i],imm);
|
|
end else
|
|
if (imm_size=os64) and
|
|
(classif_offset_se64(imm)=os64) then
|
|
begin
|
|
Assert(his_mov in desc.hint);
|
|
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
|
|
movi64(new1,imm);
|
|
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end else
|
|
begin
|
|
_MI(desc.reg_imm,mem_size,[r_thrd+i],imm);
|
|
end;
|
|
|
|
end;
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
procedure op_emit_shift(var ctx:t_jit_context2;const desc:t_op_shift);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_shift;
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
imm:Int64;
|
|
imm_size:TOperandSize;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_imm8:
|
|
begin
|
|
//input:rax
|
|
|
|
imm:=0;
|
|
if not GetTargetOfs(ctx.din,ctx.code,2,imm) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
imm_size:=ctx.din.Operand[2].Size;
|
|
|
|
Assert(imm_size=os8);
|
|
Assert(not (not_impl in desc.reg_im8.opt));
|
|
|
|
_MI8(desc.reg_im8,mem_size,[flags(ctx)+r_tmp0],imm);
|
|
end;
|
|
mo_mem_cl:
|
|
begin
|
|
//input:rax
|
|
|
|
_M(desc.mem__cl,mem_size,[flags(ctx)+r_tmp0]);
|
|
end;
|
|
mo_mem_one:
|
|
begin
|
|
//input:rax
|
|
|
|
_M(desc.mem_one,mem_size,[flags(ctx)+r_tmp0]);
|
|
end
|
|
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
memop:=classif_shift2(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_imm8,
|
|
mo_mem_cl,
|
|
mo_mem_one:
|
|
begin
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_imm8,
|
|
mo_mem_cl,
|
|
mo_mem_one:
|
|
begin
|
|
if (mem_size=os8) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
end;
|
|
|
|
mo_ctx_imm8:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
imm:=0;
|
|
if not GetTargetOfs(ctx.din,ctx.code,2,imm) then
|
|
begin
|
|
Assert(false);
|
|
end;
|
|
|
|
imm_size:=ctx.din.Operand[2].Size;
|
|
Assert(imm_size=os8);
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
mem_size:=os64; //fix size
|
|
end;
|
|
|
|
_MI8(desc.reg_im8,mem_size,[r_thrd+i],imm);
|
|
end;
|
|
mo_ctx_cl:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
mem_size:=os64; //fix size
|
|
end;
|
|
|
|
_M(desc.mem__cl,mem_size,[r_thrd+i]);
|
|
end;
|
|
mo_ctx_one:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
mem_size:=os64; //fix size
|
|
end;
|
|
|
|
_M(desc.mem_one,mem_size,[r_thrd+i]);
|
|
end;
|
|
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
//
|
|
|
|
procedure op_emit_avx2(var ctx:t_jit_context2;const desc:t_op_desc);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_type2;
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
new:TRegValue;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
new:=new_reg(ctx.din.Operand[2]);
|
|
_VM(desc.mem_reg,new,[flags(ctx)+r_tmp0],mem_size);
|
|
end;
|
|
end;
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
new:=new_reg(ctx.din.Operand[1]);
|
|
_VM(desc.reg_mem,new,[flags(ctx)+r_tmp0],mem_size);
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
memop:=classif_memop2(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg,
|
|
mo_reg_mem:
|
|
begin
|
|
build_lea(ctx,get_lea_id(memop),r_tmp0);
|
|
mem_size:=ctx.din.Operand[get_lea_id(memop)].Size;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg:
|
|
begin
|
|
if (his_align in desc.hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
end;
|
|
|
|
mo_reg_mem:
|
|
begin
|
|
if (his_align in desc.hint) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
end;
|
|
|
|
mo_ctx_reg:
|
|
begin
|
|
new:=new_reg(ctx.din.Operand[2]);
|
|
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
_VM(desc.mem_reg,new,[r_thrd+i],mem_size);
|
|
end;
|
|
mo_reg_ctx:
|
|
begin
|
|
new:=new_reg(ctx.din.Operand[1]);
|
|
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
_VM(desc.reg_mem,new,[r_thrd+i],mem_size);
|
|
end;
|
|
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_emit_avx3(var ctx:t_jit_context2;const desc:t_op_type);
|
|
var
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
i:Integer;
|
|
imm:Int64;
|
|
|
|
new1,new2:TRegValue;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
new1:=new_reg(ctx.din.Operand[2]);
|
|
new2:=new_reg(ctx.din.Operand[3]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,4,imm) then
|
|
begin
|
|
_VVMI8(desc,new2,new1,[flags(ctx)+r_tmp0],mem_size,imm);
|
|
end else
|
|
begin
|
|
_VVM(desc,new2,new1,[flags(ctx)+r_tmp0],mem_size); //[mem],arg2,arg3 -> arg3,arg2,[mem]
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,4,imm) then
|
|
begin
|
|
_VVMI8(desc,new1,new2,[flags(ctx)+r_tmp0],mem_size,imm);
|
|
end else
|
|
begin
|
|
_VVM(desc,new1,new2,[flags(ctx)+r_tmp0],mem_size);
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
if (ofMemory in ctx.din.Operand[3].Flags) then
|
|
begin
|
|
//mo_reg_reg_mem
|
|
|
|
build_lea(ctx,3,r_tmp0);
|
|
mem_size:=ctx.din.Operand[3].Size;
|
|
|
|
with ctx.builder do
|
|
begin
|
|
|
|
if false then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
|
|
end;
|
|
|
|
end else
|
|
if is_preserved(ctx.din.Operand[3]) then
|
|
begin
|
|
//mo_reg_reg_ctx
|
|
|
|
with ctx.builder do
|
|
begin
|
|
|
|
mem_size:=ctx.din.Operand[3].Size;
|
|
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[3]);
|
|
|
|
imm:=0;
|
|
if GetTargetOfs(ctx.din,ctx.code,4,imm) then
|
|
begin
|
|
_VVMI8(desc,new1,new2,[r_thrd+i],mem_size,imm);
|
|
end else
|
|
begin
|
|
_VVM(desc,new1,new2,[r_thrd+i],mem_size);
|
|
end;
|
|
|
|
end;
|
|
|
|
end else
|
|
if (ofMemory in ctx.din.Operand[1].Flags) then
|
|
begin
|
|
//mo_mem_reg_reg
|
|
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
with ctx.builder do
|
|
begin
|
|
|
|
if false then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
Assert(False);
|
|
end;
|
|
end;
|
|
|
|
//rri,mri
|
|
procedure op_emit_avx3_imm8(var ctx:t_jit_context2;const desc:t_op_type);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_type2;
|
|
mem_size:TOperandSize;
|
|
link_next:t_jit_i_link;
|
|
|
|
new1,new2:TRegValue;
|
|
|
|
imm:Int64;
|
|
|
|
procedure mem_out;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
//mem_reg
|
|
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,3,imm);
|
|
|
|
_MVI8(desc,[flags(ctx)+r_tmp0],new2,imm);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
//input:rax
|
|
|
|
//reg_mem
|
|
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
|
|
imm:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,3,imm);
|
|
|
|
_MVI8(desc,[flags(ctx)+r_tmp0],new2,imm);
|
|
end;
|
|
end;
|
|
|
|
|
|
begin
|
|
memop:=classif_memop2(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_mem_reg:
|
|
begin
|
|
build_lea(ctx,1,r_tmp0);
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
if (mem_size=os8) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_out;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyout_mov); //in:rax(addr),r14:(size)
|
|
|
|
link_next:=jmp8(nil_link);
|
|
|
|
mem_out;
|
|
|
|
reta;
|
|
|
|
link_next._label:=get_curr_label.after;
|
|
end;
|
|
end;
|
|
|
|
mo_reg_mem:
|
|
begin
|
|
build_lea(ctx,2,r_tmp0);
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
if (mem_size=os8) then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
end;
|
|
|
|
mo_ctx_reg:
|
|
begin
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
|
|
imm:=0;
|
|
GetTargetOfs(ctx.din,ctx.code,3,imm);
|
|
|
|
if (mem_size=os32) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
|
|
_VVI8(desc,new1,new2,imm);
|
|
|
|
movq([r_thrd+i],new1);
|
|
end else
|
|
begin
|
|
_MVI8(desc,[r_thrd+i],new2,imm);
|
|
end;
|
|
end;
|
|
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_emit_avx_F3(var ctx:t_jit_context2;const desc:t_op_type);
|
|
var
|
|
i:Integer;
|
|
memop:t_memop_type2;
|
|
mem_size:TOperandSize;
|
|
|
|
new1,new2:TRegValue;
|
|
|
|
procedure mem_in;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
case memop of
|
|
mo_reg_mem:
|
|
begin
|
|
//input:rax
|
|
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
_VM_F3(desc,new1,[flags(ctx)+r_tmp0],mem_size);
|
|
end;
|
|
mo_ctx_mem:
|
|
begin
|
|
//input:rax
|
|
|
|
//load?
|
|
|
|
new1:=new_reg_size(r_tmp1,ctx.din.Operand[1]);
|
|
_VM_F3(desc,new1,[flags(ctx)+r_tmp0],mem_size);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
begin
|
|
memop:=classif_memop2(ctx.din);
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_reg_mem,
|
|
mo_ctx_mem:
|
|
begin
|
|
build_lea(ctx,get_lea_id(memop),r_tmp0);
|
|
mem_size:=ctx.din.Operand[get_lea_id(memop)].Size;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
with ctx.builder do
|
|
case memop of
|
|
mo_reg_mem,
|
|
mo_ctx_mem:
|
|
begin
|
|
if false then
|
|
begin
|
|
call_far(@uplift_jit); //in/out:rax uses:r14
|
|
|
|
mem_in;
|
|
end else
|
|
begin
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
mem_in;
|
|
end;
|
|
end;
|
|
|
|
mo_ctx_reg:
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
|
|
mem_size:=ctx.din.Operand[1].Size;
|
|
|
|
//load?
|
|
|
|
_VV_F3(desc,new1,new2,mem_size);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
mo_reg_ctx:
|
|
begin
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[2]);
|
|
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
|
|
_VV_F3(desc,new1,new2,mem_size);
|
|
end;
|
|
|
|
mo_ctx_ctx:
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
new2:=new_reg_size(r_tmp1,ctx.din.Operand[2]);
|
|
|
|
//load?
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(fix_size(new2),[r_thrd+i]);
|
|
|
|
mem_size:=ctx.din.Operand[1].RegValue[0].ASize;
|
|
|
|
_VV_F3(desc,new1,new2,mem_size);
|
|
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
end;
|
|
|
|
procedure op_emit_bmi_rmr(var ctx:t_jit_context2;const desc:t_op_type);
|
|
var
|
|
i:Integer;
|
|
mem_size:TOperandSize;
|
|
|
|
new1,new2,new3:TRegValue;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
|
|
if is_preserved(ctx.din.Operand[1]) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
end else
|
|
begin
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
end;
|
|
|
|
if is_memory(ctx.din.Operand[2]) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[2]);
|
|
|
|
mem_size:=ctx.din.Operand[2].Size;
|
|
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
movq(new2,[r_tmp0]);
|
|
end else
|
|
if is_preserved(ctx.din.Operand[2]) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[2]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(new2,[r_thrd+i]);
|
|
end else
|
|
begin
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
end;
|
|
|
|
if is_preserved(ctx.din.Operand[3]) then
|
|
begin
|
|
new3:=new_reg_size(r_tmp1,ctx.din.Operand[3]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[3]);
|
|
movq(new3,[r_thrd+i]);
|
|
end else
|
|
begin
|
|
new3:=new_reg(ctx.din.Operand[3]);
|
|
end;
|
|
|
|
_VVV(desc,new1,new3,new2); //1 3 2
|
|
|
|
if is_preserved(ctx.din.Operand[1]) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
//
|
|
|
|
procedure op_emit_bmi_rrm(var ctx:t_jit_context2;const desc:t_op_type);
|
|
var
|
|
i:Integer;
|
|
mem_size:TOperandSize;
|
|
|
|
new1,new2,new3:TRegValue;
|
|
begin
|
|
with ctx.builder do
|
|
begin
|
|
|
|
if is_preserved(ctx.din.Operand[1]) then
|
|
begin
|
|
new1:=new_reg_size(r_tmp0,ctx.din.Operand[1]);
|
|
end else
|
|
begin
|
|
new1:=new_reg(ctx.din.Operand[1]);
|
|
end;
|
|
|
|
if is_preserved(ctx.din.Operand[2]) then
|
|
begin
|
|
new2:=new_reg_size(r_tmp0,ctx.din.Operand[2]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[2]);
|
|
movq(new2,[r_thrd+i]);
|
|
end else
|
|
begin
|
|
new2:=new_reg(ctx.din.Operand[2]);
|
|
end;
|
|
|
|
if is_memory(ctx.din.Operand[2]) then
|
|
begin
|
|
new3:=new_reg_size(r_tmp1,ctx.din.Operand[3]);
|
|
|
|
mem_size:=ctx.din.Operand[3].Size;
|
|
|
|
//mem_size
|
|
movi(new_reg_size(r_tmp1,os8),OPERAND_BYTES[mem_size]);
|
|
|
|
call_far(@copyin_mov); //in:rax(addr),r14:(size) out:rax
|
|
|
|
movq(new3,[r_tmp0]);
|
|
end else
|
|
if is_preserved(ctx.din.Operand[3]) then
|
|
begin
|
|
new3:=new_reg_size(r_tmp1,ctx.din.Operand[3]);
|
|
//
|
|
i:=GetFrameOffset(ctx.din.Operand[3]);
|
|
movq(new3,[r_thrd+i]);
|
|
end else
|
|
begin
|
|
new3:=new_reg(ctx.din.Operand[3]);
|
|
end;
|
|
|
|
_VVV(desc,new1,new2,new3); //1 2 3
|
|
|
|
if is_preserved(ctx.din.Operand[1]) then
|
|
begin
|
|
i:=GetFrameOffset(ctx.din.Operand[1]);
|
|
movq([r_thrd+i],fix_size(new1));
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|
|
|
|
|
|
|