Subversion Repositories Kolibri OS

Rev

Rev 9847 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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