mirror of https://github.com/red-prig/fpPS4.git
2344 lines
50 KiB
Plaintext
2344 lines
50 KiB
Plaintext
unit x86_jit;
|
|
|
|
{
|
|
x86-64 minimal JIT Compiler by Red-prig
|
|
}
|
|
|
|
{$mode ObjFPC}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
x86_fpdbgdisas;
|
|
|
|
type
|
|
t_jit_reg=object
|
|
ARegValue:TRegValues;
|
|
ASegment :ShortInt;
|
|
AOffset :Int64;
|
|
end;
|
|
|
|
TOperandSizeSet =Set of TOperandSize;
|
|
TRegisterTypeSet=Set of TRegisterType;
|
|
|
|
t_jit_regs =array of t_jit_reg;
|
|
|
|
t_jit_link_type=(lnkNone,lnkData,lnkLabel);
|
|
|
|
t_jit_instruction=object
|
|
AData:array[0..15] of Byte;
|
|
ASize:Byte;
|
|
AInstructionOffset:Integer;
|
|
ALink:record
|
|
AType:t_jit_link_type;
|
|
ADataOffset:Byte;
|
|
ALinkId:Integer;
|
|
end;
|
|
procedure EmitByte(b:byte); inline;
|
|
procedure EmitWord(w:Word); inline;
|
|
procedure EmitInt32(i:Integer); inline;
|
|
procedure EmitInt64(i:Int64); inline;
|
|
procedure EmitSelector(Segment:ShortInt); inline;
|
|
procedure EmitREX(rexB,rexX,rexR,rexW:Boolean); inline;
|
|
procedure EmitModRM(Mode,Index,RM:Byte); inline;
|
|
procedure EmitSIB(Scale,Index,Base:Byte); inline;
|
|
procedure EmitRvvv(rexR:Boolean;VectorIndex,VectorLength,SimdOpcode:Byte); inline;
|
|
procedure EmitRXBm(rexB,rexX,rexR:Boolean;mm:Byte); inline;
|
|
procedure EmitWvvv(rexW:Boolean;VectorIndex,VectorLength,SimdOpcode:Byte); inline;
|
|
end;
|
|
|
|
const
|
|
default_jit_instruction:t_jit_instruction=(
|
|
AData:($90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90,$90);
|
|
ASize:0;
|
|
AInstructionOffset:0;
|
|
ALink:(AType:lnkNone;ADataOffset:0;ALinkId:-1);
|
|
);
|
|
|
|
type
|
|
t_jit_instructions=array of t_jit_instruction;
|
|
t_jit_data =array of Pointer;
|
|
|
|
p_jit_builder=^t_jit_builder;
|
|
|
|
t_jit_i_link=object
|
|
private
|
|
builder:p_jit_builder;
|
|
inst_id:Integer;
|
|
procedure set_label(id:Integer);
|
|
function get_label():Integer;
|
|
public
|
|
property _label:Integer read get_label write set_label;
|
|
end;
|
|
|
|
t_jit_builder=object
|
|
Const
|
|
ah :t_jit_reg=(ARegValue:((AType:regGeneralH;ASize:os8;AIndex:0),(AType:regNone)));
|
|
ch :t_jit_reg=(ARegValue:((AType:regGeneralH;ASize:os8;AIndex:1),(AType:regNone)));
|
|
dh :t_jit_reg=(ARegValue:((AType:regGeneralH;ASize:os8;AIndex:2),(AType:regNone)));
|
|
bh :t_jit_reg=(ARegValue:((AType:regGeneralH;ASize:os8;AIndex:3),(AType:regNone)));
|
|
|
|
al :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 0),(AType:regNone)));
|
|
cl :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 1),(AType:regNone)));
|
|
dl :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 2),(AType:regNone)));
|
|
bl :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 3),(AType:regNone)));
|
|
spl :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 4),(AType:regNone)));
|
|
bpl :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 5),(AType:regNone)));
|
|
sil :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 6),(AType:regNone)));
|
|
dil :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 7),(AType:regNone)));
|
|
r8b :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 8),(AType:regNone)));
|
|
r9b :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex: 9),(AType:regNone)));
|
|
r10b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:10),(AType:regNone)));
|
|
r11b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:11),(AType:regNone)));
|
|
r12b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:12),(AType:regNone)));
|
|
r13b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:13),(AType:regNone)));
|
|
r14b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:14),(AType:regNone)));
|
|
r15b:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os8;AIndex:15),(AType:regNone)));
|
|
|
|
ax :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 0),(AType:regNone)));
|
|
cx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 1),(AType:regNone)));
|
|
dx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 2),(AType:regNone)));
|
|
bx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 3),(AType:regNone)));
|
|
sp :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 4),(AType:regNone)));
|
|
bp :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 5),(AType:regNone)));
|
|
si :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 6),(AType:regNone)));
|
|
di :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 7),(AType:regNone)));
|
|
r8w :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 8),(AType:regNone)));
|
|
r9w :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex: 9),(AType:regNone)));
|
|
r10w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:10),(AType:regNone)));
|
|
r11w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:11),(AType:regNone)));
|
|
r12w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:12),(AType:regNone)));
|
|
r13w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:13),(AType:regNone)));
|
|
r14w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:14),(AType:regNone)));
|
|
r15w:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os16;AIndex:15),(AType:regNone)));
|
|
|
|
eax :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 0),(AType:regNone)));
|
|
ecx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 1),(AType:regNone)));
|
|
edx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 2),(AType:regNone)));
|
|
ebx :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 3),(AType:regNone)));
|
|
esp :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 4),(AType:regNone)));
|
|
ebp :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 5),(AType:regNone)));
|
|
esi :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 6),(AType:regNone)));
|
|
edi :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 7),(AType:regNone)));
|
|
r8d :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 8),(AType:regNone)));
|
|
r9d :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex: 9),(AType:regNone)));
|
|
r10d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:10),(AType:regNone)));
|
|
r11d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:11),(AType:regNone)));
|
|
r12d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:12),(AType:regNone)));
|
|
r13d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:13),(AType:regNone)));
|
|
r14d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:14),(AType:regNone)));
|
|
r15d:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os32;AIndex:15),(AType:regNone)));
|
|
|
|
rax:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 0),(AType:regNone)));
|
|
rcx:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 1),(AType:regNone)));
|
|
rdx:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 2),(AType:regNone)));
|
|
rbx:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 3),(AType:regNone)));
|
|
rsp:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 4),(AType:regNone)));
|
|
rbp:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 5),(AType:regNone)));
|
|
rsi:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 6),(AType:regNone)));
|
|
rdi:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 7),(AType:regNone)));
|
|
r8 :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 8),(AType:regNone)));
|
|
r9 :t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex: 9),(AType:regNone)));
|
|
r10:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:10),(AType:regNone)));
|
|
r11:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:11),(AType:regNone)));
|
|
r12:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:12),(AType:regNone)));
|
|
r13:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:13),(AType:regNone)));
|
|
r14:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:14),(AType:regNone)));
|
|
r15:t_jit_reg=(ARegValue:((AType:regGeneral;ASize:os64;AIndex:15),(AType:regNone)));
|
|
|
|
rip:t_jit_reg=(ARegValue:((AType:regRip;ASize:os64),(AType:regNone)));
|
|
|
|
FS :t_jit_reg=(ARegValue:((AType:regNone),(AType:regNone));ASegment:4);
|
|
GS :t_jit_reg=(ARegValue:((AType:regNone),(AType:regNone));ASegment:5);
|
|
|
|
mm0 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 0),(AType:regNone)));
|
|
mm1 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 1),(AType:regNone)));
|
|
mm2 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 2),(AType:regNone)));
|
|
mm3 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 3),(AType:regNone)));
|
|
mm4 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 4),(AType:regNone)));
|
|
mm5 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 5),(AType:regNone)));
|
|
mm6 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 6),(AType:regNone)));
|
|
mm7 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 7),(AType:regNone)));
|
|
mm8 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 8),(AType:regNone)));
|
|
mm9 :t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 9),(AType:regNone)));
|
|
mm10:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 10),(AType:regNone)));
|
|
mm11:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 11),(AType:regNone)));
|
|
mm12:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 12),(AType:regNone)));
|
|
mm13:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 13),(AType:regNone)));
|
|
mm14:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 14),(AType:regNone)));
|
|
mm15:t_jit_reg=(ARegValue:((AType:regMm;ASize:os64;AIndex: 15),(AType:regNone)));
|
|
|
|
xmm0 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 0),(AType:regNone)));
|
|
xmm1 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 1),(AType:regNone)));
|
|
xmm2 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 2),(AType:regNone)));
|
|
xmm3 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 3),(AType:regNone)));
|
|
xmm4 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 4),(AType:regNone)));
|
|
xmm5 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 5),(AType:regNone)));
|
|
xmm6 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 6),(AType:regNone)));
|
|
xmm7 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 7),(AType:regNone)));
|
|
xmm8 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 8),(AType:regNone)));
|
|
xmm9 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 9),(AType:regNone)));
|
|
xmm10:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 10),(AType:regNone)));
|
|
xmm11:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 11),(AType:regNone)));
|
|
xmm12:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 12),(AType:regNone)));
|
|
xmm13:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 13),(AType:regNone)));
|
|
xmm14:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 14),(AType:regNone)));
|
|
xmm15:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os128;AIndex: 15),(AType:regNone)));
|
|
|
|
ymm0 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 0),(AType:regNone)));
|
|
ymm1 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 1),(AType:regNone)));
|
|
ymm2 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 2),(AType:regNone)));
|
|
ymm3 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 3),(AType:regNone)));
|
|
ymm4 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 4),(AType:regNone)));
|
|
ymm5 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 5),(AType:regNone)));
|
|
ymm6 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 6),(AType:regNone)));
|
|
ymm7 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 7),(AType:regNone)));
|
|
ymm8 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 8),(AType:regNone)));
|
|
ymm9 :t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 9),(AType:regNone)));
|
|
ymm10:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 10),(AType:regNone)));
|
|
ymm11:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 11),(AType:regNone)));
|
|
ymm12:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 12),(AType:regNone)));
|
|
ymm13:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 13),(AType:regNone)));
|
|
ymm14:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 14),(AType:regNone)));
|
|
ymm15:t_jit_reg=(ARegValue:((AType:regXmm;ASize:os256;AIndex: 15),(AType:regNone)));
|
|
var
|
|
AInstructions:t_jit_instructions;
|
|
AInstructionSize:Integer;
|
|
AData:t_jit_data;
|
|
//
|
|
procedure _add(const ji:t_jit_instruction);
|
|
Function _add_data(P:Pointer):Integer;
|
|
Function _get_data_offset(ALinkId,AInstructionEnd:Integer):Integer;
|
|
Function _get_label_offset(ALinkId,AInstructionEnd:Integer):Integer;
|
|
Function _label:Integer;
|
|
//
|
|
Procedure call(P:Pointer);
|
|
Procedure jmp (P:Pointer);
|
|
//
|
|
function call(_label_id:Integer):t_jit_i_link;
|
|
function jmp (_label_id:Integer):t_jit_i_link;
|
|
function jmp8(_label_id:Integer):t_jit_i_link;
|
|
function jcc (op:TOpCodeSuffix;_label_id:Integer):t_jit_i_link;
|
|
function movj(reg:t_jit_reg;mem:t_jit_regs;_label_id:Integer):t_jit_i_link;
|
|
function leaj(reg:t_jit_reg;mem:t_jit_regs;_label_id:Integer):t_jit_i_link;
|
|
//
|
|
Procedure reta;
|
|
//
|
|
Function GetInstructionsSize:Integer;
|
|
Function GetDataSize:Integer;
|
|
Function GetMemSize:Integer;
|
|
Procedure RebuldInstructionOffset;
|
|
Procedure LinkData;
|
|
Function SaveTo(ptr:PByte;size:Integer):Integer;
|
|
//
|
|
procedure _mov (op,op8:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
procedure _mov (op,op8:Byte;reg0:t_jit_reg;reg1:t_jit_reg);
|
|
procedure _mov (op,op8,index:Byte;reg:t_jit_reg);
|
|
procedure _movi (op,op8,index:Byte;reg:t_jit_reg;imm:Int64);
|
|
procedure _movi (op,op8,index:Byte;size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
procedure _movi8 (op,index:Byte;reg:t_jit_reg;imm:Byte);
|
|
procedure _movi8 (op,index:Byte;size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
procedure _push (op,index:Byte;size:TOperandSize;mem:t_jit_regs);
|
|
procedure _push (op:Byte;reg:t_jit_reg);
|
|
procedure _pushi (size:TOperandSize;imm:Integer);
|
|
procedure movq (reg0:t_jit_reg ;reg1:t_jit_reg);
|
|
procedure movi (size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
procedure movi (reg:t_jit_reg ;imm:Int64);
|
|
procedure movi64 (reg:t_jit_reg ;imm:Int64);
|
|
procedure movq (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure movq (mem:t_jit_regs ;reg:t_jit_reg);
|
|
procedure leaq (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure addq (mem:t_jit_regs ;reg:t_jit_reg);
|
|
procedure addq (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure addq (reg0:t_jit_reg ;reg1:t_jit_reg);
|
|
procedure addi (reg:t_jit_reg ;imm:Int64);
|
|
procedure addi8 (reg:t_jit_reg ;imm:Byte);
|
|
procedure addi8 (size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
procedure subq (mem:t_jit_regs ;reg:t_jit_reg);
|
|
procedure subq (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure subq (reg0:t_jit_reg ;reg1:t_jit_reg);
|
|
procedure subi (reg:t_jit_reg ;imm:Int64);
|
|
procedure subi8 (reg:t_jit_reg ;imm:Byte);
|
|
procedure subi8 (size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
procedure xorq (reg0:t_jit_reg ;reg1:t_jit_reg);
|
|
procedure cmpq (mem:t_jit_regs ;reg:t_jit_reg);
|
|
procedure cmpq (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure cmpq (reg0:t_jit_reg ;reg1:t_jit_reg);
|
|
procedure cmpi (reg:t_jit_reg ;imm:Int64);
|
|
procedure cmpi (size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
procedure cmpi8 (reg:t_jit_reg;imm:Byte);
|
|
procedure cmpi8 (size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
procedure push16 (mem:t_jit_regs);
|
|
procedure push64 (mem:t_jit_regs);
|
|
procedure push (reg:t_jit_reg);
|
|
procedure push8 (imm:Integer);
|
|
procedure push16 (imm:Integer);
|
|
procedure push32 (imm:Integer);
|
|
procedure pop16 (mem:t_jit_regs);
|
|
procedure pop64 (mem:t_jit_regs);
|
|
procedure pop (reg:t_jit_reg);
|
|
procedure pushfq;
|
|
procedure popfq;
|
|
procedure _pmov (Op0,Op1:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
procedure _vmov (Op0,Op1:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
procedure vmovdqu (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure vmovdqu (mem:t_jit_regs;reg:t_jit_reg);
|
|
procedure vmovdqa (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure vmovdqa (mem:t_jit_regs;reg:t_jit_reg);
|
|
procedure vmovntdq(mem:t_jit_regs;reg:t_jit_reg);
|
|
procedure vmovups (reg:t_jit_reg ;mem:t_jit_regs);
|
|
procedure vmovups (mem:t_jit_regs;reg:t_jit_reg);
|
|
procedure vmovdqa (reg0:t_jit_reg;reg1:t_jit_reg);
|
|
procedure sahf;
|
|
procedure lahf;
|
|
end;
|
|
|
|
operator + (A,B:t_jit_reg):t_jit_reg;
|
|
operator + (A:t_jit_reg;B:Integer):t_jit_reg;
|
|
operator + (A:t_jit_reg;B:Int64):t_jit_reg;
|
|
operator * (A:t_jit_reg;B:Integer):t_jit_reg;
|
|
|
|
function classif_offset_32(AOffset:Integer):Byte;
|
|
function classif_offset_64(AOffset:Int64):Byte;
|
|
function classif_offset_se64(AOffset:Int64):Byte;
|
|
|
|
implementation
|
|
|
|
function is_valid_reg_type(reg:TRegValue):Boolean; inline;
|
|
begin
|
|
Result:=(reg.AType<>regNone) and
|
|
(reg.AType<>regInvalid);
|
|
end;
|
|
|
|
function is_valid_scale(reg:TRegValue):Boolean; inline;
|
|
begin
|
|
case reg.AScale of
|
|
0,
|
|
1,
|
|
2,
|
|
4,
|
|
8:Result:=True;
|
|
else
|
|
Result:=False;
|
|
end;
|
|
end;
|
|
|
|
function get_scale_idx(reg:TRegValue):Byte; inline;
|
|
begin
|
|
case reg.AScale of
|
|
0:Result:=0;
|
|
1:Result:=0;
|
|
2:Result:=1;
|
|
4:Result:=2;
|
|
8:Result:=3;
|
|
else
|
|
Result:=0;
|
|
end;
|
|
end;
|
|
|
|
function classif_offset_32(AOffset:Integer):Byte;
|
|
begin
|
|
case AOffset of
|
|
0:Result:=0;
|
|
-128..-1,1..127:Result:=1;
|
|
else
|
|
Result:=2;
|
|
end;
|
|
end;
|
|
|
|
function classif_offset_64(AOffset:Int64):Byte;
|
|
begin
|
|
case AOffset of
|
|
0:Result:=0;
|
|
-128 .. -1, 1..127 :Result:=1;
|
|
-2147483648..-129,128..2147483647:Result:=2;
|
|
else
|
|
Result:=3;
|
|
end;
|
|
end;
|
|
|
|
function classif_offset_se64(AOffset:Int64):Byte;
|
|
begin
|
|
case AOffset of
|
|
0:Result:=0;
|
|
1..127:Result:=1;
|
|
128..2147483647:Result:=2;
|
|
else
|
|
Result:=3;
|
|
end;
|
|
end;
|
|
|
|
function classif_offset_32(reg:t_jit_reg):Byte; inline;
|
|
begin
|
|
Result:=classif_offset_32(reg.AOffset);
|
|
end;
|
|
|
|
function classif_offset_64(reg:t_jit_reg):Byte; inline;
|
|
begin
|
|
Result:=classif_offset_64(reg.AOffset);
|
|
end;
|
|
|
|
function is_not_reg(reg:t_jit_reg):Boolean; inline;
|
|
begin
|
|
Result:=(not is_valid_reg_type(reg.ARegValue[0])) and
|
|
(not is_valid_reg_type(reg.ARegValue[1]));
|
|
end;
|
|
|
|
function is_one_reg(reg:t_jit_reg):Boolean; inline;
|
|
begin
|
|
Result:=( is_valid_reg_type(reg.ARegValue[0])) and
|
|
(not is_valid_reg_type(reg.ARegValue[1]));
|
|
end;
|
|
|
|
function is_reg_size(reg:t_jit_reg;Size:TOperandSizeSet):Boolean; inline;
|
|
begin
|
|
Result:=(reg.ARegValue[0].ASize in Size) and
|
|
((reg.ARegValue[1].ASize in Size) or (reg.ARegValue[1].ASize=os0));
|
|
end;
|
|
|
|
function is_reg_type(reg:t_jit_reg;AType:TRegisterTypeSet):Boolean; inline;
|
|
begin
|
|
Result:=(reg.ARegValue[0].AType in AType) and
|
|
((reg.ARegValue[1].AType in AType) or (reg.ARegValue[1].AType=regNone));
|
|
end;
|
|
|
|
function is_valid_seg(reg:t_jit_reg):Boolean; inline;
|
|
begin
|
|
case reg.ASegment of
|
|
0..5:Result:=True
|
|
else
|
|
Result:=False;
|
|
end;
|
|
end;
|
|
|
|
function is_valid_scale(reg:t_jit_reg):Boolean; inline;
|
|
begin
|
|
Result:=is_valid_scale(reg.ARegValue[0]) and (reg.ARegValue[1].AScale<=1)
|
|
end;
|
|
|
|
operator + (A,B:t_jit_reg):t_jit_reg;
|
|
begin
|
|
Assert(is_not_reg(A) or is_one_reg(A));
|
|
Assert(is_not_reg(B) or is_one_reg(B));
|
|
|
|
Result:=A;
|
|
|
|
if is_one_reg(Result) then
|
|
begin
|
|
if (A.ARegValue[0].AScale>1) then
|
|
begin
|
|
Result.ARegValue[0]:=A.ARegValue[0];
|
|
Result.ARegValue[1]:=B.ARegValue[0];
|
|
end else
|
|
begin
|
|
Result.ARegValue[1]:=A.ARegValue[0];
|
|
Result.ARegValue[0]:=B.ARegValue[0];
|
|
end;
|
|
end else
|
|
begin
|
|
Result.ARegValue[0]:=B.ARegValue[0];
|
|
end;
|
|
|
|
if is_valid_seg(Result) then
|
|
begin
|
|
if is_valid_seg(B) then
|
|
begin
|
|
Result.ASegment:=B.ASegment;
|
|
end;
|
|
end else
|
|
begin
|
|
Result.ASegment:=B.ASegment;
|
|
end;
|
|
|
|
Result.AOffset:=Result.AOffset+B.AOffset;
|
|
end;
|
|
|
|
operator + (A:t_jit_reg;B:Integer):t_jit_reg;
|
|
begin
|
|
Result:=A;
|
|
|
|
Result.AOffset:=Result.AOffset+B;
|
|
end;
|
|
|
|
operator + (A:t_jit_reg;B:Int64):t_jit_reg;
|
|
begin
|
|
Result:=A;
|
|
|
|
Result.AOffset:=Result.AOffset+B;
|
|
end;
|
|
|
|
operator * (A:t_jit_reg;B:Integer):t_jit_reg;
|
|
begin
|
|
Assert(is_one_reg(A));
|
|
|
|
Result:=A;
|
|
|
|
if (Result.ARegValue[0].AScale<=1) then
|
|
begin
|
|
Result.ARegValue[0].AScale:=B;
|
|
end else
|
|
begin
|
|
Result.ARegValue[0].AScale:=Result.ARegValue[0].AScale*B;
|
|
end;
|
|
end;
|
|
|
|
function Sums(mem:t_jit_regs):t_jit_reg;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
if (Length(mem)=0) then
|
|
begin
|
|
Result:=Default(t_jit_reg);
|
|
end else
|
|
if (Length(mem)=1) then
|
|
begin
|
|
Result:=mem[0];
|
|
end else
|
|
begin
|
|
Result:=mem[0];
|
|
For i:=1 to High(mem) do
|
|
begin
|
|
Result:=Result+mem[i];
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
////
|
|
|
|
procedure t_jit_i_link.set_label(id:Integer);
|
|
begin
|
|
builder^.AInstructions[inst_id].ALink.ALinkId:=id;
|
|
end;
|
|
|
|
function t_jit_i_link.get_label():Integer;
|
|
begin
|
|
Result:=builder^.AInstructions[inst_id].ALink.ALinkId;
|
|
end;
|
|
|
|
////
|
|
|
|
procedure t_jit_instruction.EmitByte(b:byte); inline;
|
|
begin
|
|
AData[ASize]:=b;
|
|
Inc(ASize);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitWord(w:Word); inline;
|
|
begin
|
|
PWord(@AData[ASize])^:=w;
|
|
Inc(ASize,SizeOf(Word));
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitInt32(i:Integer); inline;
|
|
begin
|
|
PInteger(@AData[ASize])^:=i;
|
|
Inc(ASize,SizeOf(Integer));
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitInt64(i:Int64); inline;
|
|
begin
|
|
PInt64(@AData[ASize])^:=i;
|
|
Inc(ASize,SizeOf(Int64));
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitSelector(Segment:ShortInt); inline;
|
|
begin
|
|
case Segment of //Selector
|
|
4:EmitByte($64); //fs
|
|
5:EmitByte($65); //gs
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitREX(rexB,rexX,rexR,rexW:Boolean); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=$40;
|
|
if rexB then b:=b or 1;
|
|
if rexX then b:=b or 2;
|
|
if rexR then b:=b or 4;
|
|
if rexW then b:=b or 8;
|
|
EmitByte(b);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitModRM(Mode,Index,RM:Byte); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=RM and 7;
|
|
b:=b or ((Index and 7) shl 3);
|
|
b:=b or ((Mode and 3) shl 6);
|
|
EmitByte(b);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitSIB(Scale,Index,Base:Byte); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=Base and 7;
|
|
b:=b or ((Index and 7) shl 3);
|
|
b:=b or ((Scale and 3) shl 6);
|
|
EmitByte(b);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitRvvv(rexR:Boolean;VectorIndex,VectorLength,SimdOpcode:Byte); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=SimdOpcode and 3;
|
|
if (not rexR) then b:=b or $80;
|
|
b:=b or (((VectorIndex xor $F) and $F) shl 3);
|
|
b:=b or ((VectorLength and 1) shl 2);
|
|
EmitByte(b);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitRXBm(rexB,rexX,rexR:Boolean;mm:Byte); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=mm and $1F;
|
|
if (not rexR) then b:=b or $80;
|
|
if (not rexX) then b:=b or $40;
|
|
if (not rexB) then b:=b or $20;
|
|
EmitByte(b);
|
|
end;
|
|
|
|
procedure t_jit_instruction.EmitWvvv(rexW:Boolean;VectorIndex,VectorLength,SimdOpcode:Byte); inline;
|
|
var
|
|
b:Byte;
|
|
begin
|
|
b:=SimdOpcode and 3;
|
|
if (not rexW) then b:=b or $80;
|
|
b:=b or (((VectorIndex xor $F) and $F) shl 3);
|
|
b:=b or ((VectorLength and 1) shl 2);
|
|
EmitByte(b);
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_jit_builder._add(const ji:t_jit_instruction);
|
|
var
|
|
i:Integer;
|
|
begin
|
|
i:=Length(AInstructions);
|
|
SetLength(AInstructions,i+1);
|
|
AInstructions[i]:=ji;
|
|
|
|
AInstructions[i].AInstructionOffset:=AInstructionSize;
|
|
Inc(AInstructionSize,ji.ASize);
|
|
end;
|
|
|
|
Function t_jit_builder._add_data(P:Pointer):Integer;
|
|
begin
|
|
Result:=Length(AData);
|
|
SetLength(AData,Result+1);
|
|
AData[Result]:=P;
|
|
end;
|
|
|
|
Function t_jit_builder._get_data_offset(ALinkId,AInstructionEnd:Integer):Integer;
|
|
begin
|
|
Assert(ALinkId<Length(AData));
|
|
Result:=(AInstructionSize-AInstructionEnd)+(ALinkId*SizeOf(Pointer));
|
|
end;
|
|
|
|
Function t_jit_builder._get_label_offset(ALinkId,AInstructionEnd:Integer):Integer;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
Assert(ALinkId<=Length(AInstructions));
|
|
|
|
if (ALinkId>=Length(AInstructions)) then
|
|
begin
|
|
i:=AInstructionSize;
|
|
end else
|
|
begin
|
|
i:=AInstructions[ALinkId].AInstructionOffset;
|
|
end;
|
|
|
|
Result:=(i-AInstructionEnd);
|
|
end;
|
|
|
|
Function t_jit_builder._label:Integer;
|
|
begin
|
|
Result:=Length(AInstructions);
|
|
end;
|
|
|
|
Procedure t_jit_builder.call(P:Pointer);
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($FF);
|
|
ji.EmitByte($15);
|
|
|
|
ji.ALink.AType:=lnkData;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_add_data(P);
|
|
|
|
ji.EmitInt32(0);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
Procedure t_jit_builder.jmp(P:Pointer);
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($FF);
|
|
ji.EmitByte($25);
|
|
|
|
ji.ALink.AType:=lnkData;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_add_data(P);
|
|
|
|
ji.EmitInt32(0);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
function t_jit_builder.call(_label_id:Integer):t_jit_i_link;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($E8);
|
|
|
|
ji.ALink.AType:=lnkLabel;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_label_id;
|
|
|
|
ji.EmitInt32(0);
|
|
|
|
_add(ji);
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
function t_jit_builder.jmp(_label_id:Integer):t_jit_i_link;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($E9);
|
|
|
|
ji.ALink.AType:=lnkLabel;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_label_id;
|
|
|
|
ji.EmitInt32(0);
|
|
|
|
_add(ji);
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
function t_jit_builder.jmp8(_label_id:Integer):t_jit_i_link;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($EB);
|
|
|
|
ji.ALink.AType:=lnkLabel;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_label_id;
|
|
|
|
ji.EmitByte(0);
|
|
|
|
_add(ji);
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
const
|
|
COND_32:array[OPSc_o..OPSc_nle] of Byte=(
|
|
$80,$81,$82,$83,$84,$85,$86,$87,
|
|
$88,$89,$8A,$8B,$8C,$8D,$8E,$8F
|
|
);
|
|
|
|
function t_jit_builder.jcc(op:TOpCodeSuffix;_label_id:Integer):t_jit_i_link;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
case op of
|
|
OPSc_o..OPSc_nle:;
|
|
else
|
|
Assert(false);
|
|
end;
|
|
|
|
ji.EmitByte($0F);
|
|
|
|
ji.EmitByte(COND_32[op]);
|
|
|
|
ji.ALink.AType:=lnkLabel;
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.ALink.ALinkId:=_label_id;
|
|
|
|
ji.EmitInt32(0);
|
|
|
|
_add(ji);
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
function t_jit_builder.movj(reg:t_jit_reg;mem:t_jit_regs;_label_id:Integer):t_jit_i_link;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
movq(reg,mem);
|
|
|
|
i:=High(AInstructions);
|
|
|
|
AInstructions[i].ALink.AType:=lnkLabel;
|
|
AInstructions[i].ALink.ALinkId:=_label_id;
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
function t_jit_builder.leaj(reg:t_jit_reg;mem:t_jit_regs;_label_id:Integer):t_jit_i_link;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
leaq(reg,mem);
|
|
|
|
i:=High(AInstructions);
|
|
|
|
AInstructions[i].ALink.AType:=lnkLabel;
|
|
AInstructions[i].ALink.ALinkId:=_label_id;
|
|
|
|
Result.builder:=@self;
|
|
Result.inst_id:=High(AInstructions);
|
|
end;
|
|
|
|
Procedure t_jit_builder.reta;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($C3);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
Function t_jit_builder.GetInstructionsSize:Integer;
|
|
begin
|
|
Result:=AInstructionSize;
|
|
end;
|
|
|
|
Function t_jit_builder.GetDataSize:Integer;
|
|
begin
|
|
Result:=Length(AData)*SizeOf(QWORD);
|
|
end;
|
|
|
|
Function t_jit_builder.GetMemSize:Integer;
|
|
begin
|
|
Result:=AInstructionSize+Length(AData)*SizeOf(QWORD);
|
|
end;
|
|
|
|
Procedure t_jit_builder.RebuldInstructionOffset;
|
|
var
|
|
i:Integer;
|
|
begin
|
|
AInstructionSize:=0;
|
|
if (Length(AInstructions)<>0) then
|
|
For i:=0 to High(AInstructions) do
|
|
begin
|
|
AInstructions[i].AInstructionOffset:=AInstructionSize;
|
|
Inc(AInstructionSize,AInstructions[i].ASize);
|
|
end;
|
|
end;
|
|
|
|
Procedure t_jit_builder.LinkData;
|
|
var
|
|
i,d:Integer;
|
|
begin
|
|
if (Length(AInstructions)<>0) then
|
|
For i:=0 to High(AInstructions) do
|
|
begin
|
|
With AInstructions[i] do
|
|
case ALink.AType of
|
|
lnkData:
|
|
begin
|
|
d:=_get_data_offset(ALink.ALinkId,AInstructionOffset+ASize);
|
|
PInteger(@AData[ALink.ADataOffset])^:=d;
|
|
end;
|
|
lnkLabel:
|
|
begin
|
|
d:=_get_label_offset(ALink.ALinkId,AInstructionOffset+ASize);
|
|
PInteger(@AData[ALink.ADataOffset])^:=d;
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
Function t_jit_builder.SaveTo(ptr:PByte;size:Integer):Integer;
|
|
var
|
|
i,s:Integer;
|
|
begin
|
|
LinkData;
|
|
|
|
Result:=0;
|
|
if (Length(AInstructions)<>0) then
|
|
For i:=0 to High(AInstructions) do
|
|
begin
|
|
s:=AInstructions[i].ASize;
|
|
if ((Result+s)>size) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
Move(AInstructions[i].AData,ptr^,s);
|
|
Inc(Result,s);
|
|
Inc(ptr ,s);
|
|
end;
|
|
|
|
if (Length(AData)<>0) then
|
|
For i:=0 to High(AData) do
|
|
begin
|
|
s:=SizeOf(QWORD);
|
|
if ((Result+s)>size) then
|
|
begin
|
|
Exit;
|
|
end;
|
|
Move(AData[i],ptr^,s);
|
|
Inc(Result,s);
|
|
Inc(ptr ,s);
|
|
end;
|
|
end;
|
|
|
|
type
|
|
t_modrm_info=object
|
|
RH,rexF:Boolean;
|
|
|
|
rexB,rexX,rexR:Boolean;
|
|
|
|
ModRM:record
|
|
Mode,Index,RM:Byte;
|
|
end;
|
|
|
|
SIB:record
|
|
Scale,Index,Base:Byte;
|
|
end;
|
|
|
|
AOffset:Int64;
|
|
|
|
procedure build_im(Index:Byte;mreg:t_jit_reg);
|
|
procedure build_rm(reg,mreg:t_jit_reg);
|
|
procedure build_rr(reg0,reg1:t_jit_reg);
|
|
procedure build_ir(Index:Byte;reg:t_jit_reg);
|
|
procedure emit_rex(var ji:t_jit_instruction;rexW:Boolean);
|
|
procedure emit_mrm(var ji:t_jit_instruction);
|
|
end;
|
|
|
|
procedure t_modrm_info.build_im(Index:Byte;mreg:t_jit_reg);
|
|
var
|
|
ubase:Boolean;
|
|
begin
|
|
ModRM.Index:=Index;
|
|
|
|
if not is_valid_reg_type(mreg.ARegValue[0]) then
|
|
begin
|
|
ModRM.Mode:=0;
|
|
ModRM.RM :=4;
|
|
|
|
sib.Scale:=0;
|
|
sib.Index:=4;
|
|
sib.Base :=5;
|
|
end else
|
|
if (mreg.ARegValue[0].AType=regRip) then
|
|
begin
|
|
if is_valid_reg_type(mreg.ARegValue[1]) then
|
|
begin
|
|
Assert(false,'imposible');
|
|
Exit;
|
|
end;
|
|
|
|
if (mreg.ARegValue[0].AScale>1) then
|
|
begin
|
|
Assert(false,'imposible');
|
|
Exit;
|
|
end;
|
|
|
|
ModRM.Mode :=0;
|
|
ModRM.RM :=5;
|
|
end else
|
|
begin
|
|
ModRM.Mode:=classif_offset_32(mreg);
|
|
|
|
ubase:=is_valid_reg_type(mreg.ARegValue[1]);
|
|
|
|
if (mreg.ARegValue[0].AScale>1) or ubase then
|
|
begin
|
|
//sib
|
|
ModRM.RM:=4;
|
|
|
|
SIB.Scale:=get_scale_idx(mreg.ARegValue[0]);
|
|
|
|
SIB.Index:=mreg.ARegValue[0].AIndex;
|
|
if (SIB.Index>=8) then
|
|
begin
|
|
if RH then
|
|
begin
|
|
Assert(false,'imposible');
|
|
end;
|
|
rexX:=true;
|
|
Dec(SIB.Index,8);
|
|
end;
|
|
|
|
if ubase then
|
|
begin
|
|
SIB.Base:=mreg.ARegValue[1].AIndex;
|
|
if (SIB.Base>=8) then
|
|
begin
|
|
if RH then
|
|
begin
|
|
Assert(false,'imposible');
|
|
end;
|
|
rexB:=true;
|
|
Dec(SIB.Base,8);
|
|
end;
|
|
end else
|
|
begin
|
|
SIB.Base :=5; //no base
|
|
ModRM.Mode:=0; //exception
|
|
end;
|
|
|
|
if (not rexX) and (SIB.Index=4) then //exception
|
|
begin
|
|
//swap
|
|
if (not rexB) and (SIB.Base=4) then
|
|
begin
|
|
Assert(false,'imposible');
|
|
Exit;
|
|
end;
|
|
|
|
if not ubase then
|
|
begin
|
|
Assert(false,'imposible');
|
|
Exit;
|
|
end;
|
|
|
|
rexX :=rexB;
|
|
SIB.Index:=SIB.Base;
|
|
|
|
rexB :=false;
|
|
SIB.Base:=4;
|
|
end;
|
|
|
|
if ubase and
|
|
(ModRM.Mode=0) and
|
|
(SIB.Base=5) then //exception
|
|
begin
|
|
ModRM.Mode:=1;
|
|
end;
|
|
|
|
end else
|
|
begin
|
|
//no sib
|
|
|
|
ModRM.RM:=mreg.ARegValue[0].AIndex;
|
|
if (ModRM.RM>=8) then
|
|
begin
|
|
if RH then
|
|
begin
|
|
Assert(false,'imposible');
|
|
end;
|
|
rexB:=true;
|
|
Dec(ModRM.RM,8);
|
|
end;
|
|
|
|
if (ModRM.Mode=0) and (ModRM.RM=5) then //exception
|
|
begin
|
|
ModRM.Mode:=1;
|
|
end;
|
|
|
|
if (ModRM.RM=4) then //force sib
|
|
begin
|
|
SIB.Scale:=0;
|
|
SIB.Index:=4; //no index (rexX=false)
|
|
SIB.Base :=4; //=ModRM.RM
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
AOffset:=mreg.AOffset;
|
|
end;
|
|
|
|
function get_force_rex(const reg:t_jit_reg):Boolean; inline;
|
|
begin
|
|
Result:=False;
|
|
if (reg.ARegValue[0].AType=regGeneral) then
|
|
if (reg.ARegValue[0].ASize=os8) then
|
|
case reg.ARegValue[0].AIndex of
|
|
4..7:Result:=True;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
procedure t_modrm_info.build_rm(reg,mreg:t_jit_reg);
|
|
begin
|
|
ModRM.Index:=reg.ARegValue[0].AIndex;
|
|
|
|
if (reg.ARegValue[0].AType=regGeneralH) then
|
|
begin
|
|
RH:=True;
|
|
Inc(ModRM.Index,4);
|
|
end else
|
|
if (ModRM.Index>=8) then
|
|
begin
|
|
rexR:=true;
|
|
Dec(ModRM.Index,8);
|
|
end;
|
|
|
|
rexF:=get_force_rex(reg);
|
|
|
|
build_im(ModRM.Index,mreg);
|
|
end;
|
|
|
|
procedure t_modrm_info.build_rr(reg0,reg1:t_jit_reg);
|
|
begin
|
|
ModRM.Index:=reg1.ARegValue[0].AIndex;
|
|
|
|
if (reg1.ARegValue[0].AType=regGeneralH) then
|
|
begin
|
|
RH:=True;
|
|
Inc(ModRM.Index,4);
|
|
end else
|
|
if (ModRM.Index>=8) then
|
|
begin
|
|
rexR:=true;
|
|
Dec(ModRM.Index,8);
|
|
end;
|
|
|
|
rexF:=get_force_rex(reg1);
|
|
|
|
ModRM.RM:=reg0.ARegValue[0].AIndex;
|
|
|
|
if (reg0.ARegValue[0].AType=regGeneralH) then
|
|
begin
|
|
if rexF or rexR then
|
|
begin
|
|
Assert(false,'imposible');
|
|
end;
|
|
RH:=True;
|
|
Inc(ModRM.RM,4)
|
|
end else
|
|
if (ModRM.RM>=8) then
|
|
begin
|
|
if RH then
|
|
begin
|
|
Assert(false,'imposible');
|
|
end;
|
|
rexB:=true;
|
|
Dec(ModRM.RM,8);
|
|
end;
|
|
|
|
ModRM.Mode:=3;
|
|
end;
|
|
|
|
procedure t_modrm_info.build_ir(Index:Byte;reg:t_jit_reg);
|
|
begin
|
|
ModRM.Index:=Index;
|
|
|
|
ModRM.RM:=reg.ARegValue[0].AIndex;
|
|
if (ModRM.RM>=8) then
|
|
begin
|
|
rexB:=true;
|
|
Dec(ModRM.RM,8);
|
|
end;
|
|
|
|
rexF:=get_force_rex(reg);
|
|
|
|
ModRM.Mode:=3;
|
|
end;
|
|
|
|
procedure t_modrm_info.emit_rex(var ji:t_jit_instruction;rexW:Boolean);
|
|
begin
|
|
if rexF or rexB or rexX or rexR or rexW then
|
|
begin
|
|
ji.EmitREX(rexB,rexX,rexR,rexW);
|
|
end;
|
|
end;
|
|
|
|
procedure t_modrm_info.emit_mrm(var ji:t_jit_instruction);
|
|
begin
|
|
ji.EmitModRM(ModRM.Mode,ModRM.Index,ModRM.RM);
|
|
|
|
if (ModRM.RM=4) then
|
|
begin
|
|
ji.EmitSIB(SIB.Scale,SIB.Index,SIB.Base);
|
|
end;
|
|
|
|
case ModRM.Mode of
|
|
0:
|
|
begin
|
|
case ModRM.RM of
|
|
4:if (SIB.Base=5) then
|
|
begin
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.EmitInt32(AOffset); //4
|
|
end;
|
|
5:begin
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.EmitInt32(AOffset); //4
|
|
end;
|
|
end;
|
|
end;
|
|
1:ji.EmitByte(AOffset); //1
|
|
2:begin
|
|
ji.ALink.ADataOffset:=ji.ASize;
|
|
ji.EmitInt32(AOffset); //4
|
|
end;
|
|
else;
|
|
end;
|
|
end;
|
|
|
|
procedure t_jit_builder._mov(op,op8:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
rexW:Boolean;
|
|
Prefix:Byte;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os8,os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral,regGeneralH]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=False;
|
|
Prefix:=0;
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:
|
|
begin
|
|
op:=op8;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_rm(reg,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._mov(op,op8:Byte;reg0:t_jit_reg;reg1:t_jit_reg);
|
|
var
|
|
rexW:Boolean;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
Prefix:Byte;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg0));
|
|
Assert(is_one_reg(reg1));
|
|
|
|
Assert(is_reg_size(reg0,[os8,os16,os32,os64]));
|
|
Assert(is_reg_size(reg1,[os8,os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg0,[regGeneral,regGeneralH]));
|
|
Assert(is_reg_type(reg1,[regGeneral,regGeneralH]));
|
|
|
|
Assert(reg0.ARegValue[0].AScale<=1);
|
|
Assert(reg1.ARegValue[0].AScale<=1);
|
|
|
|
Assert(reg0.ARegValue[0].ASize=reg1.ARegValue[0].ASize);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=false;
|
|
Prefix:=0;
|
|
|
|
case reg0.ARegValue[0].ASize of
|
|
os8:
|
|
begin
|
|
op:=op8;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_rr(reg0,reg1);
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
////
|
|
|
|
procedure t_jit_builder._mov(op,op8,index:Byte;reg:t_jit_reg);
|
|
var
|
|
rexW:Boolean;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
Prefix:Byte;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
|
|
Assert(is_reg_size(reg,[os8,os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral,regGeneralH]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=false;
|
|
Prefix:=0;
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:
|
|
begin
|
|
op:=op8;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_ir(Index,reg);
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
////
|
|
|
|
procedure t_jit_builder._movi(op,op8,index:Byte;reg:t_jit_reg;imm:Int64);
|
|
var
|
|
rexW:Boolean;
|
|
|
|
Prefix:Byte;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os8,os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral,regGeneralH]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
Prefix:=0;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_ir(Index,reg);
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:
|
|
begin
|
|
op:=op8;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:ji.EmitByte (imm);
|
|
os16:ji.EmitWord (imm);
|
|
os32:ji.EmitInt32(imm);
|
|
os64:ji.EmitInt32(imm);
|
|
else;
|
|
end;
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._movi(op,op8,index:Byte;size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
rexW:Boolean;
|
|
Prefix:Byte;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(size in [os8,os16,os32,os64]);
|
|
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=False;
|
|
Prefix:=0;
|
|
|
|
case size of
|
|
os8:
|
|
begin
|
|
op:=op8;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_im(Index,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
case Size of
|
|
os8:ji.EmitByte (imm);
|
|
os16:ji.EmitWord (imm);
|
|
os32:ji.EmitInt32(imm);
|
|
os64:ji.EmitInt32(imm);
|
|
else;
|
|
end;
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._movi8(op,index:Byte;reg:t_jit_reg;imm:Byte);
|
|
var
|
|
rexW:Boolean;
|
|
|
|
Prefix:Byte;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral,regGeneralH]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=false;
|
|
Prefix:=0;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_ir(Index,reg);
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
ji.EmitByte(imm);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._movi8(op,index:Byte;size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
rexW:Boolean;
|
|
Prefix:Byte;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(size in [os16,os32,os64]);
|
|
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexW:=False;
|
|
Prefix:=0;
|
|
|
|
case size of
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
end;
|
|
os32:;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_im(Index,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,rexW);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
ji.EmitByte(imm); //1
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
////
|
|
|
|
procedure t_jit_builder._push(op,index:Byte;size:TOperandSize;mem:t_jit_regs);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(size in [os16,os64]);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_im(index,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (size=os16) then
|
|
begin
|
|
ji.EmitByte($66); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,False);
|
|
|
|
ji.EmitByte(op);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._push(op:Byte;reg:t_jit_reg);
|
|
var
|
|
rexB:Boolean;
|
|
|
|
Index:Byte;
|
|
|
|
Prefix:Byte;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
|
|
Assert(is_reg_size(reg,[os16,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexB:=false;
|
|
Prefix:=0;
|
|
|
|
Index:=reg.ARegValue[0].AIndex;
|
|
if (Index>=8) then
|
|
begin
|
|
rexB:=true;
|
|
Dec(Index,8);
|
|
end;
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
op:=op+Index;
|
|
end;
|
|
os64:
|
|
begin
|
|
op:=op+Index;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if rexB then
|
|
begin
|
|
ji.EmitREX(rexB,False,False,False);
|
|
end;
|
|
|
|
ji.EmitByte(op);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._pushi(size:TOperandSize;imm:Integer);
|
|
var
|
|
op,Prefix:Byte;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(size in [os8,os16,os32]);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
Prefix:=0;
|
|
op:=$68;
|
|
|
|
case size of
|
|
os8 :op:=$6A;
|
|
os16:Prefix:=$66;
|
|
os32:;
|
|
else;
|
|
end;
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
ji.EmitByte(op);
|
|
|
|
case size of
|
|
os8:ji.EmitByte (imm);
|
|
os16:ji.EmitWord (imm);
|
|
os32:ji.EmitInt32(imm);
|
|
else;
|
|
end;
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_jit_builder.movq(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
begin
|
|
_mov($89,$88,reg0,reg1);
|
|
end;
|
|
|
|
procedure t_jit_builder.movi(size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
begin
|
|
_movi($C7,$C6,0,size,mem,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.movi(reg:t_jit_reg;imm:Int64);
|
|
begin
|
|
_movi($C7,$C6,0,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.movi64(reg:t_jit_reg;imm:Int64);
|
|
var
|
|
rexF,rexB,rexW:Boolean;
|
|
|
|
Index,Prefix,op:Byte;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os8,os16,os32,os64]));
|
|
|
|
Assert(is_reg_type(reg,[regGeneral]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexF:=false;
|
|
rexB:=false;
|
|
rexW:=false;
|
|
Prefix:=0;
|
|
|
|
Index:=reg.ARegValue[0].AIndex;
|
|
if (Index>=8) then
|
|
begin
|
|
rexB:=true;
|
|
Dec(Index,8);
|
|
end;
|
|
|
|
rexF:=get_force_rex(reg);
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:
|
|
begin
|
|
op:=$B0+Index;
|
|
end;
|
|
os16:
|
|
begin
|
|
Prefix:=$66;
|
|
op:=$B8+Index;
|
|
end;
|
|
os32:
|
|
begin
|
|
op:=$B8+Index;
|
|
end;
|
|
os64:
|
|
begin
|
|
rexW:=True;
|
|
op:=$B8+Index;
|
|
end;
|
|
else;
|
|
end;
|
|
|
|
if (Prefix<>0) then
|
|
begin
|
|
ji.EmitByte(Prefix); //Operand-size override prefix (16)
|
|
end;
|
|
|
|
if rexF or rexB or rexW then
|
|
begin
|
|
ji.EmitREX(rexB,False,False,rexW);
|
|
end;
|
|
|
|
ji.EmitByte(op);
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os8:ji.EmitByte (imm);
|
|
os16:ji.EmitWord (imm);
|
|
os32:ji.EmitInt32(imm);
|
|
os64:ji.EmitInt64(imm);
|
|
else;
|
|
end;
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder.movq(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_mov($8B,$8A,reg,mem); //MOV r64, r/m64
|
|
end;
|
|
|
|
procedure t_jit_builder.movq(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_mov($89,$88,reg,mem); //MOV r/m64, r64
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_jit_builder.leaq(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
Assert(is_reg_size(reg,[os16,os32,os64]));
|
|
|
|
_mov($8D,$8D,reg,mem); //LEA r64,m
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_jit_builder.addq(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_mov($01,$00,reg,mem); //ADD r/m64, r64
|
|
end;
|
|
|
|
procedure t_jit_builder.addq(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_mov($03,$02,reg,mem); //ADD r64, r/m64
|
|
end;
|
|
|
|
procedure t_jit_builder.addq(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
begin
|
|
_mov($01,$00,reg0,reg1);
|
|
end;
|
|
|
|
procedure t_jit_builder.addi(reg:t_jit_reg;imm:Int64);
|
|
begin
|
|
_movi($81,$80,0,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.addi8(reg:t_jit_reg;imm:Byte);
|
|
begin
|
|
_movi8($83,0,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.addi8(size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
begin
|
|
_movi8($83,0,size,mem,imm);
|
|
end;
|
|
|
|
//
|
|
|
|
procedure t_jit_builder.subq(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_mov($29,$28,reg,mem); //SUB r/m64, r64
|
|
end;
|
|
|
|
procedure t_jit_builder.subq(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_mov($2B,$2A,reg,mem); //SUB r64, r/m64
|
|
end;
|
|
|
|
procedure t_jit_builder.subq(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
begin
|
|
_mov($29,$28,reg0,reg1);
|
|
end;
|
|
|
|
procedure t_jit_builder.subi(reg:t_jit_reg;imm:Int64);
|
|
begin
|
|
_movi($81,$80,5,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.subi8(reg:t_jit_reg;imm:Byte);
|
|
begin
|
|
_movi8($83,5,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.subi8(size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
begin
|
|
_movi8($83,5,size,mem,imm);
|
|
end;
|
|
|
|
///
|
|
|
|
procedure t_jit_builder.xorq(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
begin
|
|
_mov($31,$30,reg0,reg1);
|
|
end;
|
|
|
|
///
|
|
|
|
procedure t_jit_builder.cmpq(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_mov($39,$38,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpq(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_mov($3B,$3A,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpq(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
begin
|
|
_mov($39,$38,reg0,reg1);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpi(reg:t_jit_reg;imm:Int64);
|
|
begin
|
|
_movi($81,$80,7,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpi(size:TOperandSize;mem:t_jit_regs;imm:Int64);
|
|
begin
|
|
_movi($81,$80,7,size,mem,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpi8(reg:t_jit_reg;imm:Byte);
|
|
begin
|
|
_movi8($83,7,reg,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.cmpi8(size:TOperandSize;mem:t_jit_regs;imm:Byte);
|
|
begin
|
|
_movi8($83,7,size,mem,imm);
|
|
end;
|
|
|
|
|
|
///
|
|
|
|
procedure t_jit_builder.push16(mem:t_jit_regs);
|
|
begin
|
|
_push($FF,6,os16,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.push64(mem:t_jit_regs);
|
|
begin
|
|
_push($FF,6,os64,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.push(reg:t_jit_reg);
|
|
begin
|
|
_push($50,reg);
|
|
end;
|
|
|
|
procedure t_jit_builder.push8(imm:Integer);
|
|
begin
|
|
_pushi(os8,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.push16(imm:Integer);
|
|
begin
|
|
_pushi(os16,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.push32(imm:Integer);
|
|
begin
|
|
_pushi(os32,imm);
|
|
end;
|
|
|
|
procedure t_jit_builder.pop16(mem:t_jit_regs);
|
|
begin
|
|
_push($8F,0,os16,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.pop64(mem:t_jit_regs);
|
|
begin
|
|
_push($8F,0,os64,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.pop(reg:t_jit_reg);
|
|
begin
|
|
_push($58,reg);
|
|
end;
|
|
|
|
procedure t_jit_builder.pushfq;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($9C);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder.popfq;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($9D);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._pmov(Op0,Op1:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os64,os128]));
|
|
|
|
Assert(is_reg_type(reg,[regMm,regXmm]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_rm(reg,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
if (reg.ARegValue[0].ASize=os128) then
|
|
begin
|
|
ji.EmitByte($66); //xmm prefix
|
|
end;
|
|
|
|
modrm_info.emit_rex(ji,False);
|
|
|
|
ji.EmitByte(Op0);
|
|
ji.EmitByte(Op1);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder._vmov(Op0,Op1:Byte;reg:t_jit_reg;mem:t_jit_regs);
|
|
var
|
|
mreg:t_jit_reg;
|
|
|
|
modrm_info:t_modrm_info;
|
|
|
|
Vex:record
|
|
Length:Byte;
|
|
end;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg));
|
|
Assert(is_reg_size(reg,[os128,os256]));
|
|
|
|
Assert(is_reg_type(reg,[regXmm]));
|
|
|
|
Assert(reg.ARegValue[0].AScale<=1);
|
|
|
|
mreg:=Sums(mem);
|
|
|
|
Assert(is_reg_size(mreg,[os0,os32,os64]));
|
|
Assert(is_reg_type(mreg,[regNone,regGeneral,regRip]));
|
|
Assert(is_valid_scale(mreg));
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
case reg.ARegValue[0].ASize of
|
|
os128:Vex.Length:=0;
|
|
os256:Vex.Length:=1;
|
|
else;
|
|
end;
|
|
|
|
modrm_info:=Default(t_modrm_info);
|
|
|
|
modrm_info.build_rm(reg,mreg);
|
|
|
|
ji.EmitSelector(mreg.ASegment);
|
|
|
|
if (mreg.ARegValue[0].ASize=os32) then
|
|
begin
|
|
ji.EmitByte($67); //Address-size override prefix (32)
|
|
end;
|
|
|
|
if modrm_info.rexB or modrm_info.rexX then
|
|
begin
|
|
ji.EmitByte($C4); //VEX3
|
|
|
|
ji.EmitRXBm(modrm_info.rexB,modrm_info.rexX,modrm_info.rexR,1);
|
|
ji.EmitWvvv(False,0,Vex.Length,Op1);
|
|
end else
|
|
begin
|
|
ji.EmitByte($C5); //VEX2
|
|
|
|
ji.EmitRvvv(modrm_info.rexR,0,Vex.Length,Op1);
|
|
end;
|
|
|
|
ji.EmitByte(Op0);
|
|
|
|
modrm_info.emit_mrm(ji);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovdqu(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_vmov($6F,2,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovdqu(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_vmov($7F,2,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovdqa(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_vmov($6F,1,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovdqa(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_vmov($7F,1,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovntdq(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_vmov($E7,1,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovups(reg:t_jit_reg;mem:t_jit_regs);
|
|
begin
|
|
_vmov($10,0,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovups(mem:t_jit_regs;reg:t_jit_reg);
|
|
begin
|
|
_vmov($11,0,reg,mem);
|
|
end;
|
|
|
|
procedure t_jit_builder.vmovdqa(reg0:t_jit_reg;reg1:t_jit_reg);
|
|
var
|
|
rexB,rexX,rexR:Boolean;
|
|
|
|
ModRM:record
|
|
Index,RM:Byte;
|
|
end;
|
|
|
|
Vex:record
|
|
Length:Byte;
|
|
end;
|
|
|
|
ji:t_jit_instruction;
|
|
begin
|
|
Assert(is_one_reg(reg0));
|
|
Assert(is_one_reg(reg1));
|
|
|
|
Assert(is_reg_size(reg0,[os128,os256]));
|
|
Assert(is_reg_size(reg1,[os128,os256]));
|
|
|
|
Assert(is_reg_type(reg0,[regXmm]));
|
|
Assert(is_reg_type(reg1,[regXmm]));
|
|
|
|
Assert(reg0.ARegValue[0].AScale<=1);
|
|
Assert(reg1.ARegValue[0].AScale<=1);
|
|
|
|
Assert(reg0.ARegValue[0].ASize=reg1.ARegValue[0].ASize);
|
|
|
|
ji:=default_jit_instruction;
|
|
|
|
rexB:=false;
|
|
rexX:=false;
|
|
rexR:=false;
|
|
|
|
ModRM.Index:=reg0.ARegValue[0].AIndex;
|
|
if (ModRM.Index>=8) then
|
|
begin
|
|
rexR:=true;
|
|
Dec(ModRM.Index,8);
|
|
end;
|
|
|
|
ModRM.RM:=reg1.ARegValue[0].AIndex;
|
|
if (ModRM.RM>=8) then
|
|
begin
|
|
rexB:=true;
|
|
Dec(ModRM.RM,8);
|
|
end;
|
|
|
|
case reg0.ARegValue[0].ASize of
|
|
os128:Vex.Length:=0;
|
|
os256:Vex.Length:=1;
|
|
else;
|
|
end;
|
|
|
|
if rexB or rexX then
|
|
begin
|
|
ji.EmitByte($C4); //VEX3
|
|
|
|
ji.EmitRXBm(rexB,rexX,rexR,1);
|
|
ji.EmitWvvv(False,0,Vex.Length,1);
|
|
end else
|
|
begin
|
|
ji.EmitByte($C5); //VEX2
|
|
|
|
ji.EmitRvvv(rexR,0,Vex.Length,1);
|
|
end;
|
|
|
|
ji.EmitByte($6F);
|
|
|
|
ji.EmitModRM(3,ModRM.Index,ModRM.RM);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder.sahf;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($9E);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
procedure t_jit_builder.lahf;
|
|
var
|
|
ji:t_jit_instruction;
|
|
begin
|
|
ji:=default_jit_instruction;
|
|
|
|
ji.EmitByte($9F);
|
|
|
|
_add(ji);
|
|
end;
|
|
|
|
end.
|
|
|
|
|
|
|