forked from KolibriOS/kolibrios
2782 lines
70 KiB
Plaintext
2782 lines
70 KiB
Plaintext
|
(*
|
||
|
BSD 2-Clause License
|
||
|
|
||
|
Copyright (c) 2018, 2019, Anton Krotov
|
||
|
All rights reserved.
|
||
|
*)
|
||
|
|
||
|
MODULE AMD64;
|
||
|
|
||
|
IMPORT CODE, BIN, WR := WRITER, CHL := CHUNKLISTS, MACHINE, LISTS, PATHS,
|
||
|
REG, C := CONSOLE, UTILS, mConst := CONSTANTS, S := STRINGS, PE32, ELF, X86;
|
||
|
|
||
|
|
||
|
CONST
|
||
|
|
||
|
rax = REG.R0;
|
||
|
r10 = REG.R10;
|
||
|
r11 = REG.R11;
|
||
|
|
||
|
rcx = REG.R1;
|
||
|
rdx = REG.R2;
|
||
|
r8 = REG.R8;
|
||
|
r9 = REG.R9;
|
||
|
|
||
|
rsp = 4;
|
||
|
rbp = 5;
|
||
|
rsi = 6;
|
||
|
rdi = 7;
|
||
|
|
||
|
je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H;
|
||
|
|
||
|
sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H;
|
||
|
|
||
|
shl = CODE.opLSL2; shr = CODE.opLSR2; sar = CODE.opASR2; ror = CODE.opROR2;
|
||
|
|
||
|
sCODE = BIN.PICCODE;
|
||
|
sDATA = BIN.PICDATA;
|
||
|
sBSS = BIN.PICBSS;
|
||
|
sIMP = BIN.PICIMP;
|
||
|
|
||
|
|
||
|
TYPE
|
||
|
|
||
|
COMMAND = CODE.COMMAND;
|
||
|
|
||
|
Number = POINTER TO RECORD (LISTS.ITEM) value: INTEGER END;
|
||
|
|
||
|
OPRR = PROCEDURE (reg1, reg2: INTEGER);
|
||
|
|
||
|
|
||
|
VAR
|
||
|
|
||
|
R: REG.REGS;
|
||
|
|
||
|
Numbers: LISTS.LIST;
|
||
|
Numbers_Count: INTEGER;
|
||
|
Numbers_Offs: INTEGER;
|
||
|
|
||
|
prog: BIN.PROGRAM;
|
||
|
|
||
|
dllret: INTEGER;
|
||
|
|
||
|
Win64RegPar: ARRAY 4 OF INTEGER;
|
||
|
SystemVRegPar: ARRAY 6 OF INTEGER;
|
||
|
|
||
|
|
||
|
PROCEDURE OutByte (b: BYTE);
|
||
|
BEGIN
|
||
|
X86.OutByte(b)
|
||
|
END OutByte;
|
||
|
|
||
|
|
||
|
PROCEDURE OutByte2 (a, b: BYTE);
|
||
|
BEGIN
|
||
|
OutByte(a);
|
||
|
OutByte(b)
|
||
|
END OutByte2;
|
||
|
|
||
|
|
||
|
PROCEDURE OutByte3 (a, b, c: BYTE);
|
||
|
BEGIN
|
||
|
OutByte(a);
|
||
|
OutByte(b);
|
||
|
OutByte(c)
|
||
|
END OutByte3;
|
||
|
|
||
|
|
||
|
PROCEDURE OutInt (n: INTEGER);
|
||
|
BEGIN
|
||
|
OutByte(MACHINE.Byte(n, 0));
|
||
|
OutByte(MACHINE.Byte(n, 1));
|
||
|
OutByte(MACHINE.Byte(n, 2));
|
||
|
OutByte(MACHINE.Byte(n, 3))
|
||
|
END OutInt;
|
||
|
|
||
|
|
||
|
PROCEDURE isByte (n: INTEGER): BOOLEAN;
|
||
|
RETURN (-128 <= n) & (n <= 127)
|
||
|
END isByte;
|
||
|
|
||
|
|
||
|
PROCEDURE short (n: INTEGER): INTEGER;
|
||
|
RETURN 2 * ORD(isByte(n))
|
||
|
END short;
|
||
|
|
||
|
|
||
|
PROCEDURE long (n: INTEGER): INTEGER;
|
||
|
RETURN 40H * ORD(~isByte(n))
|
||
|
END long;
|
||
|
|
||
|
|
||
|
PROCEDURE OutIntByte (n: INTEGER);
|
||
|
BEGIN
|
||
|
IF isByte(n) THEN
|
||
|
OutByte(MACHINE.Byte(n, 0))
|
||
|
ELSE
|
||
|
OutInt(n)
|
||
|
END
|
||
|
END OutIntByte;
|
||
|
|
||
|
|
||
|
PROCEDURE isLong (n: INTEGER): BOOLEAN;
|
||
|
RETURN (n > MACHINE.max32) OR (n < MACHINE.min32)
|
||
|
END isLong;
|
||
|
|
||
|
|
||
|
PROCEDURE NewNumber (value: INTEGER);
|
||
|
VAR
|
||
|
number: Number;
|
||
|
|
||
|
BEGIN
|
||
|
NEW(number);
|
||
|
number.value := value;
|
||
|
LISTS.push(Numbers, number);
|
||
|
INC(Numbers_Count)
|
||
|
END NewNumber;
|
||
|
|
||
|
|
||
|
PROCEDURE NewLabel (): INTEGER;
|
||
|
BEGIN
|
||
|
BIN.NewLabel(prog)
|
||
|
RETURN CODE.NewLabel()
|
||
|
END NewLabel;
|
||
|
|
||
|
|
||
|
PROCEDURE Rex (reg1, reg2: INTEGER);
|
||
|
BEGIN
|
||
|
OutByte(48H + reg1 DIV 8 + 4 * (reg2 DIV 8))
|
||
|
END Rex;
|
||
|
|
||
|
|
||
|
PROCEDURE lea (reg, offset, section: INTEGER);
|
||
|
BEGIN
|
||
|
Rex(0, reg);
|
||
|
OutByte2(8DH, 05H + 8 * (reg MOD 8)); // lea reg, [rip + offset]
|
||
|
X86.Reloc(section, offset)
|
||
|
END lea;
|
||
|
|
||
|
|
||
|
PROCEDURE oprr (op: BYTE; reg1, reg2: INTEGER); // op reg1, reg2
|
||
|
BEGIN
|
||
|
Rex(reg1, reg2);
|
||
|
OutByte2(op, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8)
|
||
|
END oprr;
|
||
|
|
||
|
|
||
|
PROCEDURE oprr2 (op1, op2: BYTE; reg1, reg2: INTEGER); // op reg1, reg2
|
||
|
BEGIN
|
||
|
Rex(reg1, reg2);
|
||
|
OutByte3(op1, op2, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8)
|
||
|
END oprr2;
|
||
|
|
||
|
|
||
|
PROCEDURE mov (reg1, reg2: INTEGER); // mov reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(89H, reg1, reg2)
|
||
|
END mov;
|
||
|
|
||
|
|
||
|
PROCEDURE xor (reg1, reg2: INTEGER); // xor reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(31H, reg1, reg2)
|
||
|
END xor;
|
||
|
|
||
|
|
||
|
PROCEDURE and (reg1, reg2: INTEGER); // and reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(21H, reg1, reg2)
|
||
|
END and;
|
||
|
|
||
|
|
||
|
PROCEDURE or (reg1, reg2: INTEGER); // and reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(09H, reg1, reg2)
|
||
|
END or;
|
||
|
|
||
|
|
||
|
PROCEDURE add (reg1, reg2: INTEGER); // add reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(01H, reg1, reg2)
|
||
|
END add;
|
||
|
|
||
|
|
||
|
PROCEDURE sub (reg1, reg2: INTEGER); // sub reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(29H, reg1, reg2)
|
||
|
END sub;
|
||
|
|
||
|
|
||
|
PROCEDURE xchg (reg1, reg2: INTEGER); // xchg reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(87H, reg1, reg2)
|
||
|
END xchg;
|
||
|
|
||
|
|
||
|
PROCEDURE cmprr (reg1, reg2: INTEGER); // cmp reg1, reg2
|
||
|
BEGIN
|
||
|
oprr(39H, reg1, reg2)
|
||
|
END cmprr;
|
||
|
|
||
|
|
||
|
PROCEDURE pop (reg: INTEGER); // pop reg
|
||
|
BEGIN
|
||
|
IF reg >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte(58H + reg MOD 8)
|
||
|
END pop;
|
||
|
|
||
|
|
||
|
PROCEDURE push (reg: INTEGER); // push reg
|
||
|
BEGIN
|
||
|
IF reg >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte(50H + reg MOD 8)
|
||
|
END push;
|
||
|
|
||
|
|
||
|
PROCEDURE decr (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(0FFH, 0C8H + reg MOD 8) // dec reg1
|
||
|
END decr;
|
||
|
|
||
|
|
||
|
PROCEDURE incr (reg: INTEGER);
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(0FFH, 0C0H + reg MOD 8) // inc reg1
|
||
|
END incr;
|
||
|
|
||
|
|
||
|
PROCEDURE drop;
|
||
|
BEGIN
|
||
|
REG.Drop(R)
|
||
|
END drop;
|
||
|
|
||
|
|
||
|
PROCEDURE callimp (label: INTEGER);
|
||
|
VAR
|
||
|
reg: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
reg := REG.GetAnyReg(R);
|
||
|
lea(reg, label, sIMP);
|
||
|
IF reg >= 8 THEN // call qword[reg]
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte2(0FFH, 10H + reg MOD 8);
|
||
|
drop
|
||
|
END callimp;
|
||
|
|
||
|
|
||
|
PROCEDURE pushDA (offs: INTEGER);
|
||
|
VAR
|
||
|
reg: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
reg := REG.GetAnyReg(R);
|
||
|
lea(reg, offs, sDATA);
|
||
|
push(reg);
|
||
|
drop
|
||
|
END pushDA;
|
||
|
|
||
|
|
||
|
PROCEDURE CallRTL (proc: INTEGER);
|
||
|
VAR
|
||
|
label: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
REG.Store(R);
|
||
|
label := CODE.codes.rtl[proc];
|
||
|
IF label < 0 THEN
|
||
|
callimp(-label)
|
||
|
ELSE
|
||
|
X86.call(label)
|
||
|
END;
|
||
|
REG.Restore(R)
|
||
|
END CallRTL;
|
||
|
|
||
|
|
||
|
PROCEDURE UnOp (VAR reg: INTEGER);
|
||
|
BEGIN
|
||
|
REG.UnOp(R, reg)
|
||
|
END UnOp;
|
||
|
|
||
|
|
||
|
PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
|
||
|
BEGIN
|
||
|
REG.BinOp(R, reg1, reg2)
|
||
|
END BinOp;
|
||
|
|
||
|
|
||
|
PROCEDURE PushAll (NumberOfParameters: INTEGER);
|
||
|
BEGIN
|
||
|
REG.PushAll(R);
|
||
|
R.pushed := R.pushed - NumberOfParameters
|
||
|
END PushAll;
|
||
|
|
||
|
|
||
|
PROCEDURE movabs (reg, n: INTEGER);
|
||
|
VAR
|
||
|
i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
OutByte(0B8H + reg MOD 8); // movabs reg, n
|
||
|
FOR i := 0 TO 7 DO
|
||
|
OutByte(MACHINE.Byte(n, i))
|
||
|
END
|
||
|
END movabs;
|
||
|
|
||
|
|
||
|
PROCEDURE movrc (reg, n: INTEGER); // mov reg, n
|
||
|
BEGIN
|
||
|
IF isLong(n) THEN
|
||
|
movabs(reg, n)
|
||
|
ELSE
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(0C7H, 0C0H + reg MOD 8);
|
||
|
OutInt(n)
|
||
|
END
|
||
|
END movrc;
|
||
|
|
||
|
|
||
|
PROCEDURE test (reg: INTEGER); // test reg, reg
|
||
|
BEGIN
|
||
|
oprr(85H, reg, reg)
|
||
|
END test;
|
||
|
|
||
|
|
||
|
PROCEDURE oprlongc (reg, n: INTEGER; oprr: OPRR);
|
||
|
VAR
|
||
|
reg2: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movabs(reg2, n);
|
||
|
oprr(reg, reg2);
|
||
|
drop
|
||
|
END oprlongc;
|
||
|
|
||
|
|
||
|
PROCEDURE oprc (op, reg, n: INTEGER; oprr: OPRR);
|
||
|
BEGIN
|
||
|
IF isLong(n) THEN
|
||
|
oprlongc(reg, n, oprr)
|
||
|
ELSE
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(81H + short(n), op + reg MOD 8);
|
||
|
OutIntByte(n)
|
||
|
END
|
||
|
END oprc;
|
||
|
|
||
|
|
||
|
PROCEDURE cmprc (reg, n: INTEGER); // cmp reg, n
|
||
|
BEGIN
|
||
|
oprc(0F8H, reg, n, cmprr)
|
||
|
END cmprc;
|
||
|
|
||
|
|
||
|
PROCEDURE addrc (reg, n: INTEGER); // add reg, n
|
||
|
BEGIN
|
||
|
oprc(0C0H, reg, n, add)
|
||
|
END addrc;
|
||
|
|
||
|
|
||
|
PROCEDURE subrc (reg, n: INTEGER); // sub reg, n
|
||
|
BEGIN
|
||
|
oprc(0E8H, reg, n, sub)
|
||
|
END subrc;
|
||
|
|
||
|
|
||
|
PROCEDURE andrc (reg, n: INTEGER); // and reg, n
|
||
|
BEGIN
|
||
|
oprc(0E0H, reg, n, and)
|
||
|
END andrc;
|
||
|
|
||
|
|
||
|
PROCEDURE pushc (n: INTEGER);
|
||
|
VAR
|
||
|
reg2: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
IF isLong(n) THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movabs(reg2, n);
|
||
|
push(reg2);
|
||
|
drop
|
||
|
ELSE
|
||
|
OutByte(68H + short(n)); OutIntByte(n) // push n
|
||
|
END
|
||
|
END pushc;
|
||
|
|
||
|
|
||
|
PROCEDURE not (reg: INTEGER); // not reg
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(0F7H, 0D0H + reg MOD 8)
|
||
|
END not;
|
||
|
|
||
|
|
||
|
PROCEDURE neg (reg: INTEGER); // neg reg
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
OutByte2(0F7H, 0D8H + reg MOD 8)
|
||
|
END neg;
|
||
|
|
||
|
|
||
|
PROCEDURE movzx (reg1, reg2, offs: INTEGER; word: BOOLEAN); // movzx reg1, byte/word[reg2 + offs]
|
||
|
VAR
|
||
|
b: BYTE;
|
||
|
|
||
|
BEGIN
|
||
|
Rex(reg2, reg1);
|
||
|
OutByte2(0FH, 0B6H + ORD(word));
|
||
|
IF (offs = 0) & (reg2 # rbp) THEN
|
||
|
b := 0
|
||
|
ELSE
|
||
|
b := 40H + long(offs)
|
||
|
END;
|
||
|
OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8);
|
||
|
IF reg2 = rsp THEN
|
||
|
OutByte(24H)
|
||
|
END;
|
||
|
IF b # 0 THEN
|
||
|
OutIntByte(offs)
|
||
|
END
|
||
|
END movzx;
|
||
|
|
||
|
|
||
|
PROCEDURE _movrm (reg1, reg2, offs, size: INTEGER; mr: BOOLEAN);
|
||
|
VAR
|
||
|
b: BYTE;
|
||
|
|
||
|
BEGIN
|
||
|
IF size = 16 THEN
|
||
|
OutByte(66H)
|
||
|
END;
|
||
|
IF (reg1 >= 8) OR (reg2 >= 8) OR (size = 64) THEN
|
||
|
OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8) + 8 * ORD(size = 64))
|
||
|
END;
|
||
|
OutByte(8BH - 2 * ORD(mr) - ORD(size = 8));
|
||
|
IF (offs = 0) & (reg2 # rbp) THEN
|
||
|
b := 0
|
||
|
ELSE
|
||
|
b := 40H + long(offs)
|
||
|
END;
|
||
|
OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8);
|
||
|
IF reg2 = rsp THEN
|
||
|
OutByte(24H)
|
||
|
END;
|
||
|
IF b # 0 THEN
|
||
|
OutIntByte(offs)
|
||
|
END
|
||
|
END _movrm;
|
||
|
|
||
|
|
||
|
PROCEDURE movmr32 (reg1, offs, reg2: INTEGER); // mov dword[reg1+offs], reg2_32
|
||
|
BEGIN
|
||
|
_movrm(reg2, reg1, offs, 32, TRUE)
|
||
|
END movmr32;
|
||
|
|
||
|
|
||
|
PROCEDURE movrm32 (reg1, reg2, offs: INTEGER); // mov reg1_32, dword[reg2+offs]
|
||
|
BEGIN
|
||
|
_movrm(reg1, reg2, offs, 32, FALSE)
|
||
|
END movrm32;
|
||
|
|
||
|
|
||
|
PROCEDURE movmr8 (reg1, offs, reg2: INTEGER); // mov byte[reg1+offs], reg2_8
|
||
|
BEGIN
|
||
|
_movrm(reg2, reg1, offs, 8, TRUE)
|
||
|
END movmr8;
|
||
|
|
||
|
|
||
|
PROCEDURE movrm8 (reg1, reg2, offs: INTEGER); // mov reg1_8, byte[reg2+offs]
|
||
|
BEGIN
|
||
|
_movrm(reg1, reg2, offs, 8, FALSE)
|
||
|
END movrm8;
|
||
|
|
||
|
|
||
|
PROCEDURE movmr16 (reg1, offs, reg2: INTEGER); // mov word[reg1+offs], reg2_16
|
||
|
BEGIN
|
||
|
_movrm(reg2, reg1, offs, 16, TRUE)
|
||
|
END movmr16;
|
||
|
|
||
|
|
||
|
PROCEDURE movrm16 (reg1, reg2, offs: INTEGER); // mov reg1_16, word[reg2+offs]
|
||
|
BEGIN
|
||
|
_movrm(reg1, reg2, offs, 16, FALSE)
|
||
|
END movrm16;
|
||
|
|
||
|
|
||
|
PROCEDURE movmr (reg1, offs, reg2: INTEGER); // mov qword[reg1+offs], reg2
|
||
|
BEGIN
|
||
|
_movrm(reg2, reg1, offs, 64, TRUE)
|
||
|
END movmr;
|
||
|
|
||
|
|
||
|
PROCEDURE movrm (reg1, reg2, offs: INTEGER); // mov reg1, qword[reg2+offs]
|
||
|
BEGIN
|
||
|
_movrm(reg1, reg2, offs, 64, FALSE)
|
||
|
END movrm;
|
||
|
|
||
|
|
||
|
PROCEDURE pushm (reg, offs: INTEGER); // push qword[reg+offs]
|
||
|
VAR
|
||
|
b: BYTE;
|
||
|
|
||
|
BEGIN
|
||
|
IF reg >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte(0FFH);
|
||
|
IF (offs = 0) & (reg # rbp) THEN
|
||
|
b := 30H
|
||
|
ELSE
|
||
|
b := 70H + long(offs)
|
||
|
END;
|
||
|
OutByte(b + reg MOD 8);
|
||
|
IF reg = rsp THEN
|
||
|
OutByte(24H)
|
||
|
END;
|
||
|
IF b # 30H THEN
|
||
|
OutIntByte(offs)
|
||
|
END
|
||
|
END pushm;
|
||
|
|
||
|
|
||
|
PROCEDURE comisd (xmm1, xmm2: INTEGER); // comisd xmm1, xmm2
|
||
|
BEGIN
|
||
|
OutByte(66H);
|
||
|
IF (xmm1 >= 8) OR (xmm2 >= 8) THEN
|
||
|
OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8)
|
||
|
END;
|
||
|
OutByte3(0FH, 2FH, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8)
|
||
|
END comisd;
|
||
|
|
||
|
|
||
|
PROCEDURE _movsdrm (xmm, reg, offs: INTEGER; mr: BOOLEAN);
|
||
|
VAR
|
||
|
b: BYTE;
|
||
|
|
||
|
BEGIN
|
||
|
OutByte(0F2H);
|
||
|
IF (xmm >= 8) OR (reg >= 8) THEN
|
||
|
OutByte(40H + (xmm DIV 8) * 4 + reg DIV 8)
|
||
|
END;
|
||
|
OutByte2(0FH, 10H + ORD(mr));
|
||
|
IF (offs = 0) & (reg # rbp) THEN
|
||
|
b := 0
|
||
|
ELSE
|
||
|
b := 40H + long(offs)
|
||
|
END;
|
||
|
OutByte(b + (xmm MOD 8) * 8 + reg MOD 8);
|
||
|
IF reg = rsp THEN
|
||
|
OutByte(24H)
|
||
|
END;
|
||
|
IF b # 0 THEN
|
||
|
OutIntByte(offs)
|
||
|
END
|
||
|
END _movsdrm;
|
||
|
|
||
|
|
||
|
PROCEDURE movsdrm (xmm, reg, offs: INTEGER); // movsd xmm, qword[reg+offs]
|
||
|
BEGIN
|
||
|
_movsdrm(xmm, reg, offs, FALSE)
|
||
|
END movsdrm;
|
||
|
|
||
|
|
||
|
PROCEDURE movsdmr (reg, offs, xmm: INTEGER); // movsd qword[reg+offs], xmm
|
||
|
BEGIN
|
||
|
_movsdrm(xmm, reg, offs, TRUE)
|
||
|
END movsdmr;
|
||
|
|
||
|
|
||
|
PROCEDURE opxx (op, xmm1, xmm2: INTEGER);
|
||
|
BEGIN
|
||
|
OutByte(0F2H);
|
||
|
IF (xmm1 >= 8) OR (xmm2 >= 8) THEN
|
||
|
OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8)
|
||
|
END;
|
||
|
OutByte3(0FH, op, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8)
|
||
|
END opxx;
|
||
|
|
||
|
|
||
|
PROCEDURE jcc (cc, label: INTEGER); // jcc label
|
||
|
BEGIN
|
||
|
X86.jcc(cc, label)
|
||
|
END jcc;
|
||
|
|
||
|
|
||
|
PROCEDURE jmp (label: INTEGER); // jmp label
|
||
|
BEGIN
|
||
|
X86.jmp(label)
|
||
|
END jmp;
|
||
|
|
||
|
|
||
|
PROCEDURE setcc (cc, reg: INTEGER); //setcc reg8
|
||
|
BEGIN
|
||
|
IF reg >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte3(0FH, cc, 0C0H + reg MOD 8)
|
||
|
END setcc;
|
||
|
|
||
|
|
||
|
PROCEDURE shiftrc (op, reg, n: INTEGER);
|
||
|
BEGIN
|
||
|
Rex(reg, 0);
|
||
|
IF n = 1 THEN
|
||
|
OutByte(0D1H)
|
||
|
ELSE
|
||
|
OutByte(0C1H)
|
||
|
END;
|
||
|
X86.shift(op, reg MOD 8);
|
||
|
IF n # 1 THEN
|
||
|
OutByte(n)
|
||
|
END
|
||
|
END shiftrc;
|
||
|
|
||
|
|
||
|
PROCEDURE getVar (variables: LISTS.LIST; offset: INTEGER): CODE.LOCALVAR;
|
||
|
VAR
|
||
|
cur: CODE.LOCALVAR;
|
||
|
|
||
|
BEGIN
|
||
|
cur := variables.first(CODE.LOCALVAR);
|
||
|
WHILE (cur # NIL) & (cur.offset # offset) DO
|
||
|
cur := cur.next(CODE.LOCALVAR)
|
||
|
END
|
||
|
|
||
|
RETURN cur
|
||
|
END getVar;
|
||
|
|
||
|
|
||
|
PROCEDURE allocReg (cmd: COMMAND);
|
||
|
VAR
|
||
|
leave: BOOLEAN;
|
||
|
leaf: BOOLEAN;
|
||
|
cur: COMMAND;
|
||
|
variables: LISTS.LIST;
|
||
|
lvar, rvar: CODE.LOCALVAR;
|
||
|
reg: INTEGER;
|
||
|
max: INTEGER;
|
||
|
loop: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
loop := 1;
|
||
|
variables := cmd.variables;
|
||
|
leave := FALSE;
|
||
|
leaf := TRUE;
|
||
|
|
||
|
cur := cmd.next(COMMAND);
|
||
|
REPEAT
|
||
|
CASE cur.opcode OF
|
||
|
|CODE.opLLOAD64,
|
||
|
CODE.opLLOAD8,
|
||
|
CODE.opLLOAD16,
|
||
|
CODE.opLLOAD32,
|
||
|
CODE.opLLOAD64_PARAM,
|
||
|
CODE.opLLOAD32_PARAM,
|
||
|
CODE.opLADR_SAVE,
|
||
|
CODE.opLADR_INC1,
|
||
|
CODE.opLADR_DEC1,
|
||
|
CODE.opLADR_INC,
|
||
|
CODE.opLADR_DEC,
|
||
|
CODE.opLADR_INC1B,
|
||
|
CODE.opLADR_DEC1B,
|
||
|
CODE.opLADR_INCB,
|
||
|
CODE.opLADR_DECB,
|
||
|
CODE.opLADR_INCL,
|
||
|
CODE.opLADR_EXCL,
|
||
|
CODE.opLADR_UNPK:
|
||
|
lvar := getVar(variables, cur.param2);
|
||
|
IF (lvar # NIL) & (lvar.count # -1) THEN
|
||
|
INC(lvar.count, loop)
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_SAVEC,
|
||
|
CODE.opLADR_INCC,
|
||
|
CODE.opLADR_DECC,
|
||
|
CODE.opLADR_INCCB,
|
||
|
CODE.opLADR_DECCB,
|
||
|
CODE.opLADR_INCLC,
|
||
|
CODE.opLADR_EXCLC:
|
||
|
lvar := getVar(variables, cur.param1);
|
||
|
IF (lvar # NIL) & (lvar.count # -1) THEN
|
||
|
INC(lvar.count, loop)
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR:
|
||
|
lvar := getVar(variables, cur.param2);
|
||
|
IF (lvar # NIL) & (lvar.count # -1) THEN
|
||
|
lvar.count := -1
|
||
|
END
|
||
|
|
||
|
|CODE.opLOOP:
|
||
|
INC(loop, 10)
|
||
|
|
||
|
|CODE.opENDLOOP:
|
||
|
DEC(loop, 10)
|
||
|
|
||
|
|CODE.opLEAVE,
|
||
|
CODE.opLEAVER,
|
||
|
CODE.opLEAVEF:
|
||
|
leave := TRUE
|
||
|
|
||
|
|CODE.opCALL, CODE.opCALLP, CODE.opCALLI,
|
||
|
CODE.opWIN64CALL, CODE.opWIN64CALLP, CODE.opWIN64CALLI,
|
||
|
CODE.opSYSVCALL, CODE.opSYSVCALLP, CODE.opSYSVCALLI:
|
||
|
leaf := FALSE
|
||
|
|
||
|
ELSE
|
||
|
|
||
|
END;
|
||
|
cur := cur.next(COMMAND)
|
||
|
UNTIL leave OR ~leaf;
|
||
|
|
||
|
IF leaf THEN
|
||
|
REPEAT
|
||
|
reg := -1;
|
||
|
max := -1;
|
||
|
rvar := NIL;
|
||
|
lvar := variables.first(CODE.LOCALVAR);
|
||
|
WHILE lvar # NIL DO
|
||
|
IF lvar.count > max THEN
|
||
|
max := lvar.count;
|
||
|
rvar := lvar
|
||
|
END;
|
||
|
lvar := lvar.next(CODE.LOCALVAR)
|
||
|
END;
|
||
|
|
||
|
IF rvar # NIL THEN
|
||
|
reg := REG.GetAnyVarReg(R);
|
||
|
IF reg # -1 THEN
|
||
|
REG.Lock(R, reg, rvar.offset, rvar.size);
|
||
|
REG.Load(R, reg);
|
||
|
rvar.count := -1
|
||
|
END
|
||
|
END
|
||
|
|
||
|
UNTIL (rvar = NIL) OR (reg = -1)
|
||
|
END
|
||
|
|
||
|
END allocReg;
|
||
|
|
||
|
|
||
|
PROCEDURE GetRegA;
|
||
|
BEGIN
|
||
|
ASSERT(REG.GetReg(R, rax))
|
||
|
END GetRegA;
|
||
|
|
||
|
|
||
|
PROCEDURE Win64Passing (params: INTEGER);
|
||
|
VAR
|
||
|
n, i: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
n := params MOD 32;
|
||
|
params := params DIV 32;
|
||
|
FOR i := 0 TO n - 1 DO
|
||
|
IF i IN BITS(params) THEN
|
||
|
movsdrm(i, rsp, i * 8)
|
||
|
ELSE
|
||
|
movrm(Win64RegPar[i], rsp, i * 8)
|
||
|
END
|
||
|
END
|
||
|
END Win64Passing;
|
||
|
|
||
|
|
||
|
PROCEDURE SysVPassing (params: INTEGER);
|
||
|
VAR
|
||
|
n, i, s, p, ofs: INTEGER;
|
||
|
i_count, f_count: INTEGER;
|
||
|
reg: BOOLEAN;
|
||
|
|
||
|
BEGIN
|
||
|
ASSERT(r10 IN R.regs);
|
||
|
n := params MOD 32;
|
||
|
params := params DIV 32;
|
||
|
s := 0;
|
||
|
|
||
|
i_count := 0;
|
||
|
f_count := 0;
|
||
|
FOR i := 0 TO n - 1 DO
|
||
|
IF i IN BITS(params) THEN
|
||
|
INC(f_count)
|
||
|
ELSE
|
||
|
INC(i_count)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
s := MAX(0, f_count - 8) + MAX(0, i_count - 6);
|
||
|
p := 0;
|
||
|
|
||
|
subrc(rsp, s * 8);
|
||
|
|
||
|
i_count := 0;
|
||
|
f_count := 0;
|
||
|
FOR i := 0 TO n - 1 DO
|
||
|
ofs := (i + s) * 8;
|
||
|
IF i IN BITS(params) THEN
|
||
|
reg := f_count <= 7;
|
||
|
IF reg THEN
|
||
|
movsdrm(f_count, rsp, ofs);
|
||
|
INC(f_count)
|
||
|
END
|
||
|
ELSE
|
||
|
reg := i_count <= 5;
|
||
|
IF reg THEN
|
||
|
movrm(SystemVRegPar[i_count], rsp, ofs);
|
||
|
INC(i_count)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
IF ~reg THEN
|
||
|
movrm(r10, rsp, ofs);
|
||
|
movmr(rsp, p, r10);
|
||
|
INC(p, 8)
|
||
|
END
|
||
|
END
|
||
|
END SysVPassing;
|
||
|
|
||
|
|
||
|
PROCEDURE fcmp (op: INTEGER; xmm: INTEGER);
|
||
|
VAR
|
||
|
cc, reg: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
reg := REG.GetAnyReg(R);
|
||
|
xor(reg, reg);
|
||
|
CASE op OF
|
||
|
|CODE.opEQF, CODE.opEQFI:
|
||
|
comisd(xmm - 1, xmm);
|
||
|
cc := sete
|
||
|
|
||
|
|CODE.opNEF, CODE.opNEFI:
|
||
|
comisd(xmm - 1, xmm);
|
||
|
cc := setne
|
||
|
|
||
|
|CODE.opLTF, CODE.opGTFI:
|
||
|
comisd(xmm - 1, xmm);
|
||
|
cc := setc
|
||
|
|
||
|
|CODE.opGTF, CODE.opLTFI:
|
||
|
comisd(xmm, xmm - 1);
|
||
|
cc := setc
|
||
|
|
||
|
|CODE.opLEF, CODE.opGEFI:
|
||
|
comisd(xmm, xmm - 1);
|
||
|
cc := setnc
|
||
|
|
||
|
|CODE.opGEF, CODE.opLEFI:
|
||
|
comisd(xmm - 1, xmm);
|
||
|
cc := setnc
|
||
|
END;
|
||
|
OutByte2(7AH, 3 + reg DIV 8); // jp L
|
||
|
setcc(cc, reg);
|
||
|
//L:
|
||
|
END fcmp;
|
||
|
|
||
|
|
||
|
PROCEDURE translate (commands: LISTS.LIST; stroffs: INTEGER);
|
||
|
VAR
|
||
|
cmd, next: COMMAND;
|
||
|
|
||
|
param1, param2, param3, a, b, c, n, label, L, i, cc: INTEGER;
|
||
|
|
||
|
reg1, reg2, xmm: INTEGER;
|
||
|
|
||
|
float: REAL;
|
||
|
|
||
|
regVar: BOOLEAN;
|
||
|
|
||
|
BEGIN
|
||
|
xmm := -1;
|
||
|
cmd := commands.first(COMMAND);
|
||
|
WHILE cmd # NIL DO
|
||
|
|
||
|
param1 := cmd.param1;
|
||
|
param2 := cmd.param2;
|
||
|
|
||
|
CASE cmd.opcode OF
|
||
|
|
||
|
|CODE.opJMP:
|
||
|
jmp(param1)
|
||
|
|
||
|
|CODE.opCALL, CODE.opWIN64CALL, CODE.opSYSVCALL:
|
||
|
REG.Store(R);
|
||
|
CASE cmd.opcode OF
|
||
|
|CODE.opCALL:
|
||
|
|CODE.opWIN64CALL: Win64Passing(param2)
|
||
|
|CODE.opSYSVCALL: SysVPassing(param2)
|
||
|
END;
|
||
|
X86.call(param1);
|
||
|
REG.Restore(R)
|
||
|
|
||
|
|CODE.opCALLP, CODE.opWIN64CALLP, CODE.opSYSVCALLP:
|
||
|
UnOp(reg1);
|
||
|
IF reg1 # rax THEN
|
||
|
GetRegA;
|
||
|
ASSERT(REG.Exchange(R, reg1, rax));
|
||
|
drop
|
||
|
END;
|
||
|
drop;
|
||
|
REG.Store(R);
|
||
|
CASE cmd.opcode OF
|
||
|
|CODE.opCALLP:
|
||
|
|CODE.opWIN64CALLP: Win64Passing(param2)
|
||
|
|CODE.opSYSVCALLP: SysVPassing(param2)
|
||
|
END;
|
||
|
OutByte2(0FFH, 0D0H); // call rax
|
||
|
REG.Restore(R);
|
||
|
ASSERT(R.top = -1)
|
||
|
|
||
|
|CODE.opCALLI, CODE.opWIN64CALLI, CODE.opSYSVCALLI:
|
||
|
REG.Store(R);
|
||
|
CASE cmd.opcode OF
|
||
|
|CODE.opCALLI:
|
||
|
|CODE.opWIN64CALLI: Win64Passing(param2)
|
||
|
|CODE.opSYSVCALLI: SysVPassing(param2)
|
||
|
END;
|
||
|
callimp(param1);
|
||
|
REG.Restore(R)
|
||
|
|
||
|
|CODE.opLABEL:
|
||
|
X86.SetLabel(param2)
|
||
|
|
||
|
|CODE.opERR:
|
||
|
CallRTL(CODE._error)
|
||
|
|
||
|
|CODE.opERRC:
|
||
|
pushc(param2)
|
||
|
|
||
|
|CODE.opPRECALL:
|
||
|
n := param2;
|
||
|
IF (param1 # 0) & (n # 0) THEN
|
||
|
subrc(rsp, 8)
|
||
|
END;
|
||
|
WHILE n > 0 DO
|
||
|
subrc(rsp, 8);
|
||
|
movsdmr(rsp, 0, xmm);
|
||
|
DEC(xmm);
|
||
|
DEC(n)
|
||
|
END;
|
||
|
ASSERT(xmm = -1);
|
||
|
PushAll(0)
|
||
|
|
||
|
|CODE.opWIN64ALIGN16:
|
||
|
ASSERT(rax IN R.regs);
|
||
|
mov(rax, rsp);
|
||
|
andrc(rsp, -16);
|
||
|
push(rax);
|
||
|
subrc(rsp, (MAX(param2 - 4, 0) MOD 2 + MAX(4 - param2, 0) + 1) * 8)
|
||
|
|
||
|
|CODE.opSYSVALIGN16:
|
||
|
ASSERT(rax IN R.regs);
|
||
|
mov(rax, rsp);
|
||
|
andrc(rsp, -16);
|
||
|
push(rax);
|
||
|
IF ~ODD(param2) THEN
|
||
|
push(rax)
|
||
|
END
|
||
|
|
||
|
|CODE.opRESF:
|
||
|
ASSERT(xmm = -1);
|
||
|
INC(xmm);
|
||
|
n := param2;
|
||
|
IF n > 0 THEN
|
||
|
movsdmr(rsp, n * 8, xmm);
|
||
|
DEC(xmm);
|
||
|
INC(n)
|
||
|
END;
|
||
|
|
||
|
WHILE n > 0 DO
|
||
|
INC(xmm);
|
||
|
movsdrm(xmm, rsp, 0);
|
||
|
addrc(rsp, 8);
|
||
|
DEC(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opRES:
|
||
|
ASSERT(R.top = -1);
|
||
|
GetRegA;
|
||
|
n := param2;
|
||
|
WHILE n > 0 DO
|
||
|
INC(xmm);
|
||
|
movsdrm(xmm, rsp, 0);
|
||
|
addrc(rsp, 8);
|
||
|
DEC(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opENTER:
|
||
|
ASSERT(R.top = -1);
|
||
|
|
||
|
X86.SetLabel(param1);
|
||
|
|
||
|
param3 := cmd.param3;
|
||
|
|
||
|
IF param3 > 0 THEN
|
||
|
push(rbp);
|
||
|
mov(rbp, rsp);
|
||
|
|
||
|
n := param3 MOD 32;
|
||
|
param3 := param3 DIV 32;
|
||
|
|
||
|
FOR i := 0 TO n - 1 DO
|
||
|
IF i IN BITS(param3) THEN
|
||
|
movsdmr(rbp, i * 8 + 16, i)
|
||
|
ELSE
|
||
|
movmr(rbp, i * 8 + 16, Win64RegPar[i])
|
||
|
END
|
||
|
END
|
||
|
ELSIF param3 < 0 THEN
|
||
|
param3 := -param3;
|
||
|
n := (param3 MOD 32) * 8;
|
||
|
param3 := param3 DIV 32;
|
||
|
pop(r10);
|
||
|
subrc(rsp, n);
|
||
|
push(r10);
|
||
|
push(rbp);
|
||
|
mov(rbp, rsp);
|
||
|
|
||
|
a := 0;
|
||
|
b := 0;
|
||
|
c := 0;
|
||
|
|
||
|
INC(n, 16);
|
||
|
|
||
|
FOR i := 16 TO n - 8 BY 8 DO
|
||
|
IF ODD(param3) THEN
|
||
|
IF b <= 7 THEN
|
||
|
movsdmr(rbp, i, b);
|
||
|
INC(b)
|
||
|
ELSE
|
||
|
movrm(r10, rbp, n + c);
|
||
|
movmr(rbp, i, r10);
|
||
|
INC(c, 8)
|
||
|
END
|
||
|
ELSE
|
||
|
IF a <= 5 THEN
|
||
|
movmr(rbp, i, SystemVRegPar[a]);
|
||
|
INC(a)
|
||
|
ELSE
|
||
|
movrm(r10, rbp, n + c);
|
||
|
movmr(rbp, i, r10);
|
||
|
INC(c, 8)
|
||
|
END
|
||
|
END;
|
||
|
param3 := param3 DIV 2
|
||
|
END
|
||
|
ELSE
|
||
|
push(rbp);
|
||
|
mov(rbp, rsp)
|
||
|
END;
|
||
|
|
||
|
n := param2;
|
||
|
IF n > 4 THEN
|
||
|
movrc(rcx, n);
|
||
|
// L:
|
||
|
pushc(0);
|
||
|
OutByte2(0E2H, 0FCH) // loop L
|
||
|
ELSE
|
||
|
WHILE n > 0 DO
|
||
|
pushc(0);
|
||
|
DEC(n)
|
||
|
END
|
||
|
END;
|
||
|
|
||
|
IF cmd.allocReg THEN
|
||
|
allocReg(cmd)
|
||
|
END
|
||
|
|
||
|
|CODE.opLEAVE, CODE.opLEAVER, CODE.opLEAVEF:
|
||
|
IF cmd.opcode = CODE.opLEAVER THEN
|
||
|
UnOp(reg1);
|
||
|
IF reg1 # rax THEN
|
||
|
GetRegA;
|
||
|
ASSERT(REG.Exchange(R, reg1, rax));
|
||
|
drop
|
||
|
END;
|
||
|
drop
|
||
|
END;
|
||
|
|
||
|
ASSERT(R.top = -1);
|
||
|
|
||
|
IF cmd.opcode = CODE.opLEAVEF THEN
|
||
|
DEC(xmm)
|
||
|
END;
|
||
|
|
||
|
ASSERT(xmm = -1);
|
||
|
|
||
|
mov(rsp, rbp);
|
||
|
pop(rbp);
|
||
|
IF param2 > 0 THEN
|
||
|
OutByte3(0C2H, (param2 * 8) MOD 256, (param2 * 8) DIV 256) // ret param2
|
||
|
ELSE
|
||
|
OutByte(0C3H) // ret
|
||
|
END;
|
||
|
REG.Reset(R)
|
||
|
|
||
|
|CODE.opSAVES:
|
||
|
UnOp(reg1);
|
||
|
drop;
|
||
|
PushAll(0);
|
||
|
push(reg1);
|
||
|
pushDA(stroffs + param2);
|
||
|
pushc(param1);
|
||
|
CallRTL(CODE._move)
|
||
|
|
||
|
|CODE.opSADR:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, stroffs + param2, sDATA)
|
||
|
|
||
|
|CODE.opLOAD8:
|
||
|
UnOp(reg1);
|
||
|
movzx(reg1, reg1, 0, FALSE)
|
||
|
|
||
|
|CODE.opLOAD16:
|
||
|
UnOp(reg1);
|
||
|
movzx(reg1, reg1, 0, TRUE)
|
||
|
|
||
|
|CODE.opLOAD32:
|
||
|
UnOp(reg1);
|
||
|
movrm32(reg1, reg1, 0);
|
||
|
shiftrc(shl, reg1, 32);
|
||
|
shiftrc(shr, reg1, 32)
|
||
|
|
||
|
|CODE.opLOAD64:
|
||
|
UnOp(reg1);
|
||
|
movrm(reg1, reg1, 0)
|
||
|
|
||
|
|CODE.opLLOAD64:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
mov(reg1, reg2)
|
||
|
ELSE
|
||
|
movrm(reg1, rbp, param2 * 8)
|
||
|
END
|
||
|
|
||
|
|CODE.opLLOAD8,
|
||
|
CODE.opLLOAD16:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
mov(reg1, reg2)
|
||
|
ELSE
|
||
|
movzx(reg1, rbp, param2 * 8, cmd.opcode = CODE.opLLOAD16)
|
||
|
END
|
||
|
|
||
|
|CODE.opLLOAD32:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
mov(reg1, reg2)
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
xor(reg1, reg1);
|
||
|
movrm32(reg1, rbp, n)
|
||
|
END
|
||
|
|
||
|
|CODE.opGLOAD64:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sBSS);
|
||
|
movrm(reg1, reg1, 0)
|
||
|
|
||
|
|CODE.opGLOAD8:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sBSS);
|
||
|
movzx(reg1, reg1, 0, FALSE)
|
||
|
|
||
|
|CODE.opGLOAD16:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sBSS);
|
||
|
movzx(reg1, reg1, 0, TRUE)
|
||
|
|
||
|
|CODE.opGLOAD32:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
xor(reg1, reg1);
|
||
|
lea(reg1, param2, sBSS);
|
||
|
movrm32(reg1, reg1, 0)
|
||
|
|
||
|
|CODE.opVLOAD64:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrm(reg1, rbp, param2 * 8);
|
||
|
movrm(reg1, reg1, 0)
|
||
|
|
||
|
|CODE.opVLOAD8,
|
||
|
CODE.opVLOAD16:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrm(reg1, rbp, param2 * 8);
|
||
|
movzx(reg1, reg1, 0, cmd.opcode = CODE.opVLOAD16)
|
||
|
|
||
|
|CODE.opVLOAD32:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
xor(reg1, reg1);
|
||
|
movrm(reg2, rbp, param2 * 8);
|
||
|
movrm32(reg1, reg2, 0);
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR:
|
||
|
n := param2 * 8;
|
||
|
next := cmd.next(COMMAND);
|
||
|
IF next.opcode = CODE.opSAVEF THEN
|
||
|
movsdmr(rbp, n, xmm);
|
||
|
DEC(xmm);
|
||
|
cmd := next
|
||
|
ELSIF next.opcode = CODE.opLOADF THEN
|
||
|
INC(xmm);
|
||
|
movsdrm(xmm, rbp, n);
|
||
|
cmd := next
|
||
|
ELSE
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
Rex(0, reg1);
|
||
|
OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8); // lea reg1, qword[rbp+n]
|
||
|
OutIntByte(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opGADR:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sBSS)
|
||
|
|
||
|
|CODE.opVADR:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrm(reg1, rbp, param2 * 8)
|
||
|
|
||
|
|CODE.opSAVE8C:
|
||
|
UnOp(reg1);
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte3(0C6H, reg1 MOD 8, param2); // mov byte[reg1], param2
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVE16C:
|
||
|
UnOp(reg1);
|
||
|
OutByte(66H);
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte2(0C7H, reg1 MOD 8);
|
||
|
OutByte2(param2 MOD 256, param2 DIV 256); // mov word[reg1], param2
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVEC:
|
||
|
UnOp(reg1);
|
||
|
IF isLong(param2) THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrc(reg2, param2);
|
||
|
movmr(reg1, 0, reg2);
|
||
|
drop
|
||
|
ELSE
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(0C7H, reg1 MOD 8); // mov qword[reg1], param2
|
||
|
OutInt(param2)
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opRSET:
|
||
|
PushAll(2);
|
||
|
CallRTL(CODE._set);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opRSETR:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._set);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opRSETL:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._set2);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opRSET1:
|
||
|
UnOp(reg1);
|
||
|
PushAll(1);
|
||
|
push(reg1);
|
||
|
CallRTL(CODE._set);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opINCL, CODE.opEXCL:
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprc(reg1, 64);
|
||
|
OutByte2(73H, 04H); // jnb L
|
||
|
Rex(reg2, reg1);
|
||
|
OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); // bts/btr qword[reg2], reg1
|
||
|
// L:
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opINCLC, CODE.opEXCLC:
|
||
|
UnOp(reg1);
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(0FH, 0BAH); // bts/btr qword[reg1], param2
|
||
|
OutByte2(28H + 8 * ORD(cmd.opcode = CODE.opEXCLC) + reg1 MOD 8, param2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opEQS .. CODE.opGES:
|
||
|
PushAll(4);
|
||
|
pushc(cmd.opcode - CODE.opEQS);
|
||
|
CallRTL(CODE._strcmp);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opEQS2 .. CODE.opGES2:
|
||
|
PushAll(4);
|
||
|
pushc(cmd.opcode - CODE.opEQS2);
|
||
|
CallRTL(CODE._strcmp2);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opEQSW .. CODE.opGESW:
|
||
|
PushAll(4);
|
||
|
pushc(cmd.opcode - CODE.opEQSW);
|
||
|
CallRTL(CODE._strcmpw);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opEQSW2 .. CODE.opGESW2:
|
||
|
PushAll(4);
|
||
|
pushc(cmd.opcode - CODE.opEQSW2);
|
||
|
CallRTL(CODE._strcmpw2);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opINC1, CODE.opDEC1:
|
||
|
UnOp(reg1);
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opDEC1));
|
||
|
drop
|
||
|
|
||
|
|CODE.opCONST:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrc(reg1, param2)
|
||
|
|
||
|
|CODE.opGT, CODE.opGE, CODE.opLT,
|
||
|
CODE.opLE, CODE.opEQ, CODE.opNE:
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprr(reg1, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
cc := X86.cond(cmd.opcode);
|
||
|
|
||
|
IF cmd.next(COMMAND).opcode = CODE.opJE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(cc, label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(X86.inv1(cc), label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSE
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
setcc(cc + 16, reg1);
|
||
|
andrc(reg1, 1)
|
||
|
END
|
||
|
|
||
|
|CODE.opGTR, CODE.opLTL, CODE.opGER, CODE.opLEL,
|
||
|
CODE.opLER, CODE.opGEL, CODE.opLTR, CODE.opGTL,
|
||
|
CODE.opEQR, CODE.opEQL, CODE.opNER, CODE.opNEL:
|
||
|
UnOp(reg1);
|
||
|
IF param2 = 0 THEN
|
||
|
test(reg1)
|
||
|
ELSE
|
||
|
cmprc(reg1, param2)
|
||
|
END;
|
||
|
drop;
|
||
|
cc := X86.cond(cmd.opcode);
|
||
|
|
||
|
IF cmd.next(COMMAND).opcode = CODE.opJE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(cc, label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
|
||
|
label := cmd.next(COMMAND).param1;
|
||
|
jcc(X86.inv1(cc), label);
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
|
||
|
ELSE
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
setcc(cc + 16, reg1);
|
||
|
andrc(reg1, 1)
|
||
|
END
|
||
|
|
||
|
|CODE.opCODE:
|
||
|
OutByte(param2)
|
||
|
|
||
|
|CODE.opPUSHIP:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sIMP);
|
||
|
movrm(reg1, reg1, 0)
|
||
|
|
||
|
|CODE.opPARAM:
|
||
|
n := param2;
|
||
|
IF n = 1 THEN
|
||
|
UnOp(reg1);
|
||
|
push(reg1);
|
||
|
drop
|
||
|
ELSE
|
||
|
ASSERT(R.top + 1 <= n);
|
||
|
PushAll(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opJNZ:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
jcc(jne, param1)
|
||
|
|
||
|
|CODE.opJZ:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
jcc(je, param1)
|
||
|
|
||
|
|CODE.opJE:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
jcc(jne, param1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opJNE:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
jcc(je, param1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opIN:
|
||
|
label := NewLabel();
|
||
|
L := NewLabel();
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprc(reg1, 64);
|
||
|
jcc(jb, L);
|
||
|
xor(reg1, reg1);
|
||
|
jmp(label);
|
||
|
X86.SetLabel(L);
|
||
|
Rex(reg2, reg1);
|
||
|
OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
|
||
|
setcc(setc, reg1);
|
||
|
andrc(reg1, 1);
|
||
|
X86.SetLabel(label);
|
||
|
drop
|
||
|
|
||
|
|CODE.opINR:
|
||
|
label := NewLabel();
|
||
|
L := NewLabel();
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
cmprc(reg1, 64);
|
||
|
jcc(jb, L);
|
||
|
xor(reg1, reg1);
|
||
|
jmp(label);
|
||
|
X86.SetLabel(L);
|
||
|
movrc(reg2, param2);
|
||
|
Rex(reg2, reg1);
|
||
|
OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
|
||
|
setcc(setc, reg1);
|
||
|
andrc(reg1, 1);
|
||
|
X86.SetLabel(label);
|
||
|
drop
|
||
|
|
||
|
|CODE.opINL:
|
||
|
UnOp(reg1);
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(0FH, 0BAH); // bt reg1, param2
|
||
|
OutByte2(0E0H + reg1 MOD 8, param2);
|
||
|
setcc(setc, reg1);
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opNOT:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
setcc(sete, reg1);
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opORD:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
setcc(setne, reg1);
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opABS:
|
||
|
UnOp(reg1);
|
||
|
test(reg1);
|
||
|
OutByte2(7DH, 03H); // jge L
|
||
|
neg(reg1)
|
||
|
// L:
|
||
|
|
||
|
|CODE.opEQB, CODE.opNEB:
|
||
|
BinOp(reg1, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
|
||
|
test(reg1);
|
||
|
OutByte2(74H, 07H); // je L1
|
||
|
movrc(reg1, 1);
|
||
|
// L1:
|
||
|
test(reg2);
|
||
|
OutByte2(74H, 07H); // je L2
|
||
|
movrc(reg2, 1);
|
||
|
// L2:
|
||
|
cmprr(reg1, reg2);
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
IF cmd.opcode = CODE.opEQB THEN
|
||
|
setcc(sete, reg1)
|
||
|
ELSE
|
||
|
setcc(setne, reg1)
|
||
|
END;
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opMULSC:
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, param2)
|
||
|
|
||
|
|CODE.opDIVSC, CODE.opADDSL, CODE.opADDSR:
|
||
|
UnOp(reg1);
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(81H + short(param2), 0C8H + 28H * ORD(cmd.opcode = CODE.opDIVSC) + reg1 MOD 8); // or/xor reg1, param2
|
||
|
OutIntByte(param2)
|
||
|
|
||
|
|CODE.opSUBSL:
|
||
|
UnOp(reg1);
|
||
|
not(reg1);
|
||
|
andrc(reg1, param2)
|
||
|
|
||
|
|CODE.opSUBSR:
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, ORD(-BITS(param2)))
|
||
|
|
||
|
|CODE.opMULS:
|
||
|
BinOp(reg1, reg2);
|
||
|
and(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opDIVS:
|
||
|
BinOp(reg1, reg2);
|
||
|
xor(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opUMINS:
|
||
|
UnOp(reg1);
|
||
|
not(reg1)
|
||
|
|
||
|
|CODE.opCOPY:
|
||
|
PushAll(2);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._move2)
|
||
|
|
||
|
|CODE.opMOVE:
|
||
|
PushAll(3);
|
||
|
CallRTL(CODE._move2)
|
||
|
|
||
|
|CODE.opCOPYA:
|
||
|
PushAll(4);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._arrcpy);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opCOPYS:
|
||
|
PushAll(4);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._strcpy)
|
||
|
|
||
|
|CODE.opCOPYS2:
|
||
|
PushAll(4);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._strcpy2)
|
||
|
|
||
|
|CODE.opROT:
|
||
|
PushAll(0);
|
||
|
push(rsp);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._rot)
|
||
|
|
||
|
|CODE.opNEW:
|
||
|
PushAll(1);
|
||
|
n := param2 + 16;
|
||
|
ASSERT(MACHINE.Align(n, 64));
|
||
|
pushc(n);
|
||
|
pushc(param1);
|
||
|
CallRTL(CODE._new)
|
||
|
|
||
|
|CODE.opDISP:
|
||
|
PushAll(1);
|
||
|
CallRTL(CODE._dispose)
|
||
|
|
||
|
|CODE.opPUSHT:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrm(reg2, reg1, -8)
|
||
|
|
||
|
|CODE.opISREC:
|
||
|
PushAll(2);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._isrec);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opIS:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._is);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opTYPEGR:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._guardrec);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opTYPEGP:
|
||
|
UnOp(reg1);
|
||
|
PushAll(0);
|
||
|
push(reg1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._guard);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opTYPEGD:
|
||
|
UnOp(reg1);
|
||
|
PushAll(0);
|
||
|
pushm(reg1, -8);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._guardrec);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opCASET:
|
||
|
push(r10);
|
||
|
push(r10);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._guardrec);
|
||
|
pop(r10);
|
||
|
test(rax);
|
||
|
jcc(jne, param1)
|
||
|
|
||
|
|CODE.opSAVEP:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
lea(reg2, param2, sCODE);
|
||
|
movmr(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opPUSHP:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, param2, sCODE)
|
||
|
|
||
|
|CODE.opINC, CODE.opDEC:
|
||
|
BinOp(reg1, reg2);
|
||
|
// add/sub qword[reg2], reg1
|
||
|
Rex(reg2, reg1);
|
||
|
OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opINCC, CODE.opDECC:
|
||
|
UnOp(reg1);
|
||
|
IF isLong(param2) THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrc(reg2, param2);
|
||
|
// add/sub qword[reg1], reg2
|
||
|
Rex(reg1, reg2);
|
||
|
OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDECC), reg1 MOD 8 + (reg2 MOD 8) * 8);
|
||
|
drop
|
||
|
ELSE
|
||
|
// add/sub qword[reg1], param2
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(81H + short(param2), 28H * ORD(cmd.opcode = CODE.opDECC) + reg1 MOD 8);
|
||
|
OutIntByte(param2)
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opDROP:
|
||
|
UnOp(reg1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVE, CODE.opSAVE64:
|
||
|
BinOp(reg2, reg1);
|
||
|
movmr(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVE8:
|
||
|
BinOp(reg2, reg1);
|
||
|
movmr8(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVE16:
|
||
|
BinOp(reg2, reg1);
|
||
|
movmr16(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVE32:
|
||
|
BinOp(reg2, reg1);
|
||
|
movmr32(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opMIN:
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprr(reg1, reg2);
|
||
|
OutByte2(7EH, 3); // jle L
|
||
|
mov(reg1, reg2);
|
||
|
// L:
|
||
|
drop
|
||
|
|
||
|
|CODE.opMAX:
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprr(reg1, reg2);
|
||
|
OutByte2(7DH, 3); // jge L
|
||
|
mov(reg1, reg2);
|
||
|
// L:
|
||
|
drop
|
||
|
|
||
|
|CODE.opMINC:
|
||
|
UnOp(reg1);
|
||
|
cmprc(reg1, param2);
|
||
|
label := NewLabel();
|
||
|
jcc(jle, label);
|
||
|
movrc(reg1, param2);
|
||
|
X86.SetLabel(label)
|
||
|
|
||
|
|CODE.opMAXC:
|
||
|
UnOp(reg1);
|
||
|
cmprc(reg1, param2);
|
||
|
label := NewLabel();
|
||
|
jcc(jge, label);
|
||
|
movrc(reg1, param2);
|
||
|
X86.SetLabel(label)
|
||
|
|
||
|
|CODE.opSBOOL:
|
||
|
BinOp(reg2, reg1);
|
||
|
test(reg2);
|
||
|
setcc(setne, reg2);
|
||
|
movmr8(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSBOOLC:
|
||
|
UnOp(reg1);
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0));
|
||
|
drop
|
||
|
|
||
|
|CODE.opODD:
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opUMINUS:
|
||
|
UnOp(reg1);
|
||
|
neg(reg1)
|
||
|
|
||
|
|CODE.opADD:
|
||
|
BinOp(reg1, reg2);
|
||
|
add(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opSUB:
|
||
|
BinOp(reg1, reg2);
|
||
|
sub(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opSUBR, CODE.opSUBL:
|
||
|
UnOp(reg1);
|
||
|
n := param2;
|
||
|
IF n = 1 THEN
|
||
|
decr(reg1)
|
||
|
ELSIF n = -1 THEN
|
||
|
incr(reg1)
|
||
|
ELSIF n # 0 THEN
|
||
|
subrc(reg1, n)
|
||
|
END;
|
||
|
IF cmd.opcode = CODE.opSUBL THEN
|
||
|
neg(reg1)
|
||
|
END
|
||
|
|
||
|
|CODE.opADDL, CODE.opADDR:
|
||
|
IF param2 # 0 THEN
|
||
|
UnOp(reg1);
|
||
|
IF param2 = 1 THEN
|
||
|
incr(reg1)
|
||
|
ELSIF param2 = -1 THEN
|
||
|
decr(reg1)
|
||
|
ELSE
|
||
|
addrc(reg1, param2)
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opDIV:
|
||
|
PushAll(2);
|
||
|
CallRTL(CODE._div);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opDIVR:
|
||
|
a := param2;
|
||
|
IF a > 1 THEN
|
||
|
n := X86.log2(a)
|
||
|
ELSIF a < -1 THEN
|
||
|
n := X86.log2(-a)
|
||
|
ELSE
|
||
|
n := -1
|
||
|
END;
|
||
|
|
||
|
IF a = 1 THEN
|
||
|
|
||
|
ELSIF a = -1 THEN
|
||
|
UnOp(reg1);
|
||
|
neg(reg1)
|
||
|
ELSE
|
||
|
IF n > 0 THEN
|
||
|
UnOp(reg1);
|
||
|
|
||
|
IF a < 0 THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
mov(reg2, reg1);
|
||
|
shiftrc(sar, reg1, n);
|
||
|
sub(reg1, reg2);
|
||
|
drop
|
||
|
ELSE
|
||
|
shiftrc(sar, reg1, n)
|
||
|
END
|
||
|
|
||
|
ELSE
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._div);
|
||
|
GetRegA
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opDIVL:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._div2);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opMOD:
|
||
|
PushAll(2);
|
||
|
CallRTL(CODE._mod);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opMODR:
|
||
|
a := param2;
|
||
|
IF a > 1 THEN
|
||
|
n := X86.log2(a)
|
||
|
ELSIF a < -1 THEN
|
||
|
n := X86.log2(-a)
|
||
|
ELSE
|
||
|
n := -1
|
||
|
END;
|
||
|
|
||
|
IF ABS(a) = 1 THEN
|
||
|
UnOp(reg1);
|
||
|
xor(reg1, reg1)
|
||
|
ELSE
|
||
|
IF n > 0 THEN
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, ABS(a) - 1);
|
||
|
|
||
|
IF a < 0 THEN
|
||
|
test(reg1);
|
||
|
label := NewLabel();
|
||
|
jcc(je, label);
|
||
|
addrc(reg1, a);
|
||
|
X86.SetLabel(label)
|
||
|
END
|
||
|
|
||
|
ELSE
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._mod);
|
||
|
GetRegA
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opMODL:
|
||
|
PushAll(1);
|
||
|
pushc(param2);
|
||
|
CallRTL(CODE._mod2);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opMUL:
|
||
|
BinOp(reg1, reg2);
|
||
|
oprr2(0FH, 0AFH, reg2, reg1); // imul reg1, reg2
|
||
|
drop
|
||
|
|
||
|
|CODE.opMULC:
|
||
|
UnOp(reg1);
|
||
|
|
||
|
a := param2;
|
||
|
IF a > 1 THEN
|
||
|
n := X86.log2(a)
|
||
|
ELSIF a < -1 THEN
|
||
|
n := X86.log2(-a)
|
||
|
ELSE
|
||
|
n := -1
|
||
|
END;
|
||
|
|
||
|
IF a = 1 THEN
|
||
|
|
||
|
ELSIF a = -1 THEN
|
||
|
neg(reg1)
|
||
|
ELSIF a = 0 THEN
|
||
|
xor(reg1, reg1)
|
||
|
ELSE
|
||
|
IF n > 0 THEN
|
||
|
IF a < 0 THEN
|
||
|
neg(reg1)
|
||
|
END;
|
||
|
shiftrc(shl, reg1, n)
|
||
|
ELSE
|
||
|
// imul reg1, a
|
||
|
Rex(reg1, reg1);
|
||
|
OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
|
||
|
OutIntByte(a)
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opADDS:
|
||
|
BinOp(reg1, reg2);
|
||
|
or(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opSUBS:
|
||
|
BinOp(reg1, reg2);
|
||
|
not(reg2);
|
||
|
and(reg1, reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opNOP:
|
||
|
|
||
|
|CODE.opSWITCH:
|
||
|
UnOp(reg1);
|
||
|
IF param2 = 0 THEN
|
||
|
reg2 := rax
|
||
|
ELSE
|
||
|
reg2 := r10
|
||
|
END;
|
||
|
IF reg1 # reg2 THEN
|
||
|
ASSERT(REG.GetReg(R, reg2));
|
||
|
ASSERT(REG.Exchange(R, reg1, reg2));
|
||
|
drop
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opENDSW:
|
||
|
|
||
|
|CODE.opCASEL:
|
||
|
cmprc(rax, param1);
|
||
|
jcc(jl, param2)
|
||
|
|
||
|
|CODE.opCASER:
|
||
|
cmprc(rax, param1);
|
||
|
jcc(jg, param2)
|
||
|
|
||
|
|CODE.opCASELR:
|
||
|
cmprc(rax, param1);
|
||
|
jcc(jl, param2);
|
||
|
jcc(jg, cmd.param3)
|
||
|
|
||
|
|CODE.opASR, CODE.opROR, CODE.opLSL, CODE.opLSR:
|
||
|
BinOp(reg1, reg2);
|
||
|
xchg(reg2, rcx);
|
||
|
Rex(reg1, 0);
|
||
|
OutByte(0D3H);
|
||
|
X86.shift(cmd.opcode, reg1 MOD 8); // shift reg1, cl
|
||
|
xchg(reg2, rcx);
|
||
|
drop
|
||
|
|
||
|
|CODE.opASR1, CODE.opROR1, CODE.opLSL1, CODE.opLSR1:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrc(reg1, param2);
|
||
|
BinOp(reg1, reg2);
|
||
|
xchg(reg1, rcx);
|
||
|
Rex(reg2, 0);
|
||
|
OutByte(0D3H);
|
||
|
X86.shift(cmd.opcode, reg2 MOD 8); // shift reg2, cl
|
||
|
xchg(reg1, rcx);
|
||
|
drop;
|
||
|
drop;
|
||
|
ASSERT(REG.GetReg(R, reg2))
|
||
|
|
||
|
|CODE.opASR2, CODE.opROR2, CODE.opLSL2, CODE.opLSR2:
|
||
|
UnOp(reg1);
|
||
|
shiftrc(cmd.opcode, reg1, ORD(BITS(param2) * {0..5}))
|
||
|
|
||
|
|CODE.opGET:
|
||
|
BinOp(reg1, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
_movrm(reg1, reg1, 0, param2 * 8, FALSE);
|
||
|
_movrm(reg1, reg2, 0, param2 * 8, TRUE)
|
||
|
|
||
|
|CODE.opCHKBYTE:
|
||
|
BinOp(reg1, reg2);
|
||
|
cmprc(reg1, 256);
|
||
|
jcc(jb, param1)
|
||
|
|
||
|
|CODE.opCHKIDX:
|
||
|
UnOp(reg1);
|
||
|
cmprc(reg1, param2);
|
||
|
jcc(jb, param1)
|
||
|
|
||
|
|CODE.opCHKIDX2:
|
||
|
BinOp(reg1, reg2);
|
||
|
IF param2 # -1 THEN
|
||
|
cmprr(reg2, reg1);
|
||
|
mov(reg1, reg2);
|
||
|
drop;
|
||
|
jcc(jb, param1)
|
||
|
ELSE
|
||
|
INCL(R.regs, reg1);
|
||
|
DEC(R.top);
|
||
|
R.stk[R.top] := reg2
|
||
|
END
|
||
|
|
||
|
|CODE.opLENGTH:
|
||
|
PushAll(2);
|
||
|
CallRTL(CODE._length);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opLENGTHW:
|
||
|
PushAll(2);
|
||
|
CallRTL(CODE._lengthw);
|
||
|
GetRegA
|
||
|
|
||
|
|CODE.opLEN:
|
||
|
n := param2;
|
||
|
UnOp(reg1);
|
||
|
drop;
|
||
|
EXCL(R.regs, reg1);
|
||
|
|
||
|
WHILE n > 0 DO
|
||
|
UnOp(reg2);
|
||
|
drop;
|
||
|
DEC(n)
|
||
|
END;
|
||
|
|
||
|
INCL(R.regs, reg1);
|
||
|
ASSERT(REG.GetReg(R, reg1))
|
||
|
|
||
|
|CODE.opCHR:
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, 255)
|
||
|
|
||
|
|CODE.opWCHR:
|
||
|
UnOp(reg1);
|
||
|
andrc(reg1, 65535)
|
||
|
|
||
|
|CODE.opEQP, CODE.opNEP, CODE.opEQIP, CODE.opNEIP:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
|
||
|
CASE cmd.opcode OF
|
||
|
|CODE.opEQP, CODE.opNEP:
|
||
|
lea(reg2, param1, sCODE)
|
||
|
|
||
|
|CODE.opEQIP, CODE.opNEIP:
|
||
|
lea(reg2, param1, sIMP);
|
||
|
movrm(reg2, reg2, 0)
|
||
|
END;
|
||
|
|
||
|
cmprr(reg1, reg2);
|
||
|
drop;
|
||
|
drop;
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
|
||
|
CASE cmd.opcode OF
|
||
|
|CODE.opEQP, CODE.opEQIP: setcc(sete, reg1)
|
||
|
|CODE.opNEP, CODE.opNEIP: setcc(setne, reg1)
|
||
|
END;
|
||
|
|
||
|
andrc(reg1, 1)
|
||
|
|
||
|
|CODE.opINC1B, CODE.opDEC1B:
|
||
|
UnOp(reg1);
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte2(0FEH, 8 * ORD(cmd.opcode = CODE.opDEC1B) + reg1 MOD 8); // inc/dec byte[reg1]
|
||
|
drop
|
||
|
|
||
|
|CODE.opINCCB, CODE.opDECCB:
|
||
|
UnOp(reg1);
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte3(80H, 28H * ORD(cmd.opcode = CODE.opDECCB) + reg1 MOD 8, param2 MOD 256); // add/sub byte[reg1], param2 MOD 256
|
||
|
drop
|
||
|
|
||
|
|CODE.opINCB, CODE.opDECB:
|
||
|
BinOp(reg1, reg2);
|
||
|
IF (reg1 >= 8) OR (reg2 >= 8) THEN
|
||
|
OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
|
||
|
END;
|
||
|
OutByte2(28H * ORD(cmd.opcode = CODE.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); // add/sub byte[reg2], reg1_8
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSAVEIP:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
lea(reg2, param2, sIMP);
|
||
|
movrm(reg2, reg2, 0);
|
||
|
push(reg2);
|
||
|
drop;
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(41H)
|
||
|
END;
|
||
|
OutByte2(8FH, reg1 MOD 8); // pop qword[reg1]
|
||
|
drop
|
||
|
|
||
|
|CODE.opCLEANUP:
|
||
|
n := param2 * 8;
|
||
|
IF n # 0 THEN
|
||
|
addrc(rsp, n)
|
||
|
END
|
||
|
|
||
|
|CODE.opPOPSP:
|
||
|
pop(rsp)
|
||
|
|
||
|
|CODE.opLOADF:
|
||
|
UnOp(reg1);
|
||
|
INC(xmm);
|
||
|
movsdrm(xmm, reg1, 0);
|
||
|
drop
|
||
|
|
||
|
|CODE.opPUSHF:
|
||
|
subrc(rsp, 8);
|
||
|
movsdmr(rsp, 0, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opCONSTF:
|
||
|
float := cmd.float;
|
||
|
INC(xmm);
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, Numbers_Offs + Numbers_Count * 8, sDATA);
|
||
|
movsdrm(xmm, reg1, 0);
|
||
|
drop;
|
||
|
NewNumber(UTILS.splitf(float, a, b))
|
||
|
|
||
|
|CODE.opSAVEF:
|
||
|
UnOp(reg1);
|
||
|
movsdmr(reg1, 0, xmm);
|
||
|
DEC(xmm);
|
||
|
drop
|
||
|
|
||
|
|CODE.opADDF, CODE.opADDFI:
|
||
|
opxx(58H, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opSUBF:
|
||
|
opxx(5CH, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opSUBFI:
|
||
|
opxx(5CH, xmm, xmm - 1);
|
||
|
opxx(10H, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opMULF:
|
||
|
opxx(59H, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opDIVF:
|
||
|
opxx(5EH, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opDIVFI:
|
||
|
opxx(5EH, xmm, xmm - 1);
|
||
|
opxx(10H, xmm - 1, xmm);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opUMINF:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, Numbers_Offs, sDATA);
|
||
|
OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // xorpd xmm, xmmword[reg1]
|
||
|
OutByte2(57H, reg1 MOD 8 + (xmm MOD 8) * 8);
|
||
|
drop
|
||
|
|
||
|
|CODE.opFABS:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, Numbers_Offs + 16, sDATA);
|
||
|
OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // andpd xmm, xmmword[reg1]
|
||
|
OutByte2(54H, reg1 MOD 8 + (xmm MOD 8) * 8);
|
||
|
drop
|
||
|
|
||
|
|CODE.opFLT:
|
||
|
UnOp(reg1);
|
||
|
INC(xmm);
|
||
|
OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); // cvtsi2sd xmm, reg1
|
||
|
OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
|
||
|
drop
|
||
|
|
||
|
|CODE.opFLOOR:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
subrc(rsp, 8);
|
||
|
OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); // stmxcsr dword[rsp+4];
|
||
|
OutByte2(00FH, 0AEH); OutByte2(01CH, 024H); // stmxcsr dword[rsp];
|
||
|
OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); // and dword[rsp],11111111111111111001111111111111b;
|
||
|
OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); // or dword[rsp],00000000000000000010000000000000b;
|
||
|
OutByte2(00FH, 0AEH); OutByte2(014H, 024H); // ldmxcsr dword[rsp];
|
||
|
OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); // cvtsd2si reg1, xmm
|
||
|
OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
|
||
|
OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); // ldmxcsr dword[rsp+4];
|
||
|
addrc(rsp, 8);
|
||
|
DEC(xmm)
|
||
|
|
||
|
|CODE.opEQF .. CODE.opGEFI:
|
||
|
fcmp(cmd.opcode, xmm);
|
||
|
DEC(xmm, 2)
|
||
|
|
||
|
|CODE.opINF:
|
||
|
INC(xmm);
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
lea(reg1, Numbers_Offs + 32, sDATA);
|
||
|
movsdrm(xmm, reg1, 0);
|
||
|
drop
|
||
|
|
||
|
|CODE.opPACK, CODE.opPACKC:
|
||
|
IF cmd.opcode = CODE.opPACK THEN
|
||
|
BinOp(reg1, reg2)
|
||
|
ELSE
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrc(reg2, param2)
|
||
|
END;
|
||
|
push(reg1);
|
||
|
movrm(reg1, reg1, 0);
|
||
|
shiftrc(shl, reg1, 1);
|
||
|
shiftrc(shr, reg1, 53);
|
||
|
add(reg1, reg2);
|
||
|
andrc(reg1, ORD({0..10}));
|
||
|
shiftrc(shl, reg1, 52);
|
||
|
movrm(reg2, rsp, 0);
|
||
|
movrm(reg2, reg2, 0);
|
||
|
|
||
|
push(reg1);
|
||
|
lea(reg1, Numbers_Offs + 40, sDATA); // {0..51, 63}
|
||
|
movrm(reg1, reg1, 0);
|
||
|
and(reg2, reg1);
|
||
|
pop(reg1);
|
||
|
|
||
|
or(reg2, reg1);
|
||
|
pop(reg1);
|
||
|
movmr(reg1, 0, reg2);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opUNPK, CODE.opLADR_UNPK:
|
||
|
|
||
|
IF cmd.opcode = CODE.opLADR_UNPK THEN
|
||
|
n := param2 * 8;
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
regVar := reg2 # -1;
|
||
|
IF ~regVar THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
Rex(0, reg2);
|
||
|
OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8); // lea reg2, qword[rbp+n]
|
||
|
OutIntByte(n)
|
||
|
END
|
||
|
ELSE
|
||
|
BinOp(reg1, reg2);
|
||
|
regVar := FALSE
|
||
|
END;
|
||
|
|
||
|
push(reg1);
|
||
|
movrm(reg1, reg1, 0);
|
||
|
shiftrc(shl, reg1, 1);
|
||
|
shiftrc(shr, reg1, 53);
|
||
|
subrc(reg1, 1023);
|
||
|
|
||
|
IF regVar THEN
|
||
|
mov(reg2, reg1);
|
||
|
reg2 := REG.GetAnyReg(R)
|
||
|
ELSE
|
||
|
movmr(reg2, 0, reg1)
|
||
|
END;
|
||
|
|
||
|
pop(reg2);
|
||
|
movrm(reg1, reg2, 0);
|
||
|
|
||
|
push(reg2);
|
||
|
lea(reg2, Numbers_Offs + 48, sDATA); // {52..61}
|
||
|
movrm(reg2, reg2, 0);
|
||
|
or(reg1, reg2);
|
||
|
pop(reg2);
|
||
|
|
||
|
Rex(reg1, 0);
|
||
|
OutByte2(0FH, 0BAH);
|
||
|
OutByte2(0F0H + reg1 MOD 8, 3EH); // btr reg1, 62
|
||
|
movmr(reg2, 0, reg1);
|
||
|
drop;
|
||
|
drop
|
||
|
|
||
|
|CODE.opSADR_PARAM:
|
||
|
pushDA(stroffs + param2)
|
||
|
|
||
|
|CODE.opVADR_PARAM:
|
||
|
pushm(rbp, param2 * 8)
|
||
|
|
||
|
|CODE.opLOAD64_PARAM:
|
||
|
UnOp(reg1);
|
||
|
pushm(reg1, 0);
|
||
|
drop
|
||
|
|
||
|
|CODE.opLLOAD64_PARAM:
|
||
|
reg1 := REG.GetVarReg(R, param2);
|
||
|
IF reg1 # -1 THEN
|
||
|
push(reg1)
|
||
|
ELSE
|
||
|
pushm(rbp, param2 * 8)
|
||
|
END
|
||
|
|
||
|
|CODE.opGLOAD64_PARAM:
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
lea(reg2, param2, sBSS);
|
||
|
movrm(reg2, reg2, 0);
|
||
|
push(reg2);
|
||
|
drop
|
||
|
|
||
|
|CODE.opCONST_PARAM:
|
||
|
pushc(param2)
|
||
|
|
||
|
|CODE.opGLOAD32_PARAM:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
xor(reg1, reg1);
|
||
|
lea(reg1, param2, sBSS);
|
||
|
movrm32(reg1, reg1, 0);
|
||
|
push(reg1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opLOAD32_PARAM:
|
||
|
UnOp(reg1);
|
||
|
movrm32(reg1, reg1, 0);
|
||
|
shiftrc(shl, reg1, 32);
|
||
|
shiftrc(shr, reg1, 32);
|
||
|
push(reg1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opLLOAD32_PARAM:
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
xor(reg1, reg1);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
mov(reg1, reg2)
|
||
|
ELSE
|
||
|
movrm32(reg1, rbp, param2 * 8)
|
||
|
END;
|
||
|
push(reg1);
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR_SAVEC:
|
||
|
n := param1 * 8;
|
||
|
reg1 := REG.GetVarReg(R, param1);
|
||
|
IF reg1 # -1 THEN
|
||
|
movrc(reg1, param2)
|
||
|
ELSE
|
||
|
IF isLong(param2) THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrc(reg2, param2);
|
||
|
movmr(rbp, n, reg2);
|
||
|
drop
|
||
|
ELSE
|
||
|
OutByte3(48H, 0C7H, 45H + long(n)); // mov qword[rbp+n],param2
|
||
|
OutIntByte(n);
|
||
|
OutInt(param2)
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opGADR_SAVEC:
|
||
|
IF isLong(param2) THEN
|
||
|
reg1 := REG.GetAnyReg(R);
|
||
|
movrc(reg1, param2);
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
lea(reg2, param1, sBSS);
|
||
|
movmr(reg2, 0, reg1);
|
||
|
drop;
|
||
|
drop
|
||
|
ELSE
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
lea(reg2, param1, sBSS);
|
||
|
Rex(reg2, 0);
|
||
|
OutByte2(0C7H, reg2 MOD 8); // mov qword[reg2], param2
|
||
|
OutInt(param2);
|
||
|
drop
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_SAVE:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
mov(reg2, reg1)
|
||
|
ELSE
|
||
|
movmr(rbp, param2 * 8, reg1)
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR_INC1:
|
||
|
reg1 := REG.GetVarReg(R, param2);
|
||
|
IF reg1 # -1 THEN
|
||
|
incr(reg1)
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
OutByte3(48H, 0FFH, 45H + long(n)); // inc qword[rbp+n]
|
||
|
OutIntByte(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_DEC1:
|
||
|
reg1 := REG.GetVarReg(R, param2);
|
||
|
IF reg1 # -1 THEN
|
||
|
decr(reg1)
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
OutByte3(48H, 0FFH, 4DH + long(n)); // dec qword[rbp+n]
|
||
|
OutIntByte(n)
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_INCC, CODE.opLADR_DECC:
|
||
|
reg1 := REG.GetVarReg(R, param1);
|
||
|
IF isLong(param2) THEN
|
||
|
reg2 := REG.GetAnyReg(R);
|
||
|
movrc(reg2, param2);
|
||
|
IF reg1 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DECC THEN
|
||
|
sub(reg1, reg2)
|
||
|
ELSE
|
||
|
add(reg1, reg2)
|
||
|
END
|
||
|
ELSE
|
||
|
n := param1 * 8;
|
||
|
Rex(0, reg2);
|
||
|
OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DECC), 45H + long(n) + (reg2 MOD 8) * 8);
|
||
|
OutIntByte(n) // add/sub qword[rbp+n],reg2
|
||
|
END;
|
||
|
drop
|
||
|
ELSE
|
||
|
IF reg1 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DECC THEN
|
||
|
subrc(reg1, param2)
|
||
|
ELSE
|
||
|
addrc(reg1, param2)
|
||
|
END
|
||
|
ELSE
|
||
|
n := param1 * 8;
|
||
|
OutByte3(48H, 81H + short(param2), 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECC));
|
||
|
OutIntByte(n);
|
||
|
OutIntByte(param2) // add/sub qword[rbp+n],param2
|
||
|
END
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_INC1B, CODE.opLADR_DEC1B:
|
||
|
reg1 := REG.GetVarReg(R, param2);
|
||
|
IF reg1 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DEC1B THEN
|
||
|
decr(reg1)
|
||
|
ELSE
|
||
|
incr(reg1)
|
||
|
END;
|
||
|
andrc(reg1, 255)
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
OutByte2(0FEH, 45H + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_DEC1B));
|
||
|
OutIntByte(n) // inc/dec byte[rbp+n]
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_INCCB, CODE.opLADR_DECCB:
|
||
|
reg1 := REG.GetVarReg(R, param1);
|
||
|
param2 := param2 MOD 256;
|
||
|
IF reg1 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DECCB THEN
|
||
|
subrc(reg1, param2)
|
||
|
ELSE
|
||
|
addrc(reg1, param2)
|
||
|
END;
|
||
|
andrc(reg1, 255)
|
||
|
ELSE
|
||
|
n := param1 * 8;
|
||
|
OutByte2(80H, 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECCB));
|
||
|
OutIntByte(n);
|
||
|
OutByte(param2) // add/sub byte[rbp+n],param2
|
||
|
END
|
||
|
|
||
|
|CODE.opLADR_INC, CODE.opLADR_DEC:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DEC THEN
|
||
|
sub(reg2, reg1)
|
||
|
ELSE
|
||
|
add(reg2, reg1)
|
||
|
END
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
Rex(0, reg1);
|
||
|
OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
|
||
|
OutIntByte(n) // add/sub qword[rbp+n],reg1
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR_INCB, CODE.opLADR_DECB:
|
||
|
UnOp(reg1);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
IF cmd.opcode = CODE.opLADR_DECB THEN
|
||
|
sub(reg2, reg1)
|
||
|
ELSE
|
||
|
add(reg2, reg1)
|
||
|
END;
|
||
|
andrc(reg2, 255)
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
IF reg1 >= 8 THEN
|
||
|
OutByte(44H)
|
||
|
END;
|
||
|
OutByte2(28H * ORD(cmd.opcode = CODE.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
|
||
|
OutIntByte(n) // add/sub byte[rbp+n], reg1_8
|
||
|
END;
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR_INCL, CODE.opLADR_EXCL:
|
||
|
UnOp(reg1);
|
||
|
cmprc(reg1, 64);
|
||
|
reg2 := REG.GetVarReg(R, param2);
|
||
|
IF reg2 # -1 THEN
|
||
|
OutByte2(73H, 4); // jnb L
|
||
|
oprr2(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), reg2, reg1) // bts/btr reg2, reg1
|
||
|
ELSE
|
||
|
n := param2 * 8;
|
||
|
OutByte2(73H, 5 + 3 * ORD(~isByte(n))); // jnb L
|
||
|
Rex(0, reg1);
|
||
|
OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
|
||
|
OutIntByte(n) // bts/btr qword[rbp+n], reg1
|
||
|
END;
|
||
|
// L:
|
||
|
drop
|
||
|
|
||
|
|CODE.opLADR_INCLC, CODE.opLADR_EXCLC:
|
||
|
reg1 := REG.GetVarReg(R, param1);
|
||
|
IF reg1 # -1 THEN
|
||
|
Rex(reg1, 0);
|
||
|
OutByte3(0FH, 0BAH, 0E8H); // bts/btr reg1, param2
|
||
|
OutByte2(reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC), param2)
|
||
|
ELSE
|
||
|
n := param1 * 8;
|
||
|
OutByte3(48H, 0FH, 0BAH); // bts/btr qword[rbp+n], param2
|
||
|
OutByte(6DH + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC));
|
||
|
OutIntByte(n);
|
||
|
OutByte(param2)
|
||
|
END
|
||
|
|
||
|
|CODE.opLOOP, CODE.opENDLOOP:
|
||
|
|
||
|
END;
|
||
|
|
||
|
cmd := cmd.next(COMMAND)
|
||
|
END;
|
||
|
|
||
|
ASSERT(R.pushed = 0);
|
||
|
ASSERT(R.top = -1);
|
||
|
ASSERT(xmm = -1)
|
||
|
END translate;
|
||
|
|
||
|
|
||
|
PROCEDURE prolog (code: CODE.CODES; modname: ARRAY OF CHAR; target, stack_size: INTEGER);
|
||
|
VAR
|
||
|
ModName_Offs, entry: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
ModName_Offs := CHL.Length(code.types) * 8 + CHL.Length(code.data);
|
||
|
Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
|
||
|
ASSERT(MACHINE.Align(Numbers_Offs, 16));
|
||
|
|
||
|
entry := NewLabel();
|
||
|
X86.SetLabel(entry);
|
||
|
|
||
|
IF target = mConst.Target_iDLL64 THEN
|
||
|
dllret := NewLabel();
|
||
|
push(r8);
|
||
|
push(rdx);
|
||
|
push(rcx);
|
||
|
CallRTL(CODE._dllentry);
|
||
|
test(rax);
|
||
|
jcc(je, dllret)
|
||
|
END;
|
||
|
|
||
|
push(rsp);
|
||
|
lea(rax, entry, sCODE);
|
||
|
push(rax);
|
||
|
pushDA(0); //TYPES
|
||
|
pushc(CHL.Length(code.types));
|
||
|
pushDA(ModName_Offs); //MODNAME
|
||
|
CallRTL(CODE._init)
|
||
|
END prolog;
|
||
|
|
||
|
|
||
|
PROCEDURE epilog (code: CODE.CODES; modname: ARRAY OF CHAR; target: INTEGER);
|
||
|
VAR
|
||
|
i, n: INTEGER;
|
||
|
number: Number;
|
||
|
exp: CODE.EXPORT_PROC;
|
||
|
|
||
|
|
||
|
PROCEDURE import (imp: LISTS.LIST);
|
||
|
VAR
|
||
|
lib: CODE.IMPORT_LIB;
|
||
|
proc: CODE.IMPORT_PROC;
|
||
|
|
||
|
BEGIN
|
||
|
|
||
|
lib := imp.first(CODE.IMPORT_LIB);
|
||
|
WHILE lib # NIL DO
|
||
|
BIN.Import(prog, lib.name, 0);
|
||
|
proc := lib.procs.first(CODE.IMPORT_PROC);
|
||
|
WHILE proc # NIL DO
|
||
|
BIN.Import(prog, proc.name, proc.label);
|
||
|
proc := proc.next(CODE.IMPORT_PROC)
|
||
|
END;
|
||
|
lib := lib.next(CODE.IMPORT_LIB)
|
||
|
END
|
||
|
|
||
|
END import;
|
||
|
|
||
|
|
||
|
BEGIN
|
||
|
IF target = mConst.Target_iDLL64 THEN
|
||
|
X86.SetLabel(dllret);
|
||
|
OutByte(0C3H) // ret
|
||
|
ELSE
|
||
|
pushc(0);
|
||
|
CallRTL(CODE._exit)
|
||
|
END;
|
||
|
|
||
|
X86.fixup;
|
||
|
|
||
|
i := 0;
|
||
|
WHILE i < CHL.Length(code.types) DO
|
||
|
BIN.PutData64LE(prog, CHL.GetInt(code.types, i));
|
||
|
INC(i)
|
||
|
END;
|
||
|
|
||
|
i := 0;
|
||
|
WHILE i < CHL.Length(code.data) DO
|
||
|
BIN.PutData(prog, CHL.GetByte(code.data, i));
|
||
|
INC(i)
|
||
|
END;
|
||
|
|
||
|
BIN.PutDataStr(prog, modname);
|
||
|
BIN.PutData(prog, 0);
|
||
|
n := CHL.Length(prog.data);
|
||
|
ASSERT(MACHINE.Align(n, 16));
|
||
|
i := n - CHL.Length(prog.data);
|
||
|
WHILE i > 0 DO
|
||
|
BIN.PutData(prog, 0);
|
||
|
DEC(i)
|
||
|
END;
|
||
|
number := Numbers.first(Number);
|
||
|
FOR i := 0 TO Numbers_Count - 1 DO
|
||
|
BIN.PutData64LE(prog, number.value);
|
||
|
number := number.next(Number)
|
||
|
END;
|
||
|
|
||
|
exp := code.export.first(CODE.EXPORT_PROC);
|
||
|
WHILE exp # NIL DO
|
||
|
BIN.Export(prog, exp.name, exp.label);
|
||
|
exp := exp.next(CODE.EXPORT_PROC)
|
||
|
END;
|
||
|
|
||
|
import(code.import)
|
||
|
END epilog;
|
||
|
|
||
|
|
||
|
PROCEDURE rload (reg, offs, size: INTEGER);
|
||
|
BEGIN
|
||
|
offs := offs * 8;
|
||
|
CASE size OF
|
||
|
|1: movzx(reg, rbp, offs, FALSE)
|
||
|
|2: movzx(reg, rbp, offs, TRUE)
|
||
|
|4: xor(reg, reg); movrm32(reg, rbp, offs)
|
||
|
|8: movrm(reg, rbp, offs)
|
||
|
END
|
||
|
END rload;
|
||
|
|
||
|
|
||
|
PROCEDURE rsave (reg, offs, size: INTEGER);
|
||
|
BEGIN
|
||
|
offs := offs * 8;
|
||
|
CASE size OF
|
||
|
|1: movmr8(rbp, offs, reg)
|
||
|
|2: movmr16(rbp, offs, reg)
|
||
|
|4: movmr32(rbp, offs, reg)
|
||
|
|8: movmr(rbp, offs, reg)
|
||
|
END
|
||
|
END rsave;
|
||
|
|
||
|
|
||
|
PROCEDURE CodeGen* (code: CODE.CODES; outname: ARRAY OF CHAR; target, stack, base: INTEGER);
|
||
|
VAR
|
||
|
path, modname, ext: PATHS.PATH;
|
||
|
n: INTEGER;
|
||
|
|
||
|
BEGIN
|
||
|
Win64RegPar[0] := rcx;
|
||
|
Win64RegPar[1] := rdx;
|
||
|
Win64RegPar[2] := r8;
|
||
|
Win64RegPar[3] := r9;
|
||
|
|
||
|
SystemVRegPar[0] := rdi;
|
||
|
SystemVRegPar[1] := rsi;
|
||
|
SystemVRegPar[2] := rdx;
|
||
|
SystemVRegPar[3] := rcx;
|
||
|
SystemVRegPar[4] := r8;
|
||
|
SystemVRegPar[5] := r9;
|
||
|
|
||
|
PATHS.split(outname, path, modname, ext);
|
||
|
S.append(modname, ext);
|
||
|
|
||
|
R := REG.Create(push, pop, mov, xchg, rload, rsave, {rax, r10, r11}, {rcx, rdx, r8, r9});
|
||
|
|
||
|
n := code.dmin - CHL.Length(code.data);
|
||
|
IF n > 0 THEN
|
||
|
INC(code.bss, n)
|
||
|
END;
|
||
|
code.bss := MAX(code.bss, 8);
|
||
|
|
||
|
Numbers := LISTS.create(NIL);
|
||
|
Numbers_Count := 0;
|
||
|
NewNumber(ROR(1, 1)); (* 8000000000000000H *)
|
||
|
NewNumber(0);
|
||
|
NewNumber(ROR(-2, 1)); (* 7FFFFFFFFFFFFFFFH *)
|
||
|
NewNumber(-1);
|
||
|
NewNumber(ROR(7FFH, 12)); (* +Infinity *)
|
||
|
NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1)))); (* {0..51, 63} *)
|
||
|
NewNumber(LSR(ASR(ROR(1, 1), 9), 2)); (* {52..61} *)
|
||
|
|
||
|
prog := BIN.create(code.lcount);
|
||
|
BIN.SetParams(prog, code.bss, stack, WCHR(1), WCHR(0));
|
||
|
|
||
|
X86.SetProgram(prog);
|
||
|
|
||
|
prolog(code, modname, target, stack);
|
||
|
translate(code.commands, CHL.Length(code.types) * 8);
|
||
|
epilog(code, modname, target);
|
||
|
|
||
|
BIN.fixup(prog);
|
||
|
IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
|
||
|
PE32.write(prog, outname, base, target = mConst.Target_iConsole64, target = mConst.Target_iDLL64, TRUE)
|
||
|
ELSIF target = mConst.Target_iELF64 THEN
|
||
|
ELF.write(prog, outname, TRUE)
|
||
|
END
|
||
|
END CodeGen;
|
||
|
|
||
|
|
||
|
END AMD64.
|