Subversion Repositories Kolibri OS

Rev

Rev 7667 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018, 2019, Anton Krotov
  5.     All rights reserved.
  6. *)
  7.  
  8. MODULE AMD64;
  9.  
  10. IMPORT IL, BIN, WR := WRITER, CHL := CHUNKLISTS, LISTS, PATHS, PROG,
  11.        REG, C := CONSOLE, UTILS, mConst := CONSTANTS, S := STRINGS, PE32, ELF, X86;
  12.  
  13.  
  14. CONST
  15.  
  16.     rax = REG.R0;
  17.     r10 = REG.R10;
  18.     r11 = REG.R11;
  19.  
  20.     rcx = REG.R1;
  21.     rdx = REG.R2;
  22.     r8 = REG.R8;
  23.     r9 = REG.R9;
  24.  
  25.     rsp = 4;
  26.     rbp = 5;
  27.     rsi = 6;
  28.     rdi = 7;
  29.  
  30.     je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H;
  31.  
  32.     sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H;
  33.  
  34.     shl = IL.opLSL2; shr = IL.opLSR2; sar = IL.opASR2; ror = IL.opROR2;
  35.  
  36.     sCODE = BIN.PICCODE;
  37.     sDATA = BIN.PICDATA;
  38.     sBSS  = BIN.PICBSS;
  39.     sIMP  = BIN.PICIMP;
  40.  
  41.  
  42. TYPE
  43.  
  44.     COMMAND = IL.COMMAND;
  45.  
  46.     Number = POINTER TO RECORD (LISTS.ITEM) value: INTEGER END;
  47.  
  48.     OPRR = PROCEDURE (reg1, reg2: INTEGER);
  49.  
  50.  
  51. VAR
  52.  
  53.     R: REG.REGS;
  54.  
  55.     Numbers: LISTS.LIST;
  56.     Numbers_Count: INTEGER;
  57.     Numbers_Offs: INTEGER;
  58.  
  59.     prog: BIN.PROGRAM;
  60.  
  61.     tcount: INTEGER;
  62.  
  63.     dllret, sofinit: INTEGER;
  64.  
  65.     Win64RegPar: ARRAY 4 OF INTEGER;
  66.     SystemVRegPar: ARRAY 6 OF INTEGER;
  67.  
  68.  
  69. PROCEDURE OutByte (b: BYTE);
  70. BEGIN
  71.     X86.OutByte(b)
  72. END OutByte;
  73.  
  74.  
  75. PROCEDURE OutByte2 (a, b: BYTE);
  76. BEGIN
  77.     OutByte(a);
  78.     OutByte(b)
  79. END OutByte2;
  80.  
  81.  
  82. PROCEDURE OutByte3 (a, b, c: BYTE);
  83. BEGIN
  84.     OutByte(a);
  85.     OutByte(b);
  86.     OutByte(c)
  87. END OutByte3;
  88.  
  89.  
  90. PROCEDURE OutInt (n: INTEGER);
  91. BEGIN
  92.     OutByte(UTILS.Byte(n, 0));
  93.     OutByte(UTILS.Byte(n, 1));
  94.     OutByte(UTILS.Byte(n, 2));
  95.     OutByte(UTILS.Byte(n, 3))
  96. END OutInt;
  97.  
  98.  
  99. PROCEDURE isByte (n: INTEGER): BOOLEAN;
  100.     RETURN (-128 <= n) & (n <= 127)
  101. END isByte;
  102.  
  103.  
  104. PROCEDURE short (n: INTEGER): INTEGER;
  105.     RETURN 2 * ORD(isByte(n))
  106. END short;
  107.  
  108.  
  109. PROCEDURE long (n: INTEGER): INTEGER;
  110.     RETURN 40H * ORD(~isByte(n))
  111. END long;
  112.  
  113.  
  114. PROCEDURE OutIntByte (n: INTEGER);
  115. BEGIN
  116.     IF isByte(n) THEN
  117.         OutByte(UTILS.Byte(n, 0))
  118.     ELSE
  119.         OutInt(n)
  120.     END
  121. END OutIntByte;
  122.  
  123.  
  124. PROCEDURE isLong (n: INTEGER): BOOLEAN;
  125.     RETURN (n > UTILS.max32) OR (n < UTILS.min32)
  126. END isLong;
  127.  
  128.  
  129. PROCEDURE NewNumber (value: INTEGER);
  130. VAR
  131.     number: Number;
  132.  
  133. BEGIN
  134.     NEW(number);
  135.     number.value := value;
  136.     LISTS.push(Numbers, number);
  137.     INC(Numbers_Count)
  138. END NewNumber;
  139.  
  140.  
  141. PROCEDURE NewLabel (): INTEGER;
  142. BEGIN
  143.     BIN.NewLabel(prog)
  144.     RETURN IL.NewLabel()
  145. END NewLabel;
  146.  
  147.  
  148. PROCEDURE Rex (reg1, reg2: INTEGER);
  149. BEGIN
  150.     OutByte(48H + reg1 DIV 8 + 4 * (reg2 DIV 8))
  151. END Rex;
  152.  
  153.  
  154. PROCEDURE lea (reg, offset, section: INTEGER);
  155. BEGIN
  156.     Rex(0, reg);
  157.     OutByte2(8DH, 05H + 8 * (reg MOD 8)); // lea reg, [rip + offset]
  158.     X86.Reloc(section, offset)
  159. END lea;
  160.  
  161.  
  162. PROCEDURE oprr (op: BYTE; reg1, reg2: INTEGER);  // op reg1, reg2
  163. BEGIN
  164.     Rex(reg1, reg2);
  165.     OutByte2(op, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8)
  166. END oprr;
  167.  
  168.  
  169. PROCEDURE oprr2 (op1, op2: BYTE; reg1, reg2: INTEGER);  // op reg1, reg2
  170. BEGIN
  171.     Rex(reg1, reg2);
  172.     OutByte3(op1, op2, 0C0H + 8 * (reg2 MOD 8) + reg1 MOD 8)
  173. END oprr2;
  174.  
  175.  
  176. PROCEDURE mov (reg1, reg2: INTEGER); // mov reg1, reg2
  177. BEGIN
  178.     oprr(89H, reg1, reg2)
  179. END mov;
  180.  
  181.  
  182. PROCEDURE xor (reg1, reg2: INTEGER); // xor reg1, reg2
  183. BEGIN
  184.     oprr(31H, reg1, reg2)
  185. END xor;
  186.  
  187.  
  188. PROCEDURE and (reg1, reg2: INTEGER); // and reg1, reg2
  189. BEGIN
  190.     oprr(21H, reg1, reg2)
  191. END and;
  192.  
  193.  
  194. PROCEDURE or (reg1, reg2: INTEGER); // and reg1, reg2
  195. BEGIN
  196.     oprr(09H, reg1, reg2)
  197. END or;
  198.  
  199.  
  200. PROCEDURE add (reg1, reg2: INTEGER); // add reg1, reg2
  201. BEGIN
  202.     oprr(01H, reg1, reg2)
  203. END add;
  204.  
  205.  
  206. PROCEDURE sub (reg1, reg2: INTEGER); // sub reg1, reg2
  207. BEGIN
  208.     oprr(29H, reg1, reg2)
  209. END sub;
  210.  
  211.  
  212. PROCEDURE xchg (reg1, reg2: INTEGER); // xchg reg1, reg2
  213. BEGIN
  214.     oprr(87H, reg1, reg2)
  215. END xchg;
  216.  
  217.  
  218. PROCEDURE cmprr (reg1, reg2: INTEGER);  // cmp reg1, reg2
  219. BEGIN
  220.     oprr(39H, reg1, reg2)
  221. END cmprr;
  222.  
  223.  
  224. PROCEDURE pop (reg: INTEGER); // pop reg
  225. BEGIN
  226.     IF reg >= 8 THEN
  227.         OutByte(41H)
  228.     END;
  229.     OutByte(58H + reg MOD 8)
  230. END pop;
  231.  
  232.  
  233. PROCEDURE push (reg: INTEGER); // push reg
  234. BEGIN
  235.     IF reg >= 8 THEN
  236.         OutByte(41H)
  237.     END;
  238.     OutByte(50H + reg MOD 8)
  239. END push;
  240.  
  241.  
  242. PROCEDURE decr (reg: INTEGER);
  243. BEGIN
  244.     Rex(reg, 0);
  245.     OutByte2(0FFH, 0C8H + reg MOD 8) // dec reg1
  246. END decr;
  247.  
  248.  
  249. PROCEDURE incr (reg: INTEGER);
  250. BEGIN
  251.     Rex(reg, 0);
  252.     OutByte2(0FFH, 0C0H + reg MOD 8) // inc reg1
  253. END incr;
  254.  
  255.  
  256. PROCEDURE drop;
  257. BEGIN
  258.     REG.Drop(R)
  259. END drop;
  260.  
  261.  
  262. PROCEDURE GetAnyReg (): INTEGER;
  263.     RETURN REG.GetAnyReg(R)
  264. END GetAnyReg;
  265.  
  266.  
  267. PROCEDURE GetVarReg (offs: INTEGER): INTEGER;
  268.     RETURN REG.GetVarReg(R, offs)
  269. END GetVarReg;
  270.  
  271.  
  272. PROCEDURE callimp (label: INTEGER);
  273. VAR
  274.     reg: INTEGER;
  275.  
  276. BEGIN
  277.     reg := GetAnyReg();
  278.     lea(reg, label, sIMP);
  279.     IF reg >= 8 THEN // call qword[reg]
  280.         OutByte(41H)
  281.     END;
  282.     OutByte2(0FFH, 10H + reg MOD 8);
  283.     drop
  284. END callimp;
  285.  
  286.  
  287. PROCEDURE pushDA (offs: INTEGER);
  288. VAR
  289.     reg: INTEGER;
  290.  
  291. BEGIN
  292.     reg := GetAnyReg();
  293.     lea(reg, offs, sDATA);
  294.     push(reg);
  295.     drop
  296. END pushDA;
  297.  
  298.  
  299. PROCEDURE CallRTL (proc: INTEGER);
  300. VAR
  301.     label: INTEGER;
  302.  
  303. BEGIN
  304.     REG.Store(R);
  305.     label := IL.codes.rtl[proc];
  306.     IF label < 0 THEN
  307.         callimp(-label)
  308.     ELSE
  309.         X86.call(label)
  310.     END;
  311.     REG.Restore(R)
  312. END CallRTL;
  313.  
  314.  
  315. PROCEDURE UnOp (VAR reg: INTEGER);
  316. BEGIN
  317.     REG.UnOp(R, reg)
  318. END UnOp;
  319.  
  320.  
  321. PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
  322. BEGIN
  323.     REG.BinOp(R, reg1, reg2)
  324. END BinOp;
  325.  
  326.  
  327. PROCEDURE PushAll (NumberOfParameters: INTEGER);
  328. BEGIN
  329.     REG.PushAll(R);
  330.     DEC(R.pushed, NumberOfParameters)
  331. END PushAll;
  332.  
  333.  
  334. PROCEDURE movabs (reg, n: INTEGER);
  335. VAR
  336.     i: INTEGER;
  337.  
  338. BEGIN
  339.     Rex(reg, 0);
  340.     OutByte(0B8H + reg MOD 8);  // movabs reg, n
  341.     FOR i := 0 TO 7 DO
  342.         OutByte(UTILS.Byte(n, i))
  343.     END
  344. END movabs;
  345.  
  346.  
  347. PROCEDURE movrc (reg, n: INTEGER); // mov reg, n
  348. BEGIN
  349.     IF isLong(n) THEN
  350.         movabs(reg, n)
  351.     ELSIF n = 0 THEN
  352.         xor(reg, reg)
  353.     ELSE
  354.         Rex(reg, 0);
  355.         OutByte2(0C7H, 0C0H + reg MOD 8);
  356.         OutInt(n)
  357.     END
  358. END movrc;
  359.  
  360.  
  361. PROCEDURE test (reg: INTEGER); // test reg, reg
  362. BEGIN
  363.     oprr(85H, reg, reg)
  364. END test;
  365.  
  366.  
  367. PROCEDURE oprlongc (reg, n: INTEGER; oprr: OPRR);
  368. VAR
  369.     reg2: INTEGER;
  370.  
  371. BEGIN
  372.     reg2 := GetAnyReg();
  373.     movabs(reg2, n);
  374.     oprr(reg, reg2);
  375.     drop
  376. END oprlongc;
  377.  
  378.  
  379. PROCEDURE oprc (op, reg, n: INTEGER; oprr: OPRR);
  380. BEGIN
  381.     IF isLong(n) THEN
  382.         oprlongc(reg, n, oprr)
  383.     ELSE
  384.         Rex(reg, 0);
  385.         OutByte2(81H + short(n), op + reg MOD 8);
  386.         OutIntByte(n)
  387.     END
  388. END oprc;
  389.  
  390.  
  391. PROCEDURE cmprc (reg, n: INTEGER); // cmp reg, n
  392. BEGIN
  393.     oprc(0F8H, reg, n, cmprr)
  394. END cmprc;
  395.  
  396.  
  397. PROCEDURE addrc (reg, n: INTEGER); // add reg, n
  398. BEGIN
  399.     oprc(0C0H, reg, n, add)
  400. END addrc;
  401.  
  402.  
  403. PROCEDURE subrc (reg, n: INTEGER); // sub reg, n
  404. BEGIN
  405.     oprc(0E8H, reg, n, sub)
  406. END subrc;
  407.  
  408.  
  409. PROCEDURE andrc (reg, n: INTEGER); // and reg, n
  410. BEGIN
  411.     oprc(0E0H, reg, n, and)
  412. END andrc;
  413.  
  414.  
  415. PROCEDURE pushc (n: INTEGER);
  416. VAR
  417.     reg2: INTEGER;
  418.  
  419. BEGIN
  420.     IF isLong(n) THEN
  421.         reg2 := GetAnyReg();
  422.         movabs(reg2, n);
  423.         push(reg2);
  424.         drop
  425.     ELSE
  426.         OutByte(68H + short(n)); OutIntByte(n) // push n
  427.     END
  428. END pushc;
  429.  
  430.  
  431. PROCEDURE not (reg: INTEGER); // not reg
  432. BEGIN
  433.     Rex(reg, 0);
  434.     OutByte2(0F7H, 0D0H + reg MOD 8)
  435. END not;
  436.  
  437.  
  438. PROCEDURE neg (reg: INTEGER); // neg reg
  439. BEGIN
  440.     Rex(reg, 0);
  441.     OutByte2(0F7H, 0D8H + reg MOD 8)
  442. END neg;
  443.  
  444.  
  445. PROCEDURE movzx (reg1, reg2, offs: INTEGER; word: BOOLEAN);  // movzx reg1, byte/word[reg2 + offs]
  446. VAR
  447.     b: BYTE;
  448.  
  449. BEGIN
  450.     Rex(reg2, reg1);
  451.     OutByte2(0FH, 0B6H + ORD(word));
  452.     IF (offs = 0) & (reg2 # rbp) THEN
  453.         b := 0
  454.     ELSE
  455.         b := 40H + long(offs)
  456.     END;
  457.     OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8);
  458.     IF reg2 = rsp THEN
  459.         OutByte(24H)
  460.     END;
  461.     IF b # 0 THEN
  462.         OutIntByte(offs)
  463.     END
  464. END movzx;
  465.  
  466.  
  467. PROCEDURE _movrm (reg1, reg2, offs, size: INTEGER; mr: BOOLEAN);
  468. VAR
  469.     b: BYTE;
  470.  
  471. BEGIN
  472.     IF size = 16 THEN
  473.         OutByte(66H)
  474.     END;
  475.     IF (reg1 >= 8) OR (reg2 >= 8) OR (size = 64) THEN
  476.         OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8) + 8 * ORD(size = 64))
  477.     END;
  478.     OutByte(8BH - 2 * ORD(mr) - ORD(size = 8));
  479.     IF (offs = 0) & (reg2 # rbp) THEN
  480.         b := 0
  481.     ELSE
  482.         b := 40H + long(offs)
  483.     END;
  484.     OutByte(b + (reg1 MOD 8) * 8 + reg2 MOD 8);
  485.     IF reg2 = rsp THEN
  486.         OutByte(24H)
  487.     END;
  488.     IF b # 0 THEN
  489.         OutIntByte(offs)
  490.     END
  491. END _movrm;
  492.  
  493.  
  494. PROCEDURE movmr32 (reg1, offs, reg2: INTEGER); // mov dword[reg1+offs], reg2_32
  495. BEGIN
  496.     _movrm(reg2, reg1, offs, 32, TRUE)
  497. END movmr32;
  498.  
  499.  
  500. PROCEDURE movrm32 (reg1, reg2, offs: INTEGER); // mov reg1_32, dword[reg2+offs]
  501. BEGIN
  502.     _movrm(reg1, reg2, offs, 32, FALSE)
  503. END movrm32;
  504.  
  505.  
  506. PROCEDURE movmr8 (reg1, offs, reg2: INTEGER); // mov byte[reg1+offs], reg2_8
  507. BEGIN
  508.     _movrm(reg2, reg1, offs, 8, TRUE)
  509. END movmr8;
  510.  
  511.  
  512. PROCEDURE movrm8 (reg1, reg2, offs: INTEGER); // mov reg1_8, byte[reg2+offs]
  513. BEGIN
  514.     _movrm(reg1, reg2, offs, 8, FALSE)
  515. END movrm8;
  516.  
  517.  
  518. PROCEDURE movmr16 (reg1, offs, reg2: INTEGER); // mov word[reg1+offs], reg2_16
  519. BEGIN
  520.     _movrm(reg2, reg1, offs, 16, TRUE)
  521. END movmr16;
  522.  
  523.  
  524. PROCEDURE movrm16 (reg1, reg2, offs: INTEGER); // mov reg1_16, word[reg2+offs]
  525. BEGIN
  526.     _movrm(reg1, reg2, offs, 16, FALSE)
  527. END movrm16;
  528.  
  529.  
  530. PROCEDURE movmr (reg1, offs, reg2: INTEGER); // mov qword[reg1+offs], reg2
  531. BEGIN
  532.     _movrm(reg2, reg1, offs, 64, TRUE)
  533. END movmr;
  534.  
  535.  
  536. PROCEDURE movrm (reg1, reg2, offs: INTEGER); // mov reg1, qword[reg2+offs]
  537. BEGIN
  538.     _movrm(reg1, reg2, offs, 64, FALSE)
  539. END movrm;
  540.  
  541.  
  542. PROCEDURE pushm (reg, offs: INTEGER); // push qword[reg+offs]
  543. VAR
  544.     b: BYTE;
  545.  
  546. BEGIN
  547.     IF reg >= 8 THEN
  548.         OutByte(41H)
  549.     END;
  550.     OutByte(0FFH);
  551.     IF (offs = 0) & (reg # rbp) THEN
  552.         b := 30H
  553.     ELSE
  554.         b := 70H + long(offs)
  555.     END;
  556.     OutByte(b + reg MOD 8);
  557.     IF reg = rsp THEN
  558.         OutByte(24H)
  559.     END;
  560.     IF b # 30H THEN
  561.         OutIntByte(offs)
  562.     END
  563. END pushm;
  564.  
  565.  
  566. PROCEDURE comisd (xmm1, xmm2: INTEGER); // comisd xmm1, xmm2
  567. BEGIN
  568.     OutByte(66H);
  569.     IF (xmm1 >= 8) OR (xmm2 >= 8) THEN
  570.         OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8)
  571.     END;
  572.     OutByte3(0FH, 2FH, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8)
  573. END comisd;
  574.  
  575.  
  576. PROCEDURE _movsdrm (xmm, reg, offs: INTEGER; mr: BOOLEAN);
  577. VAR
  578.     b: BYTE;
  579.  
  580. BEGIN
  581.     OutByte(0F2H);
  582.     IF (xmm >= 8) OR (reg >= 8) THEN
  583.         OutByte(40H + (xmm DIV 8) * 4 + reg DIV 8)
  584.     END;
  585.     OutByte2(0FH, 10H + ORD(mr));
  586.     IF (offs = 0) & (reg # rbp) THEN
  587.         b := 0
  588.     ELSE
  589.         b := 40H + long(offs)
  590.     END;
  591.     OutByte(b + (xmm MOD 8) * 8 + reg MOD 8);
  592.     IF reg = rsp THEN
  593.         OutByte(24H)
  594.     END;
  595.     IF b # 0 THEN
  596.         OutIntByte(offs)
  597.     END
  598. END _movsdrm;
  599.  
  600.  
  601. PROCEDURE movsdrm (xmm, reg, offs: INTEGER); // movsd xmm, qword[reg+offs]
  602. BEGIN
  603.     _movsdrm(xmm, reg, offs, FALSE)
  604. END movsdrm;
  605.  
  606.  
  607. PROCEDURE movsdmr (reg, offs, xmm: INTEGER); // movsd qword[reg+offs], xmm
  608. BEGIN
  609.     _movsdrm(xmm, reg, offs, TRUE)
  610. END movsdmr;
  611.  
  612.  
  613. PROCEDURE opxx (op, xmm1, xmm2: INTEGER);
  614. BEGIN
  615.     OutByte(0F2H);
  616.     IF (xmm1 >= 8) OR (xmm2 >= 8) THEN
  617.         OutByte(40H + (xmm1 DIV 8) * 4 + xmm2 DIV 8)
  618.     END;
  619.     OutByte3(0FH, op, 0C0H + (xmm1 MOD 8) * 8 + xmm2 MOD 8)
  620. END opxx;
  621.  
  622.  
  623. PROCEDURE jcc (cc, label: INTEGER); // jcc label
  624. BEGIN
  625.     X86.jcc(cc, label)
  626. END jcc;
  627.  
  628.  
  629. PROCEDURE jmp (label: INTEGER); // jmp label
  630. BEGIN
  631.     X86.jmp(label)
  632. END jmp;
  633.  
  634.  
  635. PROCEDURE setcc (cc, reg: INTEGER); //setcc reg8
  636. BEGIN
  637.     IF reg >= 8 THEN
  638.         OutByte(41H)
  639.     END;
  640.     OutByte3(0FH, cc, 0C0H + reg MOD 8)
  641. END setcc;
  642.  
  643.  
  644. PROCEDURE shiftrc (op, reg, n: INTEGER);
  645. BEGIN
  646.     Rex(reg, 0);
  647.     IF n = 1 THEN
  648.         OutByte(0D1H)
  649.     ELSE
  650.         OutByte(0C1H)
  651.     END;
  652.     X86.shift(op, reg MOD 8);
  653.     IF n # 1 THEN
  654.         OutByte(n)
  655.     END
  656. END shiftrc;
  657.  
  658.  
  659. PROCEDURE getVar (variables: LISTS.LIST; offset: INTEGER): IL.LOCALVAR;
  660. VAR
  661.     cur: IL.LOCALVAR;
  662.  
  663. BEGIN
  664.     cur := variables.first(IL.LOCALVAR);
  665.     WHILE (cur # NIL) & (cur.offset # offset) DO
  666.         cur := cur.next(IL.LOCALVAR)
  667.     END
  668.  
  669.     RETURN cur
  670. END getVar;
  671.  
  672.  
  673. PROCEDURE allocReg (cmd: COMMAND);
  674. VAR
  675.     leave:      BOOLEAN;
  676.     leaf:       BOOLEAN;
  677.     cur:        COMMAND;
  678.     variables:  LISTS.LIST;
  679.     lvar, rvar: IL.LOCALVAR;
  680.     reg:        INTEGER;
  681.     max:        INTEGER;
  682.     loop:       INTEGER;
  683.     param2:     INTEGER;
  684.  
  685. BEGIN
  686.     loop := 1;
  687.     variables := cmd.variables;
  688.     leave := FALSE;
  689.     leaf := TRUE;
  690.  
  691.     cur := cmd.next(COMMAND);
  692.     REPEAT
  693.         CASE cur.opcode OF
  694.         |IL.opLLOAD64,
  695.          IL.opLLOAD8,
  696.          IL.opLLOAD16,
  697.          IL.opLLOAD32,
  698.          IL.opLLOAD64_PARAM,
  699.          IL.opLLOAD32_PARAM,
  700.          IL.opLADR_SAVE,
  701.          IL.opLADR_INC,
  702.          IL.opLADR_DEC,
  703.          IL.opLADR_INCB,
  704.          IL.opLADR_DECB,
  705.          IL.opLADR_INCL,
  706.          IL.opLADR_EXCL,
  707.          IL.opLADR_UNPK:
  708.             lvar := getVar(variables, cur.param2);
  709.             IF (lvar # NIL) & (lvar.count # -1) THEN
  710.                 INC(lvar.count, loop)
  711.             END
  712.  
  713.         |IL.opLADR_SAVEC,
  714.          IL.opLADR_INCC,
  715.          IL.opLADR_INCCB,
  716.          IL.opLADR_DECCB,
  717.          IL.opLADR_INCLC,
  718.          IL.opLADR_EXCLC:
  719.             lvar := getVar(variables, cur.param1);
  720.             IF (lvar # NIL) & (lvar.count # -1) THEN
  721.                 INC(lvar.count, loop)
  722.             END
  723.  
  724.         |IL.opLADR:
  725.             lvar := getVar(variables, cur.param2);
  726.             IF (lvar # NIL) & (lvar.count # -1) THEN
  727.                 lvar.count := -1
  728.             END
  729.  
  730.         |IL.opLOOP:
  731.             INC(loop, 10)
  732.  
  733.         |IL.opENDLOOP:
  734.             DEC(loop, 10)
  735.  
  736.         |IL.opLEAVE,
  737.          IL.opLEAVER,
  738.          IL.opLEAVEF:
  739.             leave := TRUE
  740.  
  741.         |IL.opCALL, IL.opCALLP, IL.opCALLI,
  742.          IL.opWIN64CALL, IL.opWIN64CALLP, IL.opWIN64CALLI,
  743.          IL.opSYSVCALL, IL.opSYSVCALLP, IL.opSYSVCALLI,
  744.  
  745.          IL.opSAVES, IL.opRSET, IL.opRSETR,
  746.          IL.opRSETL, IL.opRSET1,
  747.          IL.opEQS .. IL.opGES,
  748.          IL.opEQSW .. IL.opGESW,
  749.          IL.opCOPY, IL.opMOVE, IL.opCOPYA,
  750.          IL.opCOPYS, IL.opROT,
  751.          IL.opNEW, IL.opDISP, IL.opISREC,
  752.          IL.opIS, IL.opTYPEGR, IL.opTYPEGP,
  753.          IL.opCASET, IL.opDIV,
  754.          IL.opDIVL, IL.opMOD,
  755.          IL.opMODL, IL.opLENGTH, IL.opLENGTHW:
  756.             leaf := FALSE
  757.  
  758.         |IL.opDIVR, IL.opMODR:
  759.             param2 := cur.param2;
  760.             IF param2 >= 1 THEN
  761.                 param2 := UTILS.Log2(param2)
  762.             ELSIF param2 <= -1 THEN
  763.                 param2 := UTILS.Log2(-param2)
  764.             ELSE
  765.                 param2 := -1
  766.             END;
  767.             IF param2 < 0 THEN
  768.                 leaf := FALSE
  769.             END
  770.  
  771.         ELSE
  772.  
  773.         END;
  774.         cur := cur.next(COMMAND)
  775.     UNTIL leave OR ~leaf;
  776.  
  777.     IF leaf THEN
  778.         REPEAT
  779.             reg := -1;
  780.             max := -1;
  781.             rvar := NIL;
  782.             lvar := variables.first(IL.LOCALVAR);
  783.             WHILE lvar # NIL DO
  784.                 IF lvar.count > max THEN
  785.                     max := lvar.count;
  786.                     rvar := lvar
  787.                 END;
  788.                 lvar := lvar.next(IL.LOCALVAR)
  789.             END;
  790.  
  791.             IF rvar # NIL THEN
  792.                 reg := REG.GetAnyVarReg(R);
  793.                 IF reg # -1 THEN
  794.                     REG.Lock(R, reg, rvar.offset, rvar.size);
  795.                     REG.Load(R, reg);
  796.                     rvar.count := -1
  797.                 END
  798.             END
  799.  
  800.         UNTIL (rvar = NIL) OR (reg = -1)
  801.     END
  802.  
  803. END allocReg;
  804.  
  805.  
  806. PROCEDURE GetRegA;
  807. BEGIN
  808.     ASSERT(REG.GetReg(R, rax))
  809. END GetRegA;
  810.  
  811.  
  812. PROCEDURE Win64Passing (params: INTEGER);
  813. VAR
  814.     n, i: INTEGER;
  815.  
  816. BEGIN
  817.     n := params MOD 32;
  818.     params := params DIV 32;
  819.     FOR i := 0 TO n - 1 DO
  820.         IF i IN BITS(params) THEN
  821.             movsdrm(i, rsp, i * 8)
  822.         ELSE
  823.             movrm(Win64RegPar[i], rsp, i * 8)
  824.         END
  825.     END
  826. END Win64Passing;
  827.  
  828.  
  829. PROCEDURE SysVPassing (params: INTEGER);
  830. VAR
  831.     n, i, s, p, ofs: INTEGER;
  832.     i_count, f_count: INTEGER;
  833.     reg: BOOLEAN;
  834.  
  835. BEGIN
  836.     ASSERT(r10 IN R.regs);
  837.     n := params MOD 32;
  838.     params := params DIV 32;
  839.     s := 0;
  840.  
  841.     i_count := 0;
  842.     f_count := 0;
  843.     FOR i := 0 TO n - 1 DO
  844.         IF i IN BITS(params) THEN
  845.             INC(f_count)
  846.         ELSE
  847.             INC(i_count)
  848.         END
  849.     END;
  850.  
  851.     s := MAX(0, f_count - 8) + MAX(0, i_count - 6);
  852.     p := 0;
  853.  
  854.     subrc(rsp, s * 8);
  855.  
  856.     i_count := 0;
  857.     f_count := 0;
  858.     FOR i := 0 TO n - 1 DO
  859.         ofs := (i + s) * 8;
  860.         IF i IN BITS(params) THEN
  861.             reg := f_count <= 7;
  862.             IF reg THEN
  863.                 movsdrm(f_count, rsp, ofs);
  864.                 INC(f_count)
  865.             END
  866.         ELSE
  867.             reg := i_count <= 5;
  868.             IF reg THEN
  869.                 movrm(SystemVRegPar[i_count], rsp, ofs);
  870.                 INC(i_count)
  871.             END
  872.         END;
  873.  
  874.         IF ~reg THEN
  875.             movrm(r10, rsp, ofs);
  876.             movmr(rsp, p, r10);
  877.             INC(p, 8)
  878.         END
  879.     END
  880. END SysVPassing;
  881.  
  882.  
  883. PROCEDURE fcmp (op: INTEGER; xmm: INTEGER);
  884. VAR
  885.     cc, reg: INTEGER;
  886.  
  887. BEGIN
  888.     reg := GetAnyReg();
  889.     xor(reg, reg);
  890.     CASE op OF
  891.     |IL.opEQF:
  892.         comisd(xmm - 1, xmm);
  893.         cc := sete
  894.  
  895.     |IL.opNEF:
  896.         comisd(xmm - 1, xmm);
  897.         cc := setne
  898.  
  899.     |IL.opLTF:
  900.         comisd(xmm - 1, xmm);
  901.         cc := setc
  902.  
  903.     |IL.opGTF:
  904.         comisd(xmm, xmm - 1);
  905.         cc := setc
  906.  
  907.     |IL.opLEF:
  908.         comisd(xmm, xmm - 1);
  909.         cc := setnc
  910.  
  911.     |IL.opGEF:
  912.         comisd(xmm - 1, xmm);
  913.         cc := setnc
  914.     END;
  915.     OutByte2(7AH, 3 + reg DIV 8); // jp L
  916.     setcc(cc, reg);
  917.     //L:
  918. END fcmp;
  919.  
  920.  
  921. PROCEDURE translate (commands: LISTS.LIST; stroffs: INTEGER);
  922. VAR
  923.     cmd, next: COMMAND;
  924.  
  925.     opcode, param1, param2, param3, a, b, c, n, label, L, i, cc: INTEGER;
  926.  
  927.     reg1, reg2, xmm: INTEGER;
  928.  
  929.     float: REAL;
  930.  
  931.     regVar: BOOLEAN;
  932.  
  933. BEGIN
  934.     xmm := -1;
  935.     cmd := commands.first(COMMAND);
  936.     WHILE cmd # NIL DO
  937.  
  938.         param1 := cmd.param1;
  939.         param2 := cmd.param2;
  940.  
  941.         opcode := cmd.opcode;
  942.  
  943.         CASE opcode OF
  944.  
  945.         |IL.opJMP:
  946.             jmp(param1)
  947.  
  948.         |IL.opCALL, IL.opWIN64CALL, IL.opSYSVCALL:
  949.             REG.Store(R);
  950.             CASE opcode OF
  951.             |IL.opCALL:
  952.             |IL.opWIN64CALL: Win64Passing(param2)
  953.             |IL.opSYSVCALL:  SysVPassing(param2)
  954.             END;
  955.             X86.call(param1);
  956.             REG.Restore(R)
  957.  
  958.         |IL.opCALLP, IL.opWIN64CALLP, IL.opSYSVCALLP:
  959.             UnOp(reg1);
  960.             IF reg1 # rax THEN
  961.                 GetRegA;
  962.                 ASSERT(REG.Exchange(R, reg1, rax));
  963.                 drop
  964.             END;
  965.             drop;
  966.             REG.Store(R);
  967.             CASE opcode OF
  968.             |IL.opCALLP:
  969.             |IL.opWIN64CALLP: Win64Passing(param2)
  970.             |IL.opSYSVCALLP:  SysVPassing(param2)
  971.             END;
  972.             OutByte2(0FFH, 0D0H); // call rax
  973.             REG.Restore(R);
  974.             ASSERT(R.top = -1)
  975.  
  976.         |IL.opCALLI, IL.opWIN64CALLI, IL.opSYSVCALLI:
  977.             REG.Store(R);
  978.             CASE opcode OF
  979.             |IL.opCALLI:
  980.             |IL.opWIN64CALLI: Win64Passing(param2)
  981.             |IL.opSYSVCALLI:  SysVPassing(param2)
  982.             END;
  983.             callimp(param1);
  984.             REG.Restore(R)
  985.  
  986.         |IL.opLABEL:
  987.             X86.SetLabel(param1)
  988.  
  989.         |IL.opERR:
  990.             CallRTL(IL._error)
  991.  
  992.         |IL.opPUSHC:
  993.             pushc(param2)
  994.  
  995.         |IL.opPRECALL:
  996.             n := param2;
  997.             IF (param1 # 0) & (n # 0) THEN
  998.                 subrc(rsp, 8)
  999.             END;
  1000.             WHILE n > 0 DO
  1001.                 subrc(rsp, 8);
  1002.                 movsdmr(rsp, 0, xmm);
  1003.                 DEC(xmm);
  1004.                 DEC(n)
  1005.             END;
  1006.             ASSERT(xmm = -1);
  1007.             PushAll(0)
  1008.  
  1009.         |IL.opWIN64ALIGN16:
  1010.             ASSERT(rax IN R.regs);
  1011.             mov(rax, rsp);
  1012.             andrc(rsp, -16);
  1013.             push(rax);
  1014.             subrc(rsp, (MAX(param2 - 4, 0) MOD 2 + MAX(4 - param2, 0) + 1) * 8)
  1015.  
  1016.         |IL.opSYSVALIGN16:
  1017.             ASSERT(rax IN R.regs);
  1018.             mov(rax, rsp);
  1019.             andrc(rsp, -16);
  1020.             push(rax);
  1021.             IF ~ODD(param2) THEN
  1022.                 push(rax)
  1023.             END
  1024.  
  1025.         |IL.opRESF:
  1026.             ASSERT(xmm = -1);
  1027.             INC(xmm);
  1028.             n := param2;
  1029.             IF n > 0 THEN
  1030.                 movsdmr(rsp, n * 8, xmm);
  1031.                 DEC(xmm);
  1032.                 INC(n)
  1033.             END;
  1034.  
  1035.             WHILE n > 0 DO
  1036.                 INC(xmm);
  1037.                 movsdrm(xmm, rsp, 0);
  1038.                 addrc(rsp, 8);
  1039.                 DEC(n)
  1040.             END
  1041.  
  1042.         |IL.opRES:
  1043.             ASSERT(R.top = -1);
  1044.             GetRegA;
  1045.             n := param2;
  1046.             WHILE n > 0 DO
  1047.                 INC(xmm);
  1048.                 movsdrm(xmm, rsp, 0);
  1049.                 addrc(rsp, 8);
  1050.                 DEC(n)
  1051.             END
  1052.  
  1053.         |IL.opENTER:
  1054.             ASSERT(R.top = -1);
  1055.  
  1056.             X86.SetLabel(param1);
  1057.  
  1058.             param3 := cmd.param3;
  1059.  
  1060.             IF param3 > 0 THEN
  1061.                 push(rbp);
  1062.                 mov(rbp, rsp);
  1063.  
  1064.                 n := param3 MOD 32;
  1065.                 param3 := param3 DIV 32;
  1066.  
  1067.                 FOR i := 0 TO n - 1 DO
  1068.                     IF i IN BITS(param3) THEN
  1069.                         movsdmr(rbp, i * 8 + 16, i)
  1070.                     ELSE
  1071.                         movmr(rbp, i * 8 + 16, Win64RegPar[i])
  1072.                     END
  1073.                 END
  1074.             ELSIF param3 < 0 THEN
  1075.                 param3 := -param3;
  1076.                 n := (param3 MOD 32) * 8;
  1077.                 param3 := param3 DIV 32;
  1078.                 pop(r10);
  1079.                 subrc(rsp, n);
  1080.                 push(r10);
  1081.                 push(rbp);
  1082.                 mov(rbp, rsp);
  1083.  
  1084.                 a := 0;
  1085.                 b := 0;
  1086.                 c := 0;
  1087.  
  1088.                 INC(n, 16);
  1089.  
  1090.                 FOR i := 16 TO n - 8 BY 8 DO
  1091.                     IF ODD(param3) THEN
  1092.                         IF b <= 7 THEN
  1093.                             movsdmr(rbp, i, b);
  1094.                             INC(b)
  1095.                         ELSE
  1096.                             movrm(r10, rbp, n + c);
  1097.                             movmr(rbp, i, r10);
  1098.                             INC(c, 8)
  1099.                         END
  1100.                     ELSE
  1101.                         IF a <= 5 THEN
  1102.                             movmr(rbp, i, SystemVRegPar[a]);
  1103.                             INC(a)
  1104.                         ELSE
  1105.                             movrm(r10, rbp, n + c);
  1106.                             movmr(rbp, i, r10);
  1107.                             INC(c, 8)
  1108.                         END
  1109.                     END;
  1110.                     param3 := param3 DIV 2
  1111.                 END
  1112.             ELSE
  1113.                 push(rbp);
  1114.                 mov(rbp, rsp)
  1115.             END;
  1116.  
  1117.             n := param2;
  1118.             IF n > 4 THEN
  1119.                 movrc(rcx, n);
  1120.                                       // L:
  1121.                 pushc(0);
  1122.                 OutByte2(0E2H, 0FCH) // loop L
  1123.             ELSE
  1124.                 WHILE n > 0 DO
  1125.                     pushc(0);
  1126.                     DEC(n)
  1127.                 END
  1128.             END;
  1129.  
  1130.             IF cmd.allocReg THEN
  1131.                 allocReg(cmd)
  1132.             END
  1133.  
  1134.         |IL.opLEAVE, IL.opLEAVER, IL.opLEAVEF:
  1135.             IF opcode = IL.opLEAVER THEN
  1136.                 UnOp(reg1);
  1137.                 IF reg1 # rax THEN
  1138.                     GetRegA;
  1139.                     ASSERT(REG.Exchange(R, reg1, rax));
  1140.                     drop
  1141.                 END;
  1142.                 drop
  1143.             END;
  1144.  
  1145.             ASSERT(R.top = -1);
  1146.  
  1147.             IF opcode = IL.opLEAVEF THEN
  1148.                 DEC(xmm)
  1149.             END;
  1150.  
  1151.             ASSERT(xmm = -1);
  1152.  
  1153.             IF param1 > 0 THEN
  1154.                 mov(rsp, rbp)
  1155.             END;
  1156.  
  1157.             pop(rbp);
  1158.             IF param2 > 0 THEN
  1159.                 OutByte3(0C2H, (param2 * 8) MOD 256, (param2 * 8) DIV 256)  // ret param2
  1160.             ELSE
  1161.                 OutByte(0C3H) // ret
  1162.             END;
  1163.             REG.Reset(R)
  1164.  
  1165.         |IL.opSAVES:
  1166.             PushAll(1);
  1167.             pushDA(stroffs + param2);
  1168.             pushc(param1);
  1169.             CallRTL(IL._move)
  1170.  
  1171.         |IL.opSADR:
  1172.             lea(GetAnyReg(), stroffs + param2, sDATA)
  1173.  
  1174.         |IL.opLOAD8:
  1175.             UnOp(reg1);
  1176.             movzx(reg1, reg1, 0, FALSE)
  1177.  
  1178.         |IL.opLOAD16:
  1179.             UnOp(reg1);
  1180.             movzx(reg1, reg1, 0, TRUE)
  1181.  
  1182.         |IL.opLOAD32:
  1183.             UnOp(reg1);
  1184.             movrm32(reg1, reg1, 0);
  1185.             shiftrc(shl, reg1, 32);
  1186.             shiftrc(shr, reg1, 32)
  1187.  
  1188.         |IL.opLOAD64:
  1189.             UnOp(reg1);
  1190.             movrm(reg1, reg1, 0)
  1191.  
  1192.         |IL.opLLOAD64:
  1193.             reg1 := GetAnyReg();
  1194.             reg2 := GetVarReg(param2);
  1195.             IF reg2 # -1 THEN
  1196.                 mov(reg1, reg2)
  1197.             ELSE
  1198.                 movrm(reg1, rbp, param2 * 8)
  1199.             END
  1200.  
  1201.         |IL.opLLOAD8,
  1202.          IL.opLLOAD16:
  1203.             reg1 := GetAnyReg();
  1204.             reg2 := GetVarReg(param2);
  1205.             IF reg2 # -1 THEN
  1206.                 mov(reg1, reg2)
  1207.             ELSE
  1208.                 movzx(reg1, rbp, param2 * 8, opcode = IL.opLLOAD16)
  1209.             END
  1210.  
  1211.         |IL.opLLOAD32:
  1212.             reg1 := GetAnyReg();
  1213.             reg2 := GetVarReg(param2);
  1214.             IF reg2 # -1 THEN
  1215.                 mov(reg1, reg2)
  1216.             ELSE
  1217.                 n := param2 * 8;
  1218.                 xor(reg1, reg1);
  1219.                 movrm32(reg1, rbp, n)
  1220.             END
  1221.  
  1222.         |IL.opGLOAD64:
  1223.             reg1 := GetAnyReg();
  1224.             lea(reg1, param2, sBSS);
  1225.             movrm(reg1, reg1, 0)
  1226.  
  1227.         |IL.opGLOAD8:
  1228.             reg1 := GetAnyReg();
  1229.             lea(reg1, param2, sBSS);
  1230.             movzx(reg1, reg1, 0, FALSE)
  1231.  
  1232.         |IL.opGLOAD16:
  1233.             reg1 := GetAnyReg();
  1234.             lea(reg1, param2, sBSS);
  1235.             movzx(reg1, reg1, 0, TRUE)
  1236.  
  1237.         |IL.opGLOAD32:
  1238.             reg1 := GetAnyReg();
  1239.             xor(reg1, reg1);
  1240.             lea(reg1, param2, sBSS);
  1241.             movrm32(reg1, reg1, 0)
  1242.  
  1243.         |IL.opVLOAD64:
  1244.             reg1 := GetAnyReg();
  1245.             movrm(reg1, rbp, param2 * 8);
  1246.             movrm(reg1, reg1, 0)
  1247.  
  1248.         |IL.opVLOAD8,
  1249.          IL.opVLOAD16:
  1250.             reg1 := GetAnyReg();
  1251.             movrm(reg1, rbp, param2 * 8);
  1252.             movzx(reg1, reg1, 0, opcode = IL.opVLOAD16)
  1253.  
  1254.         |IL.opVLOAD32:
  1255.             reg1 := GetAnyReg();
  1256.             reg2 := GetAnyReg();
  1257.             xor(reg1, reg1);
  1258.             movrm(reg2, rbp, param2 * 8);
  1259.             movrm32(reg1, reg2, 0);
  1260.             drop
  1261.  
  1262.         |IL.opLADR:
  1263.             n := param2 * 8;
  1264.             next := cmd.next(COMMAND);
  1265.             IF next.opcode = IL.opSAVEF THEN
  1266.                 movsdmr(rbp, n, xmm);
  1267.                 DEC(xmm);
  1268.                 cmd := next
  1269.             ELSIF next.opcode = IL.opLOADF THEN
  1270.                 INC(xmm);
  1271.                 movsdrm(xmm, rbp, n);
  1272.                 cmd := next
  1273.             ELSE
  1274.                 reg1 := GetAnyReg();
  1275.                 Rex(0, reg1);
  1276.                 OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8);  // lea reg1, qword[rbp+n]
  1277.                 OutIntByte(n)
  1278.             END
  1279.  
  1280.         |IL.opGADR:
  1281.             lea(GetAnyReg(), param2, sBSS)
  1282.  
  1283.         |IL.opVADR:
  1284.             movrm(GetAnyReg(), rbp, param2 * 8)
  1285.  
  1286.         |IL.opSAVE8C:
  1287.             UnOp(reg1);
  1288.             IF reg1 >= 8 THEN
  1289.                 OutByte(41H)
  1290.             END;
  1291.             OutByte3(0C6H, reg1 MOD 8, param2); // mov byte[reg1], param2
  1292.             drop
  1293.  
  1294.         |IL.opSAVE16C:
  1295.             UnOp(reg1);
  1296.             OutByte(66H);
  1297.             IF reg1 >= 8 THEN
  1298.                 OutByte(41H)
  1299.             END;
  1300.             OutByte2(0C7H, reg1 MOD 8);
  1301.             OutByte2(param2 MOD 256, param2 DIV 256); // mov word[reg1], param2
  1302.             drop
  1303.  
  1304.         |IL.opSAVEC:
  1305.             UnOp(reg1);
  1306.             IF isLong(param2) THEN
  1307.                 reg2 := GetAnyReg();
  1308.                 movrc(reg2, param2);
  1309.                 movmr(reg1, 0, reg2);
  1310.                 drop
  1311.             ELSE
  1312.                 Rex(reg1, 0);
  1313.                 OutByte2(0C7H, reg1 MOD 8); // mov qword[reg1], param2
  1314.                 OutInt(param2)
  1315.             END;
  1316.             drop
  1317.  
  1318.         |IL.opRSET:
  1319.             PushAll(2);
  1320.             CallRTL(IL._set);
  1321.             GetRegA
  1322.  
  1323.         |IL.opRSETR:
  1324.             PushAll(1);
  1325.             pushc(param2);
  1326.             CallRTL(IL._set);
  1327.             GetRegA
  1328.  
  1329.         |IL.opRSETL:
  1330.             PushAll(1);
  1331.             pushc(param2);
  1332.             CallRTL(IL._set2);
  1333.             GetRegA
  1334.  
  1335.         |IL.opRSET1:
  1336.             UnOp(reg1);
  1337.             PushAll(1);
  1338.             push(reg1);
  1339.             CallRTL(IL._set);
  1340.             GetRegA
  1341.  
  1342.         |IL.opINCL, IL.opEXCL:
  1343.             BinOp(reg1, reg2);
  1344.             cmprc(reg1, 64);
  1345.             OutByte2(73H, 04H); // jnb L
  1346.             Rex(reg2, reg1);
  1347.             OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); // bts/btr qword[reg2], reg1
  1348.             // L:
  1349.             drop;
  1350.             drop
  1351.  
  1352.         |IL.opINCLC, IL.opEXCLC:
  1353.             UnOp(reg1);
  1354.             Rex(reg1, 0);
  1355.             OutByte2(0FH, 0BAH);  // bts/btr qword[reg1], param2
  1356.             OutByte2(28H + 8 * ORD(opcode = IL.opEXCLC) + reg1 MOD 8, param2);
  1357.             drop
  1358.  
  1359.         |IL.opEQS .. IL.opGES:
  1360.             PushAll(4);
  1361.             pushc(opcode - IL.opEQS);
  1362.             CallRTL(IL._strcmp);
  1363.             GetRegA
  1364.  
  1365.         |IL.opEQSW .. IL.opGESW:
  1366.             PushAll(4);
  1367.             pushc(opcode - IL.opEQSW);
  1368.             CallRTL(IL._strcmpw);
  1369.             GetRegA
  1370.  
  1371.         |IL.opCONST:
  1372.             movrc(GetAnyReg(), param2)
  1373.  
  1374.         |IL.opEQ..IL.opGE,
  1375.          IL.opEQC..IL.opGEC:
  1376.  
  1377.             IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN
  1378.                 BinOp(reg1, reg2);
  1379.                 cmprr(reg1, reg2);
  1380.                 drop
  1381.             ELSE
  1382.                 UnOp(reg1);
  1383.                 IF param2 = 0 THEN
  1384.                     test(reg1)
  1385.                 ELSE
  1386.                     cmprc(reg1, param2)
  1387.                 END
  1388.             END;
  1389.  
  1390.             drop;
  1391.             cc := X86.cond(opcode);
  1392.  
  1393.             IF cmd.next(COMMAND).opcode = IL.opJE THEN
  1394.                 label := cmd.next(COMMAND).param1;
  1395.                 jcc(cc, label);
  1396.                 cmd := cmd.next(COMMAND)
  1397.  
  1398.             ELSIF cmd.next(COMMAND).opcode = IL.opJNE THEN
  1399.                 label := cmd.next(COMMAND).param1;
  1400.                 jcc(X86.inv0(cc), label);
  1401.                 cmd := cmd.next(COMMAND)
  1402.  
  1403.             ELSE
  1404.                 reg1 := GetAnyReg();
  1405.                 setcc(cc + 16, reg1);
  1406.                 andrc(reg1, 1)
  1407.             END
  1408.  
  1409.         |IL.opCODE:
  1410.             OutByte(param2)
  1411.  
  1412.         |IL.opPUSHIP:
  1413.             reg1 := GetAnyReg();
  1414.             lea(reg1, param2, sIMP);
  1415.             movrm(reg1, reg1, 0)
  1416.  
  1417.         |IL.opPARAM:
  1418.             n := param2;
  1419.             IF n = 1 THEN
  1420.                 UnOp(reg1);
  1421.                 push(reg1);
  1422.                 drop
  1423.             ELSE
  1424.                 ASSERT(R.top + 1 <= n);
  1425.                 PushAll(n)
  1426.             END
  1427.  
  1428.         |IL.opACC:
  1429.             IF (R.top # 0) OR (R.stk[0] # rax) THEN
  1430.                 PushAll(0);
  1431.                 GetRegA;
  1432.                 pop(rax);
  1433.                 DEC(R.pushed)
  1434.             END
  1435.  
  1436.         |IL.opJNZ:
  1437.             UnOp(reg1);
  1438.             test(reg1);
  1439.             jcc(jne, param1)
  1440.  
  1441.         |IL.opJZ:
  1442.             UnOp(reg1);
  1443.             test(reg1);
  1444.             jcc(je, param1)
  1445.  
  1446.         |IL.opJE:
  1447.             UnOp(reg1);
  1448.             test(reg1);
  1449.             jcc(jne, param1);
  1450.             drop
  1451.  
  1452.         |IL.opJNE:
  1453.             UnOp(reg1);
  1454.             test(reg1);
  1455.             jcc(je, param1);
  1456.             drop
  1457.  
  1458.         |IL.opIN:
  1459.             label := NewLabel();
  1460.             L := NewLabel();
  1461.             BinOp(reg1, reg2);
  1462.             cmprc(reg1, 64);
  1463.             jcc(jb, L);
  1464.             xor(reg1, reg1);
  1465.             jmp(label);
  1466.             X86.SetLabel(L);
  1467.             Rex(reg2, reg1);
  1468.             OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
  1469.             setcc(setc, reg1);
  1470.             andrc(reg1, 1);
  1471.             X86.SetLabel(label);
  1472.             drop
  1473.  
  1474.         |IL.opINR:
  1475.             label := NewLabel();
  1476.             L := NewLabel();
  1477.             UnOp(reg1);
  1478.             reg2 := GetAnyReg();
  1479.             cmprc(reg1, 64);
  1480.             jcc(jb, L);
  1481.             xor(reg1, reg1);
  1482.             jmp(label);
  1483.             X86.SetLabel(L);
  1484.             movrc(reg2, param2);
  1485.             Rex(reg2, reg1);
  1486.             OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
  1487.             setcc(setc, reg1);
  1488.             andrc(reg1, 1);
  1489.             X86.SetLabel(label);
  1490.             drop
  1491.  
  1492.         |IL.opINL:
  1493.             UnOp(reg1);
  1494.             Rex(reg1, 0);
  1495.             OutByte2(0FH, 0BAH);  // bt reg1, param2
  1496.             OutByte2(0E0H + reg1 MOD 8, param2);
  1497.             setcc(setc, reg1);
  1498.             andrc(reg1, 1)
  1499.  
  1500.         |IL.opNOT:
  1501.             UnOp(reg1);
  1502.             test(reg1);
  1503.             setcc(sete, reg1);
  1504.             andrc(reg1, 1)
  1505.  
  1506.         |IL.opORD:
  1507.             UnOp(reg1);
  1508.             test(reg1);
  1509.             setcc(setne, reg1);
  1510.             andrc(reg1, 1)
  1511.  
  1512.         |IL.opABS:
  1513.             UnOp(reg1);
  1514.             test(reg1);
  1515.             OutByte2(7DH, 03H); // jge L
  1516.             neg(reg1)
  1517.             // L:
  1518.  
  1519.         |IL.opEQB, IL.opNEB:
  1520.             BinOp(reg1, reg2);
  1521.             drop;
  1522.             test(reg1);
  1523.             label := NewLabel();
  1524.             jcc(je, label);
  1525.             movrc(reg1, 1);
  1526.             X86.SetLabel(label);
  1527.             test(reg2);
  1528.             label := NewLabel();
  1529.             jcc(je, label);
  1530.             movrc(reg2, 1);
  1531.             X86.SetLabel(label);
  1532.             cmprr(reg1, reg2);
  1533.             IF opcode = IL.opEQB THEN
  1534.                 setcc(sete, reg1)
  1535.             ELSE
  1536.                 setcc(setne, reg1)
  1537.             END;
  1538.             andrc(reg1, 1)
  1539.  
  1540.         |IL.opMULSC:
  1541.             UnOp(reg1);
  1542.             andrc(reg1, param2)
  1543.  
  1544.         |IL.opDIVSC, IL.opADDSL, IL.opADDSR:
  1545.             UnOp(reg1);
  1546.             Rex(reg1, 0);
  1547.             OutByte2(81H + short(param2), 0C8H + 28H * ORD(opcode = IL.opDIVSC) + reg1 MOD 8); // or/xor reg1, param2
  1548.             OutIntByte(param2)
  1549.  
  1550.         |IL.opSUBSL:
  1551.             UnOp(reg1);
  1552.             not(reg1);
  1553.             andrc(reg1, param2)
  1554.  
  1555.         |IL.opSUBSR:
  1556.             UnOp(reg1);
  1557.             andrc(reg1, ORD(-BITS(param2)))
  1558.  
  1559.         |IL.opMULS:
  1560.             BinOp(reg1, reg2);
  1561.             and(reg1, reg2);
  1562.             drop
  1563.  
  1564.         |IL.opDIVS:
  1565.             BinOp(reg1, reg2);
  1566.             xor(reg1, reg2);
  1567.             drop
  1568.  
  1569.         |IL.opUMINS:
  1570.             UnOp(reg1);
  1571.             not(reg1)
  1572.  
  1573.         |IL.opCOPY:
  1574.             PushAll(2);
  1575.             pushc(param2);
  1576.             CallRTL(IL._move2)
  1577.  
  1578.         |IL.opMOVE:
  1579.             PushAll(3);
  1580.             CallRTL(IL._move2)
  1581.  
  1582.         |IL.opCOPYA:
  1583.             PushAll(4);
  1584.             pushc(param2);
  1585.             CallRTL(IL._arrcpy);
  1586.             GetRegA
  1587.  
  1588.         |IL.opCOPYS:
  1589.             PushAll(4);
  1590.             pushc(param2);
  1591.             CallRTL(IL._strcpy)
  1592.  
  1593.         |IL.opROT:
  1594.             PushAll(0);
  1595.             push(rsp);
  1596.             pushc(param2);
  1597.             CallRTL(IL._rot)
  1598.  
  1599.         |IL.opNEW:
  1600.             PushAll(1);
  1601.             n := param2 + 16;
  1602.             ASSERT(UTILS.Align(n, 64));
  1603.             pushc(n);
  1604.             pushc(param1);
  1605.             CallRTL(IL._new)
  1606.  
  1607.         |IL.opDISP:
  1608.             PushAll(1);
  1609.             CallRTL(IL._dispose)
  1610.  
  1611.         |IL.opPUSHT:
  1612.             UnOp(reg1);
  1613.             reg2 := GetAnyReg();
  1614.             movrm(reg2, reg1, -8)
  1615.  
  1616.         |IL.opISREC:
  1617.             PushAll(2);
  1618.             pushc(param2 * tcount);
  1619.             CallRTL(IL._isrec);
  1620.             GetRegA
  1621.  
  1622.         |IL.opIS:
  1623.             PushAll(1);
  1624.             pushc(param2 * tcount);
  1625.             CallRTL(IL._is);
  1626.             GetRegA
  1627.  
  1628.         |IL.opTYPEGR:
  1629.             PushAll(1);
  1630.             pushc(param2 * tcount);
  1631.             CallRTL(IL._guardrec);
  1632.             GetRegA
  1633.  
  1634.         |IL.opTYPEGP:
  1635.             UnOp(reg1);
  1636.             PushAll(0);
  1637.             push(reg1);
  1638.             pushc(param2 * tcount);
  1639.             CallRTL(IL._guard);
  1640.             GetRegA
  1641.  
  1642.         |IL.opTYPEGD:
  1643.             UnOp(reg1);
  1644.             PushAll(0);
  1645.             pushm(reg1, -8);
  1646.             pushc(param2 * tcount);
  1647.             CallRTL(IL._guardrec);
  1648.             GetRegA
  1649.  
  1650.         |IL.opCASET:
  1651.             push(r10);
  1652.             push(r10);
  1653.             pushc(param2 * tcount);
  1654.             CallRTL(IL._guardrec);
  1655.             pop(r10);
  1656.             test(rax);
  1657.             jcc(jne, param1)
  1658.  
  1659.         |IL.opSAVEP:
  1660.             UnOp(reg1);
  1661.             reg2 := GetAnyReg();
  1662.             lea(reg2, param2, sCODE);
  1663.             movmr(reg1, 0, reg2);
  1664.             drop;
  1665.             drop
  1666.  
  1667.         |IL.opPUSHP:
  1668.             lea(GetAnyReg(), param2, sCODE)
  1669.  
  1670.         |IL.opINC, IL.opDEC:
  1671.             BinOp(reg1, reg2);
  1672.             // add/sub qword[reg2], reg1
  1673.             Rex(reg2, reg1);
  1674.             OutByte2(01H + 28H * ORD(opcode = IL.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
  1675.             drop;
  1676.             drop
  1677.  
  1678.         |IL.opINCC:
  1679.             UnOp(reg1);
  1680.             IF isLong(param2) THEN
  1681.                 reg2 := GetAnyReg();
  1682.                 movrc(reg2, param2);
  1683.                 // add qword[reg1], reg2
  1684.                 Rex(reg1, reg2);
  1685.                 OutByte2(01H, reg1 MOD 8 + (reg2 MOD 8) * 8);
  1686.                 drop
  1687.             ELSIF ABS(param2) = 1 THEN
  1688.                 Rex(reg1, 0);
  1689.                 OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(param2 = -1)) // inc/dec qword[reg1]
  1690.             ELSE
  1691.                 // add qword[reg1], param2
  1692.                 Rex(reg1, 0);
  1693.                 OutByte2(81H + short(param2), reg1 MOD 8);
  1694.                 OutIntByte(param2)
  1695.             END;
  1696.             drop
  1697.  
  1698.         |IL.opDROP:
  1699.             UnOp(reg1);
  1700.             drop
  1701.  
  1702.         |IL.opSAVE, IL.opSAVE64:
  1703.             BinOp(reg2, reg1);
  1704.             movmr(reg1, 0, reg2);
  1705.             drop;
  1706.             drop
  1707.  
  1708.         |IL.opSAVE8:
  1709.             BinOp(reg2, reg1);
  1710.             movmr8(reg1, 0, reg2);
  1711.             drop;
  1712.             drop
  1713.  
  1714.         |IL.opSAVE16:
  1715.             BinOp(reg2, reg1);
  1716.             movmr16(reg1, 0, reg2);
  1717.             drop;
  1718.             drop
  1719.  
  1720.         |IL.opSAVE32:
  1721.             BinOp(reg2, reg1);
  1722.             movmr32(reg1, 0, reg2);
  1723.             drop;
  1724.             drop
  1725.  
  1726.         |IL.opMIN:
  1727.             BinOp(reg1, reg2);
  1728.             cmprr(reg1, reg2);
  1729.             OutByte2(7EH, 3); // jle L
  1730.             mov(reg1, reg2);
  1731.             // L:
  1732.             drop
  1733.  
  1734.         |IL.opMAX:
  1735.             BinOp(reg1, reg2);
  1736.             cmprr(reg1, reg2);
  1737.             OutByte2(7DH, 3);  // jge L
  1738.             mov(reg1, reg2);
  1739.             // L:
  1740.             drop
  1741.  
  1742.         |IL.opMINC:
  1743.             UnOp(reg1);
  1744.             cmprc(reg1, param2);
  1745.             label := NewLabel();
  1746.             jcc(jle, label);
  1747.             movrc(reg1, param2);
  1748.             X86.SetLabel(label)
  1749.  
  1750.         |IL.opMAXC:
  1751.             UnOp(reg1);
  1752.             cmprc(reg1, param2);
  1753.             label := NewLabel();
  1754.             jcc(jge, label);
  1755.             movrc(reg1, param2);
  1756.             X86.SetLabel(label)
  1757.  
  1758.         |IL.opSBOOL:
  1759.             BinOp(reg2, reg1);
  1760.             test(reg2);
  1761.             IF reg1 >= 8 THEN
  1762.                 OutByte(41H)
  1763.             END;
  1764.             OutByte3(0FH, 95H, reg1 MOD 8); // setne byte[reg1]
  1765.             drop;
  1766.             drop
  1767.  
  1768.         |IL.opSBOOLC:
  1769.             UnOp(reg1);
  1770.             IF reg1 >= 8 THEN
  1771.                 OutByte(41H)
  1772.             END;
  1773.             OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0)); // mov byte[reg1], 0/1
  1774.             drop
  1775.  
  1776.         |IL.opODD:
  1777.             UnOp(reg1);
  1778.             andrc(reg1, 1)
  1779.  
  1780.         |IL.opUMINUS:
  1781.             UnOp(reg1);
  1782.             neg(reg1)
  1783.  
  1784.         |IL.opADD:
  1785.             BinOp(reg1, reg2);
  1786.             add(reg1, reg2);
  1787.             drop
  1788.  
  1789.         |IL.opSUB:
  1790.             BinOp(reg1, reg2);
  1791.             sub(reg1, reg2);
  1792.             drop
  1793.  
  1794.         |IL.opSUBR, IL.opSUBL:
  1795.             UnOp(reg1);
  1796.             n := param2;
  1797.             IF n = 1 THEN
  1798.                 decr(reg1)
  1799.             ELSIF n = -1 THEN
  1800.                 incr(reg1)
  1801.             ELSIF n # 0 THEN
  1802.                 subrc(reg1, n)
  1803.             END;
  1804.             IF opcode = IL.opSUBL THEN
  1805.                 neg(reg1)
  1806.             END
  1807.  
  1808.         |IL.opADDL, IL.opADDR:
  1809.             IF param2 # 0 THEN
  1810.                 UnOp(reg1);
  1811.                 IF param2 = 1 THEN
  1812.                     incr(reg1)
  1813.                 ELSIF param2 = -1 THEN
  1814.                     decr(reg1)
  1815.                 ELSE
  1816.                     addrc(reg1, param2)
  1817.                 END
  1818.             END
  1819.  
  1820.         |IL.opDIV:
  1821.             PushAll(2);
  1822.             CallRTL(IL._div);
  1823.             GetRegA
  1824.  
  1825.         |IL.opDIVR:
  1826.             a := param2;
  1827.             IF a > 1 THEN
  1828.                 n := UTILS.Log2(a)
  1829.             ELSIF a < -1 THEN
  1830.                 n := UTILS.Log2(-a)
  1831.             ELSE
  1832.                 n := -1
  1833.             END;
  1834.  
  1835.             IF a = 1 THEN
  1836.  
  1837.             ELSIF a = -1 THEN
  1838.                 UnOp(reg1);
  1839.                 neg(reg1)
  1840.             ELSE
  1841.                 IF n > 0 THEN
  1842.                     UnOp(reg1);
  1843.  
  1844.                     IF a < 0 THEN
  1845.                         reg2 := GetAnyReg();
  1846.                         mov(reg2, reg1);
  1847.                         shiftrc(sar, reg1, n);
  1848.                         sub(reg1, reg2);
  1849.                         drop
  1850.                     ELSE
  1851.                         shiftrc(sar, reg1, n)
  1852.                     END
  1853.  
  1854.                 ELSE
  1855.                     PushAll(1);
  1856.                     pushc(param2);
  1857.                     CallRTL(IL._div);
  1858.                     GetRegA
  1859.                 END
  1860.             END
  1861.  
  1862.         |IL.opDIVL:
  1863.             PushAll(1);
  1864.             pushc(param2);
  1865.             CallRTL(IL._div2);
  1866.             GetRegA
  1867.  
  1868.         |IL.opMOD:
  1869.             PushAll(2);
  1870.             CallRTL(IL._mod);
  1871.             GetRegA
  1872.  
  1873.         |IL.opMODR:
  1874.             a := param2;
  1875.             IF a > 1 THEN
  1876.                 n := UTILS.Log2(a)
  1877.             ELSIF a < -1 THEN
  1878.                 n := UTILS.Log2(-a)
  1879.             ELSE
  1880.                 n := -1
  1881.             END;
  1882.  
  1883.             IF ABS(a) = 1 THEN
  1884.                 UnOp(reg1);
  1885.                 xor(reg1, reg1)
  1886.             ELSE
  1887.                 IF n > 0 THEN
  1888.                     UnOp(reg1);
  1889.                     andrc(reg1, ABS(a) - 1);
  1890.  
  1891.                     IF a < 0 THEN
  1892.                         test(reg1);
  1893.                         label := NewLabel();
  1894.                         jcc(je, label);
  1895.                         addrc(reg1, a);
  1896.                         X86.SetLabel(label)
  1897.                     END
  1898.  
  1899.                 ELSE
  1900.                     PushAll(1);
  1901.                     pushc(param2);
  1902.                     CallRTL(IL._mod);
  1903.                     GetRegA
  1904.                 END
  1905.             END
  1906.  
  1907.         |IL.opMODL:
  1908.             PushAll(1);
  1909.             pushc(param2);
  1910.             CallRTL(IL._mod2);
  1911.             GetRegA
  1912.  
  1913.         |IL.opMUL:
  1914.             BinOp(reg1, reg2);
  1915.             oprr2(0FH, 0AFH, reg2, reg1); // imul reg1, reg2
  1916.             drop
  1917.  
  1918.         |IL.opMULC:
  1919.             UnOp(reg1);
  1920.  
  1921.             a := param2;
  1922.             IF a > 1 THEN
  1923.                 n := UTILS.Log2(a)
  1924.             ELSIF a < -1 THEN
  1925.                 n := UTILS.Log2(-a)
  1926.             ELSE
  1927.                 n := -1
  1928.             END;
  1929.  
  1930.             IF a = 1 THEN
  1931.  
  1932.             ELSIF a = -1 THEN
  1933.                 neg(reg1)
  1934.             ELSIF a = 0 THEN
  1935.                 xor(reg1, reg1)
  1936.             ELSE
  1937.                 IF n > 0 THEN
  1938.                     IF a < 0 THEN
  1939.                         neg(reg1)
  1940.                     END;
  1941.                     shiftrc(shl, reg1, n)
  1942.                 ELSE
  1943.                     // imul reg1, a
  1944.                     Rex(reg1, reg1);
  1945.                     OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
  1946.                     OutIntByte(a)
  1947.                 END
  1948.             END
  1949.  
  1950.         |IL.opADDS:
  1951.             BinOp(reg1, reg2);
  1952.             or(reg1, reg2);
  1953.             drop
  1954.  
  1955.         |IL.opSUBS:
  1956.             BinOp(reg1, reg2);
  1957.             not(reg2);
  1958.             and(reg1, reg2);
  1959.             drop
  1960.  
  1961.         |IL.opNOP:
  1962.  
  1963.         |IL.opSWITCH:
  1964.             UnOp(reg1);
  1965.             IF param2 = 0 THEN
  1966.                 reg2 := rax
  1967.             ELSE
  1968.                 reg2 := r10
  1969.             END;
  1970.             IF reg1 # reg2 THEN
  1971.                 ASSERT(REG.GetReg(R, reg2));
  1972.                 ASSERT(REG.Exchange(R, reg1, reg2));
  1973.                 drop
  1974.             END;
  1975.             drop
  1976.  
  1977.         |IL.opENDSW:
  1978.  
  1979.         |IL.opCASEL:
  1980.             cmprc(rax, param1);
  1981.             jcc(jl, param2)
  1982.  
  1983.         |IL.opCASER:
  1984.             cmprc(rax, param1);
  1985.             jcc(jg, param2)
  1986.  
  1987.         |IL.opCASELR:
  1988.             cmprc(rax, param1);
  1989.             jcc(jl, param2);
  1990.             jcc(jg, cmd.param3)
  1991.  
  1992.         |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR:
  1993.             BinOp(reg1, reg2);
  1994.             xchg(reg2, rcx);
  1995.             Rex(reg1, 0);
  1996.             OutByte(0D3H);
  1997.             X86.shift(opcode, reg1 MOD 8); // shift reg1, cl
  1998.             xchg(reg2, rcx);
  1999.             drop
  2000.  
  2001.         |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1:
  2002.             reg1 := GetAnyReg();
  2003.             movrc(reg1, param2);
  2004.             BinOp(reg1, reg2);
  2005.             xchg(reg1, rcx);
  2006.             Rex(reg2, 0);
  2007.             OutByte(0D3H);
  2008.             X86.shift(opcode, reg2 MOD 8); // shift reg2, cl
  2009.             xchg(reg1, rcx);
  2010.             drop;
  2011.             drop;
  2012.             ASSERT(REG.GetReg(R, reg2))
  2013.  
  2014.         |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2:
  2015.             UnOp(reg1);
  2016.             shiftrc(opcode, reg1, param2 MOD 64)
  2017.  
  2018.         |IL.opGET, IL.opGETC:
  2019.             IF opcode = IL.opGET THEN
  2020.                 BinOp(reg1, reg2)
  2021.             ELSIF opcode = IL.opGETC THEN
  2022.                 UnOp(reg2);
  2023.                 reg1 := GetAnyReg();
  2024.                 movrc(reg1, param1)
  2025.             END;
  2026.             drop;
  2027.             drop;
  2028.             _movrm(reg1, reg1, 0, param2 * 8, FALSE);
  2029.             _movrm(reg1, reg2, 0, param2 * 8, TRUE)
  2030.  
  2031.         |IL.opCHKBYTE:
  2032.             BinOp(reg1, reg2);
  2033.             cmprc(reg1, 256);
  2034.             jcc(jb, param1)
  2035.  
  2036.         |IL.opCHKIDX:
  2037.             UnOp(reg1);
  2038.             cmprc(reg1, param2);
  2039.             jcc(jb, param1)
  2040.  
  2041.         |IL.opCHKIDX2:
  2042.             BinOp(reg1, reg2);
  2043.             IF param2 # -1 THEN
  2044.                 cmprr(reg2, reg1);
  2045.                 mov(reg1, reg2);
  2046.                 drop;
  2047.                 jcc(jb, param1)
  2048.             ELSE
  2049.                 INCL(R.regs, reg1);
  2050.                 DEC(R.top);
  2051.                 R.stk[R.top] := reg2
  2052.             END
  2053.  
  2054.         |IL.opLENGTH:
  2055.             PushAll(2);
  2056.             CallRTL(IL._length);
  2057.             GetRegA
  2058.  
  2059.         |IL.opLENGTHW:
  2060.             PushAll(2);
  2061.             CallRTL(IL._lengthw);
  2062.             GetRegA
  2063.  
  2064.         |IL.opLEN:
  2065.             n := param2;
  2066.             UnOp(reg1);
  2067.             drop;
  2068.             EXCL(R.regs, reg1);
  2069.  
  2070.             WHILE n > 0 DO
  2071.                 UnOp(reg2);
  2072.                 drop;
  2073.                 DEC(n)
  2074.             END;
  2075.  
  2076.             INCL(R.regs, reg1);
  2077.             ASSERT(REG.GetReg(R, reg1))
  2078.  
  2079.         |IL.opCHR:
  2080.             UnOp(reg1);
  2081.             andrc(reg1, 255)
  2082.  
  2083.         |IL.opWCHR:
  2084.             UnOp(reg1);
  2085.             andrc(reg1, 65535)
  2086.  
  2087.         |IL.opEQP, IL.opNEP, IL.opEQIP, IL.opNEIP:
  2088.             UnOp(reg1);
  2089.             reg2 := GetAnyReg();
  2090.  
  2091.             CASE opcode OF
  2092.             |IL.opEQP, IL.opNEP:
  2093.                 lea(reg2, param1, sCODE)
  2094.  
  2095.             |IL.opEQIP, IL.opNEIP:
  2096.                 lea(reg2, param1, sIMP);
  2097.                 movrm(reg2, reg2, 0)
  2098.             END;
  2099.  
  2100.             cmprr(reg1, reg2);
  2101.             drop;
  2102.             drop;
  2103.             reg1 := GetAnyReg();
  2104.  
  2105.             CASE opcode OF
  2106.             |IL.opEQP, IL.opEQIP: setcc(sete,  reg1)
  2107.             |IL.opNEP, IL.opNEIP: setcc(setne, reg1)
  2108.             END;
  2109.  
  2110.             andrc(reg1, 1)
  2111.  
  2112.         |IL.opINCCB, IL.opDECCB:
  2113.             UnOp(reg1);
  2114.             IF reg1 >= 8 THEN
  2115.                 OutByte(41H)
  2116.             END;
  2117.             OutByte3(80H, 28H * ORD(opcode = IL.opDECCB) + reg1 MOD 8, param2 MOD 256); // add/sub byte[reg1], param2 MOD 256
  2118.             drop
  2119.  
  2120.         |IL.opINCB, IL.opDECB:
  2121.             BinOp(reg1, reg2);
  2122.             IF (reg1 >= 8) OR (reg2 >= 8) THEN
  2123.                 OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
  2124.             END;
  2125.             OutByte2(28H * ORD(opcode = IL.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); // add/sub byte[reg2], reg1_8
  2126.             drop;
  2127.             drop
  2128.  
  2129.         |IL.opSAVEIP:
  2130.             UnOp(reg1);
  2131.             reg2 := GetAnyReg();
  2132.             lea(reg2, param2, sIMP);
  2133.             movrm(reg2, reg2, 0);
  2134.             push(reg2);
  2135.             drop;
  2136.             IF reg1 >= 8 THEN
  2137.                 OutByte(41H)
  2138.             END;
  2139.             OutByte2(8FH, reg1 MOD 8); // pop qword[reg1]
  2140.             drop
  2141.  
  2142.         |IL.opCLEANUP:
  2143.             n := param2 * 8;
  2144.             IF n # 0 THEN
  2145.                 addrc(rsp, n)
  2146.             END
  2147.  
  2148.         |IL.opPOPSP:
  2149.             pop(rsp)
  2150.  
  2151.         |IL.opLOADF:
  2152.             UnOp(reg1);
  2153.             INC(xmm);
  2154.             movsdrm(xmm, reg1, 0);
  2155.             drop
  2156.  
  2157.         |IL.opPUSHF:
  2158.             subrc(rsp, 8);
  2159.             movsdmr(rsp, 0, xmm);
  2160.             DEC(xmm)
  2161.  
  2162.         |IL.opCONSTF:
  2163.             float := cmd.float;
  2164.             INC(xmm);
  2165.             reg1 := GetAnyReg();
  2166.             lea(reg1, Numbers_Offs + Numbers_Count * 8, sDATA);
  2167.             movsdrm(xmm, reg1, 0);
  2168.             drop;
  2169.             NewNumber(UTILS.splitf(float, a, b))
  2170.  
  2171.         |IL.opSAVEF:
  2172.             UnOp(reg1);
  2173.             movsdmr(reg1, 0, xmm);
  2174.             DEC(xmm);
  2175.             drop
  2176.  
  2177.         |IL.opADDF, IL.opADDFI:
  2178.             opxx(58H, xmm - 1, xmm);
  2179.             DEC(xmm)
  2180.  
  2181.         |IL.opSUBF:
  2182.             opxx(5CH, xmm - 1, xmm);
  2183.             DEC(xmm)
  2184.  
  2185.         |IL.opSUBFI:
  2186.             opxx(5CH, xmm, xmm - 1);
  2187.             opxx(10H, xmm - 1, xmm);
  2188.             DEC(xmm)
  2189.  
  2190.         |IL.opMULF:
  2191.             opxx(59H, xmm - 1, xmm);
  2192.             DEC(xmm)
  2193.  
  2194.         |IL.opDIVF:
  2195.             opxx(5EH, xmm - 1, xmm);
  2196.             DEC(xmm)
  2197.  
  2198.         |IL.opDIVFI:
  2199.             opxx(5EH, xmm, xmm - 1);
  2200.             opxx(10H, xmm - 1, xmm);
  2201.             DEC(xmm)
  2202.  
  2203.         |IL.opUMINF:
  2204.             reg1 := GetAnyReg();
  2205.             lea(reg1, Numbers_Offs, sDATA);
  2206.             OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // xorpd xmm, xmmword[reg1]
  2207.             OutByte2(57H, reg1 MOD 8 + (xmm MOD 8) * 8);
  2208.             drop
  2209.  
  2210.         |IL.opFABS:
  2211.             reg1 := GetAnyReg();
  2212.             lea(reg1, Numbers_Offs + 16, sDATA);
  2213.             OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // andpd xmm, xmmword[reg1]
  2214.             OutByte2(54H, reg1 MOD 8 + (xmm MOD 8) * 8);
  2215.             drop
  2216.  
  2217.         |IL.opFLT:
  2218.             UnOp(reg1);
  2219.             INC(xmm);
  2220.             OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); // cvtsi2sd xmm, reg1
  2221.             OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
  2222.             drop
  2223.  
  2224.         |IL.opFLOOR:
  2225.             reg1 := GetAnyReg();
  2226.             subrc(rsp, 8);
  2227.             OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); // stmxcsr dword[rsp+4];
  2228.             OutByte2(00FH, 0AEH); OutByte2(01CH, 024H);       // stmxcsr dword[rsp];
  2229.             OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); // and dword[rsp],11111111111111111001111111111111b;
  2230.             OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); // or dword[rsp],00000000000000000010000000000000b;
  2231.             OutByte2(00FH, 0AEH); OutByte2(014H, 024H); // ldmxcsr dword[rsp];
  2232.             OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); // cvtsd2si reg1, xmm
  2233.             OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
  2234.             OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); // ldmxcsr dword[rsp+4];
  2235.             addrc(rsp, 8);
  2236.             DEC(xmm)
  2237.  
  2238.         |IL.opEQF .. IL.opGEF:
  2239.             fcmp(opcode, xmm);
  2240.             DEC(xmm, 2)
  2241.  
  2242.         |IL.opINF:
  2243.             INC(xmm);
  2244.             reg1 := GetAnyReg();
  2245.             lea(reg1, Numbers_Offs + 32, sDATA);
  2246.             movsdrm(xmm, reg1, 0);
  2247.             drop
  2248.  
  2249.         |IL.opPACK, IL.opPACKC:
  2250.             IF opcode = IL.opPACK THEN
  2251.                 BinOp(reg1, reg2)
  2252.             ELSE
  2253.                 UnOp(reg1);
  2254.                 reg2 := GetAnyReg();
  2255.                 movrc(reg2, param2)
  2256.             END;
  2257.             push(reg1);
  2258.             movrm(reg1, reg1, 0);
  2259.             shiftrc(shl, reg1, 1);
  2260.             shiftrc(shr, reg1, 53);
  2261.             add(reg1, reg2);
  2262.             andrc(reg1, ORD({0..10}));
  2263.             shiftrc(shl, reg1, 52);
  2264.             movrm(reg2, rsp, 0);
  2265.             movrm(reg2, reg2, 0);
  2266.  
  2267.             push(reg1);
  2268.             lea(reg1, Numbers_Offs + 40, sDATA); // {0..51, 63}
  2269.             movrm(reg1, reg1, 0);
  2270.             and(reg2, reg1);
  2271.             pop(reg1);
  2272.  
  2273.             or(reg2, reg1);
  2274.             pop(reg1);
  2275.             movmr(reg1, 0, reg2);
  2276.             drop;
  2277.             drop
  2278.  
  2279.         |IL.opUNPK, IL.opLADR_UNPK:
  2280.  
  2281.             IF opcode = IL.opLADR_UNPK THEN
  2282.                 n := param2 * 8;
  2283.                 UnOp(reg1);
  2284.                 reg2 := GetVarReg(param2);
  2285.                 regVar := reg2 # -1;
  2286.                 IF ~regVar THEN
  2287.                     reg2 := GetAnyReg();
  2288.                     Rex(0, reg2);
  2289.                     OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8);  // lea reg2, qword[rbp+n]
  2290.                     OutIntByte(n)
  2291.                 END
  2292.             ELSE
  2293.                 BinOp(reg1, reg2);
  2294.                 regVar := FALSE
  2295.             END;
  2296.  
  2297.             push(reg1);
  2298.             movrm(reg1, reg1, 0);
  2299.             shiftrc(shl, reg1, 1);
  2300.             shiftrc(shr, reg1, 53);
  2301.             subrc(reg1, 1023);
  2302.  
  2303.             IF regVar THEN
  2304.                 mov(reg2, reg1);
  2305.                 reg2 := GetAnyReg()
  2306.             ELSE
  2307.                 movmr(reg2, 0, reg1)
  2308.             END;
  2309.  
  2310.             pop(reg2);
  2311.             movrm(reg1, reg2, 0);
  2312.  
  2313.             push(reg2);
  2314.             lea(reg2, Numbers_Offs + 48, sDATA); // {52..61}
  2315.             movrm(reg2, reg2, 0);
  2316.             or(reg1, reg2);
  2317.             pop(reg2);
  2318.  
  2319.             Rex(reg1, 0);
  2320.             OutByte2(0FH, 0BAH);
  2321.             OutByte2(0F0H + reg1 MOD 8, 3EH); // btr reg1, 62
  2322.             movmr(reg2, 0, reg1);
  2323.             drop;
  2324.             drop
  2325.  
  2326.         |IL.opSADR_PARAM:
  2327.             pushDA(stroffs + param2)
  2328.  
  2329.         |IL.opVADR_PARAM:
  2330.             pushm(rbp, param2 * 8)
  2331.  
  2332.         |IL.opLOAD64_PARAM:
  2333.             UnOp(reg1);
  2334.             pushm(reg1, 0);
  2335.             drop
  2336.  
  2337.         |IL.opLLOAD64_PARAM:
  2338.             reg1 := GetVarReg(param2);
  2339.             IF reg1 # -1 THEN
  2340.                 push(reg1)
  2341.             ELSE
  2342.                 pushm(rbp, param2 * 8)
  2343.             END
  2344.  
  2345.         |IL.opGLOAD64_PARAM:
  2346.             reg2 := GetAnyReg();
  2347.             lea(reg2, param2, sBSS);
  2348.             movrm(reg2, reg2, 0);
  2349.             push(reg2);
  2350.             drop
  2351.  
  2352.         |IL.opCONST_PARAM:
  2353.             pushc(param2)
  2354.  
  2355.         |IL.opGLOAD32_PARAM:
  2356.             reg1 := GetAnyReg();
  2357.             xor(reg1, reg1);
  2358.             lea(reg1, param2, sBSS);
  2359.             movrm32(reg1, reg1, 0);
  2360.             push(reg1);
  2361.             drop
  2362.  
  2363.         |IL.opLOAD32_PARAM:
  2364.             UnOp(reg1);
  2365.             movrm32(reg1, reg1, 0);
  2366.             shiftrc(shl, reg1, 32);
  2367.             shiftrc(shr, reg1, 32);
  2368.             push(reg1);
  2369.             drop
  2370.  
  2371.         |IL.opLLOAD32_PARAM:
  2372.             reg1 := GetAnyReg();
  2373.             xor(reg1, reg1);
  2374.             reg2 := GetVarReg(param2);
  2375.             IF reg2 # -1 THEN
  2376.                 mov(reg1, reg2)
  2377.             ELSE
  2378.                 movrm32(reg1, rbp, param2 * 8)
  2379.             END;
  2380.             push(reg1);
  2381.             drop
  2382.  
  2383.         |IL.opLADR_SAVEC:
  2384.             n := param1 * 8;
  2385.             reg1 := GetVarReg(param1);
  2386.             IF reg1 # -1 THEN
  2387.                 movrc(reg1, param2)
  2388.             ELSE
  2389.                 IF isLong(param2) THEN
  2390.                     reg2 := GetAnyReg();
  2391.                     movrc(reg2, param2);
  2392.                     movmr(rbp, n, reg2);
  2393.                     drop
  2394.                 ELSE
  2395.                     OutByte3(48H, 0C7H, 45H + long(n)); // mov qword[rbp+n],param2
  2396.                     OutIntByte(n);
  2397.                     OutInt(param2)
  2398.                 END
  2399.             END
  2400.  
  2401.         |IL.opGADR_SAVEC:
  2402.             IF isLong(param2) THEN
  2403.                 reg1 := GetAnyReg();
  2404.                 movrc(reg1, param2);
  2405.                 reg2 := GetAnyReg();
  2406.                 lea(reg2, param1, sBSS);
  2407.                 movmr(reg2, 0, reg1);
  2408.                 drop;
  2409.                 drop
  2410.             ELSE
  2411.                 reg2 := GetAnyReg();
  2412.                 lea(reg2, param1, sBSS);
  2413.                 Rex(reg2, 0);
  2414.                 OutByte2(0C7H, reg2 MOD 8); // mov qword[reg2], param2
  2415.                 OutInt(param2);
  2416.                 drop
  2417.             END
  2418.  
  2419.         |IL.opLADR_SAVE:
  2420.             UnOp(reg1);
  2421.             reg2 := GetVarReg(param2);
  2422.             IF reg2 # -1 THEN
  2423.                 mov(reg2, reg1)
  2424.             ELSE
  2425.                 movmr(rbp, param2 * 8, reg1)
  2426.             END;
  2427.             drop
  2428.  
  2429.         |IL.opLADR_INCC:
  2430.             reg1 := GetVarReg(param1);
  2431.             IF isLong(param2) THEN
  2432.                 reg2 := GetAnyReg();
  2433.                 movrc(reg2, param2);
  2434.                 IF reg1 # -1 THEN
  2435.                     add(reg1, reg2)
  2436.                 ELSE
  2437.                     n := param1 * 8;
  2438.                     Rex(0, reg2);
  2439.                     OutByte2(01H, 45H + long(n) + (reg2 MOD 8) * 8);
  2440.                     OutIntByte(n) // add qword[rbp+n],reg2
  2441.                 END;
  2442.                 drop
  2443.             ELSIF ABS(param2) = 1 THEN
  2444.                 IF reg1 # -1 THEN
  2445.                     IF param2 = 1 THEN
  2446.                         incr(reg1)
  2447.                     ELSE
  2448.                         decr(reg1)
  2449.                     END
  2450.                 ELSE
  2451.                     n := param1 * 8;
  2452.                     OutByte3(48H, 0FFH, 45H + 8 * ORD(param2 = -1) + long(n)); // inc/dec qword[rbp+n]
  2453.                     OutIntByte(n)
  2454.                 END
  2455.             ELSE
  2456.                 IF reg1 # -1 THEN
  2457.                     addrc(reg1, param2)
  2458.                 ELSE
  2459.                     n := param1 * 8;
  2460.                     OutByte3(48H, 81H + short(param2), 45H + long(n));
  2461.                     OutIntByte(n);
  2462.                     OutIntByte(param2) // add qword[rbp+n],param2
  2463.                 END
  2464.             END
  2465.  
  2466.         |IL.opLADR_INCCB, IL.opLADR_DECCB:
  2467.             reg1 := GetVarReg(param1);
  2468.             param2 := param2 MOD 256;
  2469.             IF reg1 # -1 THEN
  2470.                 IF opcode = IL.opLADR_DECCB THEN
  2471.                     subrc(reg1, param2)
  2472.                 ELSE
  2473.                     addrc(reg1, param2)
  2474.                 END;
  2475.                 andrc(reg1, 255)
  2476.             ELSE
  2477.                 n := param1 * 8;
  2478.                 OutByte2(80H, 45H + long(n) + 28H * ORD(opcode = IL.opLADR_DECCB));
  2479.                 OutIntByte(n);
  2480.                 OutByte(param2) // add/sub byte[rbp+n],param2
  2481.             END
  2482.  
  2483.         |IL.opLADR_INC, IL.opLADR_DEC:
  2484.             UnOp(reg1);
  2485.             reg2 := GetVarReg(param2);
  2486.             IF reg2 # -1 THEN
  2487.                 IF opcode = IL.opLADR_DEC THEN
  2488.                     sub(reg2, reg1)
  2489.                 ELSE
  2490.                     add(reg2, reg1)
  2491.                 END
  2492.             ELSE
  2493.                 n := param2 * 8;
  2494.                 Rex(0, reg1);
  2495.                 OutByte2(01H + 28H * ORD(opcode = IL.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
  2496.                 OutIntByte(n) // add/sub qword[rbp+n],reg1
  2497.             END;
  2498.             drop
  2499.  
  2500.         |IL.opLADR_INCB, IL.opLADR_DECB:
  2501.             UnOp(reg1);
  2502.             reg2 := GetVarReg(param2);
  2503.             IF reg2 # -1 THEN
  2504.                 IF opcode = IL.opLADR_DECB THEN
  2505.                     sub(reg2, reg1)
  2506.                 ELSE
  2507.                     add(reg2, reg1)
  2508.                 END;
  2509.                 andrc(reg2, 255)
  2510.             ELSE
  2511.                 n := param2 * 8;
  2512.                 IF reg1 >= 8 THEN
  2513.                     OutByte(44H)
  2514.                 END;
  2515.                 OutByte2(28H * ORD(opcode = IL.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
  2516.                 OutIntByte(n) // add/sub byte[rbp+n], reg1_8
  2517.             END;
  2518.             drop
  2519.  
  2520.         |IL.opLADR_INCL, IL.opLADR_EXCL:
  2521.             UnOp(reg1);
  2522.             cmprc(reg1, 64);
  2523.             reg2 := GetVarReg(param2);
  2524.             IF reg2 # -1 THEN
  2525.                 OutByte2(73H, 4); // jnb L
  2526.                 oprr2(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), reg2, reg1) // bts/btr reg2, reg1
  2527.             ELSE
  2528.                 n := param2 * 8;
  2529.                 OutByte2(73H, 5 + 3 * ORD(~isByte(n))); // jnb L
  2530.                 Rex(0, reg1);
  2531.                 OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
  2532.                 OutIntByte(n) // bts/btr qword[rbp+n], reg1
  2533.             END;
  2534.             // L:
  2535.             drop
  2536.  
  2537.         |IL.opLADR_INCLC, IL.opLADR_EXCLC:
  2538.             reg1 := GetVarReg(param1);
  2539.             IF reg1 # -1 THEN
  2540.                 Rex(reg1, 0);
  2541.                 OutByte3(0FH, 0BAH, 0E8H);  // bts/btr reg1, param2
  2542.                 OutByte2(reg1 MOD 8 + 8 * ORD(opcode = IL.opLADR_EXCLC), param2)
  2543.             ELSE
  2544.                 n := param1 * 8;
  2545.                 OutByte3(48H, 0FH, 0BAH);  // bts/btr qword[rbp+n], param2
  2546.                 OutByte(6DH + long(n) + 8 * ORD(opcode = IL.opLADR_EXCLC));
  2547.                 OutIntByte(n);
  2548.                 OutByte(param2)
  2549.             END
  2550.  
  2551.         |IL.opLOOP, IL.opENDLOOP:
  2552.  
  2553.         END;
  2554.  
  2555.         cmd := cmd.next(COMMAND)
  2556.     END;
  2557.  
  2558.     ASSERT(R.pushed = 0);
  2559.     ASSERT(R.top = -1);
  2560.     ASSERT(xmm = -1)
  2561. END translate;
  2562.  
  2563.  
  2564. PROCEDURE prolog (code: IL.CODES; modname: ARRAY OF CHAR; target, stack_size: INTEGER);
  2565. VAR
  2566.     ModName_Offs, entry, L: INTEGER;
  2567.  
  2568. BEGIN
  2569.     ModName_Offs := tcount * 8 + CHL.Length(code.data);
  2570.     Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
  2571.     ASSERT(UTILS.Align(Numbers_Offs, 16));
  2572.  
  2573.     entry := NewLabel();
  2574.     X86.SetLabel(entry);
  2575.  
  2576.     IF target = mConst.Target_iDLL64 THEN
  2577.         dllret := NewLabel();
  2578.         push(r8);
  2579.         push(rdx);
  2580.         push(rcx);
  2581.         CallRTL(IL._dllentry);
  2582.         test(rax);
  2583.         jcc(je, dllret)
  2584.     END;
  2585.  
  2586.     IF target = mConst.Target_iELF64 THEN
  2587.         push(rsp)
  2588.     ELSE
  2589.         pushc(0)
  2590.     END;
  2591.  
  2592.     lea(rax, entry, sCODE);
  2593.     push(rax);
  2594.     pushDA(0); //TYPES
  2595.     pushc(tcount);
  2596.     pushDA(ModName_Offs); //MODNAME
  2597.     CallRTL(IL._init);
  2598.  
  2599.     IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64} THEN
  2600.         L := NewLabel();
  2601.         pushc(0);
  2602.         push(rsp);
  2603.         pushc(1024 * 1024 * stack_size);
  2604.         pushc(0);
  2605.         CallRTL(IL._new);
  2606.         pop(rax);
  2607.         test(rax);
  2608.         jcc(je, L);
  2609.         addrc(rax, 1024 * 1024 * stack_size - 8);
  2610.         mov(rsp, rax);
  2611.         X86.SetLabel(L)
  2612.     END
  2613. END prolog;
  2614.  
  2615.  
  2616. PROCEDURE epilog (code: IL.CODES; modname: ARRAY OF CHAR; target: INTEGER);
  2617. VAR
  2618.     i, n: INTEGER;
  2619.     number: Number;
  2620.     exp: IL.EXPORT_PROC;
  2621.  
  2622.  
  2623.     PROCEDURE import (imp: LISTS.LIST);
  2624.     VAR
  2625.         lib:  IL.IMPORT_LIB;
  2626.         proc: IL.IMPORT_PROC;
  2627.  
  2628.     BEGIN
  2629.  
  2630.         lib := imp.first(IL.IMPORT_LIB);
  2631.         WHILE lib # NIL DO
  2632.             BIN.Import(prog, lib.name, 0);
  2633.             proc := lib.procs.first(IL.IMPORT_PROC);
  2634.             WHILE proc # NIL DO
  2635.                 BIN.Import(prog, proc.name, proc.label);
  2636.                 proc := proc.next(IL.IMPORT_PROC)
  2637.             END;
  2638.             lib := lib.next(IL.IMPORT_LIB)
  2639.         END
  2640.  
  2641.     END import;
  2642.  
  2643.  
  2644. BEGIN
  2645.     IF target = mConst.Target_iDLL64 THEN
  2646.         X86.SetLabel(dllret);
  2647.         OutByte(0C3H) // ret
  2648.     ELSIF target = mConst.Target_iELFSO64 THEN
  2649.         sofinit := NewLabel();
  2650.         OutByte(0C3H);  // ret
  2651.         X86.SetLabel(sofinit);
  2652.         CallRTL(IL._sofinit);
  2653.         OutByte(0C3H)   // ret
  2654.     ELSE
  2655.         pushc(0);
  2656.         CallRTL(IL._exit)
  2657.     END;
  2658.  
  2659.     X86.fixup;
  2660.  
  2661.     i := 0;
  2662.     WHILE i < tcount DO
  2663.         BIN.PutData64LE(prog, CHL.GetInt(code.types, i));
  2664.         INC(i)
  2665.     END;
  2666.  
  2667.     i := 0;
  2668.     WHILE i < CHL.Length(code.data) DO
  2669.         BIN.PutData(prog, CHL.GetByte(code.data, i));
  2670.         INC(i)
  2671.     END;
  2672.  
  2673.     BIN.PutDataStr(prog, modname);
  2674.     BIN.PutData(prog, 0);
  2675.     n := CHL.Length(prog.data);
  2676.     ASSERT(UTILS.Align(n, 16));
  2677.     i := n - CHL.Length(prog.data);
  2678.     WHILE i > 0 DO
  2679.         BIN.PutData(prog, 0);
  2680.         DEC(i)
  2681.     END;
  2682.     number := Numbers.first(Number);
  2683.     FOR i := 0 TO Numbers_Count - 1 DO
  2684.         BIN.PutData64LE(prog, number.value);
  2685.         number := number.next(Number)
  2686.     END;
  2687.  
  2688.     exp := code.export.first(IL.EXPORT_PROC);
  2689.     WHILE exp # NIL DO
  2690.         BIN.Export(prog, exp.name, exp.label);
  2691.         exp := exp.next(IL.EXPORT_PROC)
  2692.     END;
  2693.  
  2694.     import(code.import)
  2695. END epilog;
  2696.  
  2697.  
  2698. PROCEDURE rload (reg, offs, size: INTEGER);
  2699. BEGIN
  2700.     offs := offs * 8;
  2701.     CASE size OF
  2702.     |1: movzx(reg, rbp, offs, FALSE)
  2703.     |2: movzx(reg, rbp, offs, TRUE)
  2704.     |4: xor(reg, reg); movrm32(reg, rbp, offs)
  2705.     |8: movrm(reg, rbp, offs)
  2706.     END
  2707. END rload;
  2708.  
  2709.  
  2710. PROCEDURE rsave (reg, offs, size: INTEGER);
  2711. BEGIN
  2712.     offs := offs * 8;
  2713.     CASE size OF
  2714.     |1: movmr8(rbp, offs, reg)
  2715.     |2: movmr16(rbp, offs, reg)
  2716.     |4: movmr32(rbp, offs, reg)
  2717.     |8: movmr(rbp, offs, reg)
  2718.     END
  2719. END rsave;
  2720.  
  2721.  
  2722. PROCEDURE CodeGen* (code: IL.CODES; outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
  2723. VAR
  2724.     path, modname, ext: PATHS.PATH;
  2725.  
  2726. BEGIN
  2727.     tcount := CHL.Length(code.types);
  2728.  
  2729.     Win64RegPar[0] := rcx;
  2730.     Win64RegPar[1] := rdx;
  2731.     Win64RegPar[2] := r8;
  2732.     Win64RegPar[3] := r9;
  2733.  
  2734.     SystemVRegPar[0] := rdi;
  2735.     SystemVRegPar[1] := rsi;
  2736.     SystemVRegPar[2] := rdx;
  2737.     SystemVRegPar[3] := rcx;
  2738.     SystemVRegPar[4] := r8;
  2739.     SystemVRegPar[5] := r9;
  2740.  
  2741.     PATHS.split(outname, path, modname, ext);
  2742.     S.append(modname, ext);
  2743.  
  2744.     REG.Init(R, push, pop, mov, xchg, rload, rsave, {rax, r10, r11}, {rcx, rdx, r8, r9});
  2745.  
  2746.     code.bss := MAX(code.bss, MAX(code.dmin - CHL.Length(code.data), 8));
  2747.  
  2748.     Numbers := LISTS.create(NIL);
  2749.     Numbers_Count := 0;
  2750.     NewNumber(ROR(1, 1));      (* 8000000000000000H *)
  2751.     NewNumber(0);
  2752.     NewNumber(ROR(-2, 1));     (* 7FFFFFFFFFFFFFFFH *)
  2753.     NewNumber(-1);
  2754.     NewNumber(ROR(7FFH, 12));  (* +Infinity *)
  2755.     NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1))));  (* {0..51, 63} *)
  2756.     NewNumber(LSR(ASR(ROR(1, 1), 9), 2));  (* {52..61} *)
  2757.  
  2758.     prog := BIN.create(code.lcount);
  2759.     BIN.SetParams(prog, code.bss, 1, WCHR(1), WCHR(0));
  2760.  
  2761.     X86.SetProgram(prog);
  2762.  
  2763.     prolog(code, modname, target, options.stack);
  2764.     translate(code.commands, tcount * 8);
  2765.     epilog(code, modname, target);
  2766.  
  2767.     BIN.fixup(prog);
  2768.     IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
  2769.         PE32.write(prog, outname, options.base, target = mConst.Target_iConsole64, target = mConst.Target_iDLL64, TRUE)
  2770.     ELSIF target IN {mConst.Target_iELF64, mConst.Target_iELFSO64} THEN
  2771.         ELF.write(prog, outname, sofinit, target = mConst.Target_iELFSO64, TRUE)
  2772.     END
  2773. END CodeGen;
  2774.  
  2775.  
  2776. END AMD64.