kolibrios/programs/develop/oberon07/Source/AMD64.ob07

2818 lines
71 KiB
Plaintext
Raw Normal View History

(*
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;
param2: 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,
CODE.opSAVES, CODE.opRSET, CODE.opRSETR,
CODE.opRSETL, CODE.opRSET1,
CODE.opEQS .. CODE.opGES,
CODE.opEQS2 .. CODE.opGES2,
CODE.opEQSW .. CODE.opGESW,
CODE.opEQSW2 .. CODE.opGESW2,
CODE.opCOPY, CODE.opMOVE, CODE.opCOPYA,
CODE.opCOPYS, CODE.opCOPYS2, CODE.opROT,
CODE.opNEW, CODE.opDISP, CODE.opISREC,
CODE.opIS, CODE.opTYPEGR, CODE.opTYPEGP,
CODE.opCASET, CODE.opDIV,
CODE.opDIVL, CODE.opMOD,
CODE.opMODL, CODE.opLENGTH, CODE.opLENGTHW:
leaf := FALSE
|CODE.opDIVR, CODE.opMODR:
param2 := cur.param2;
IF param2 >= 1 THEN
param2 := X86.log2(param2)
ELSIF param2 <= -1 THEN
param2 := X86.log2(-param2)
ELSE
param2 := -1
END;
IF param2 < 0 THEN
leaf := FALSE
END
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.opACC:
IF (R.top # 0) OR (R.stk[0] # rax) THEN
PushAll(0);
GetRegA;
pop(rax);
DEC(R.pushed)
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.