Subversion Repositories Kolibri OS

Rev

Rev 8859 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. (*
  2.     BSD 2-Clause License
  3.  
  4.     Copyright (c) 2018-2022, 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.             n := param2;
  1156.             IF n = 1 THEN
  1157.                 UnOp(reg1);
  1158.                 push(reg1);
  1159.                 drop
  1160.             ELSE
  1161.                 ASSERT(R.top + 1 <= n);
  1162.                 PushAll(n)
  1163.             END
  1164.  
  1165.         |IL.opJNZ1:
  1166.             UnOp(reg1);
  1167.             test(reg1);
  1168.             jcc(jne, param1)
  1169.  
  1170.         |IL.opJG:
  1171.             UnOp(reg1);
  1172.             test(reg1);
  1173.             jcc(jg, param1)
  1174.  
  1175.         |IL.opJNZ:
  1176.             UnOp(reg1);
  1177.             test(reg1);
  1178.             jcc(jne, param1);
  1179.             drop
  1180.  
  1181.         |IL.opJZ:
  1182.             UnOp(reg1);
  1183.             test(reg1);
  1184.             jcc(je, param1);
  1185.             drop
  1186.  
  1187.         |IL.opIN, IL.opINR:
  1188.             IF opcode = IL.opINR THEN
  1189.                 reg2 := GetAnyReg();
  1190.                 movrc(reg2, param2)
  1191.             END;
  1192.             label := NewLabel();
  1193.             L := NewLabel();
  1194.             BinOp(reg1, reg2);
  1195.             cmprc(reg1, 64);
  1196.             jcc(jb, L);
  1197.             xor(reg1, reg1);
  1198.             X86.jmp(label);
  1199.             X86.SetLabel(L);
  1200.             Rex(reg2, reg1);
  1201.             OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); (* bt reg2, reg1 *)
  1202.             X86.setcc(setc, reg1);
  1203.             andrc(reg1, 1);
  1204.             X86.SetLabel(label);
  1205.             drop
  1206.  
  1207.         |IL.opINL:
  1208.             UnOp(reg1);
  1209.             Rex(reg1, 0);
  1210.             OutByte2(0FH, 0BAH); (* bt reg1, param2 *)
  1211.             OutByte2(0E0H + reg1 MOD 8, param2);
  1212.             X86.setcc(setc, reg1);
  1213.             andrc(reg1, 1)
  1214.  
  1215.         |IL.opNOT:
  1216.             UnOp(reg1);
  1217.             test(reg1);
  1218.             X86.setcc(sete, reg1);
  1219.             andrc(reg1, 1)
  1220.  
  1221.         |IL.opORD:
  1222.             UnOp(reg1);
  1223.             test(reg1);
  1224.             X86.setcc(setne, reg1);
  1225.             andrc(reg1, 1)
  1226.  
  1227.         |IL.opABS:
  1228.             UnOp(reg1);
  1229.             test(reg1);
  1230.             OutByte2(7DH, 03H); (* jge L *)
  1231.             neg(reg1)
  1232.             (* L: *)
  1233.  
  1234.         |IL.opEQB, IL.opNEB:
  1235.             BinOp(reg1, reg2);
  1236.             drop;
  1237.             test(reg1);
  1238.             label := NewLabel();
  1239.             jcc(je, label);
  1240.             movrc(reg1, 1);
  1241.             X86.SetLabel(label);
  1242.             test(reg2);
  1243.             label := NewLabel();
  1244.             jcc(je, label);
  1245.             movrc(reg2, 1);
  1246.             X86.SetLabel(label);
  1247.             cmprr(reg1, reg2);
  1248.             IF opcode = IL.opEQB THEN
  1249.                 X86.setcc(sete, reg1)
  1250.             ELSE
  1251.                 X86.setcc(setne, reg1)
  1252.             END;
  1253.             andrc(reg1, 1)
  1254.  
  1255.         |IL.opMULSC:
  1256.             UnOp(reg1);
  1257.             andrc(reg1, param2)
  1258.  
  1259.         |IL.opDIVSC:
  1260.             UnOp(reg1);
  1261.             xorrc(reg1, param2)
  1262.  
  1263.         |IL.opADDSC:
  1264.             UnOp(reg1);
  1265.             orrc(reg1, param2)
  1266.  
  1267.         |IL.opSUBSL:
  1268.             UnOp(reg1);
  1269.             not(reg1);
  1270.             andrc(reg1, param2)
  1271.  
  1272.         |IL.opSUBSR:
  1273.             UnOp(reg1);
  1274.             andrc(reg1, ORD(-BITS(param2)))
  1275.  
  1276.         |IL.opMULS:
  1277.             BinOp(reg1, reg2);
  1278.             and(reg1, reg2);
  1279.             drop
  1280.  
  1281.         |IL.opDIVS:
  1282.             BinOp(reg1, reg2);
  1283.             xor(reg1, reg2);
  1284.             drop
  1285.  
  1286.         |IL.opUMINS:
  1287.             UnOp(reg1);
  1288.             not(reg1)
  1289.  
  1290.         |IL.opCOPY:
  1291.             IF (0 < param2) & (param2 <= 256) THEN
  1292.                 BinOp(reg1, reg2);
  1293.                 reg3 := GetAnyReg();
  1294.                 FOR n := 0 TO param2 - param2 MOD 8 - 1 BY 8 DO
  1295.                     movrm(reg3, reg1, n);
  1296.                     movmr(reg2, n, reg3)
  1297.                 END;
  1298.                 n := param2 - param2 MOD 8;
  1299.                 IF param2 MOD 8 >= 4 THEN
  1300.                     movrm32(reg3, reg1, n);
  1301.                     movmr32(reg2, n, reg3);
  1302.                     INC(n, 4);
  1303.                     DEC(param2, 4)
  1304.                 END;
  1305.                 IF param2 MOD 8 >= 2 THEN
  1306.                     X86.movrm16(reg3, reg1, n);
  1307.                     X86.movmr16(reg2, n, reg3);
  1308.                     INC(n, 2);
  1309.                     DEC(param2, 2)
  1310.                 END;
  1311.                 IF param2 MOD 8 = 1 THEN
  1312.                     X86.movrm8(reg3, reg1, n);
  1313.                     X86.movmr8(reg2, n, reg3);
  1314.                 END;
  1315.                 drop;
  1316.                 drop;
  1317.                 drop
  1318.             ELSE
  1319.                 PushAll(2);
  1320.                 pushc(param2);
  1321.                 CallRTL(IL._move)
  1322.             END
  1323.  
  1324.         |IL.opMOVE:
  1325.             PushAll(3);
  1326.             CallRTL(IL._move)
  1327.  
  1328.         |IL.opCOPYA:
  1329.             PushAll(4);
  1330.             pushc(param2);
  1331.             CallRTL(IL._arrcpy);
  1332.             GetRegA
  1333.  
  1334.         |IL.opCOPYS:
  1335.             PushAll(4);
  1336.             pushc(param2);
  1337.             CallRTL(IL._strcpy)
  1338.  
  1339.         |IL.opROT:
  1340.             PushAll(0);
  1341.             push(rsp);
  1342.             pushc(param2);
  1343.             CallRTL(IL._rot)
  1344.  
  1345.         |IL.opNEW:
  1346.             PushAll(1);
  1347.             n := param2 + 8;
  1348.             ASSERT(UTILS.Align(n, 8));
  1349.             pushc(n);
  1350.             pushc(param1);
  1351.             CallRTL(IL._new)
  1352.  
  1353.         |IL.opDISP:
  1354.             PushAll(1);
  1355.             CallRTL(IL._dispose)
  1356.  
  1357.         |IL.opPUSHT:
  1358.             UnOp(reg1);
  1359.             movrm(GetAnyReg(), reg1, -8)
  1360.  
  1361.         |IL.opISREC:
  1362.             PushAll(2);
  1363.             pushc(param2 * tcount);
  1364.             CallRTL(IL._isrec);
  1365.             GetRegA
  1366.  
  1367.         |IL.opIS:
  1368.             PushAll(1);
  1369.             pushc(param2 * tcount);
  1370.             CallRTL(IL._is);
  1371.             GetRegA
  1372.  
  1373.         |IL.opTYPEGR:
  1374.             PushAll(1);
  1375.             pushc(param2 * tcount);
  1376.             CallRTL(IL._guardrec);
  1377.             GetRegA
  1378.  
  1379.         |IL.opTYPEGP:
  1380.             UnOp(reg1);
  1381.             PushAll(0);
  1382.             push(reg1);
  1383.             pushc(param2 * tcount);
  1384.             CallRTL(IL._guard);
  1385.             GetRegA
  1386.  
  1387.         |IL.opTYPEGD:
  1388.             UnOp(reg1);
  1389.             PushAll(0);
  1390.             X86.pushm(reg1, -8);
  1391.             pushc(param2 * tcount);
  1392.             CallRTL(IL._guardrec);
  1393.             GetRegA
  1394.  
  1395.         |IL.opCASET:
  1396.             push(rcx);
  1397.             push(rcx);
  1398.             pushc(param2 * tcount);
  1399.             CallRTL(IL._guardrec);
  1400.             pop(rcx);
  1401.             test(rax);
  1402.             jcc(jne, param1)
  1403.  
  1404.         |IL.opSAVEP:
  1405.             UnOp(reg1);
  1406.             reg2 := GetAnyReg();
  1407.             lea(reg2, param2, sCODE);
  1408.             movmr(reg1, 0, reg2);
  1409.             drop;
  1410.             drop
  1411.  
  1412.         |IL.opPUSHP:
  1413.             lea(GetAnyReg(), param2, sCODE)
  1414.  
  1415.         |IL.opINC, IL.opDEC:
  1416.             BinOp(reg1, reg2);
  1417.             (* add/sub qword[reg2], reg1 *)
  1418.             Rex(reg2, reg1);
  1419.             OutByte2(01H + 28H * ORD(opcode = IL.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
  1420.             drop;
  1421.             drop
  1422.  
  1423.         |IL.opINCC:
  1424.             UnOp(reg1);
  1425.             IF isLong(param2) THEN
  1426.                 reg2 := GetAnyReg();
  1427.                 movrc(reg2, param2);
  1428.                 (* add qword[reg1], reg2 *)
  1429.                 Rex(reg1, reg2);
  1430.                 OutByte2(01H, reg1 MOD 8 + (reg2 MOD 8) * 8);
  1431.                 drop
  1432.             ELSIF ABS(param2) = 1 THEN
  1433.                 Rex(reg1, 0);
  1434.                 OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(param2 = -1)) (* inc/dec qword[reg1] *)
  1435.             ELSE
  1436.                 (* add qword[reg1], param2 *)
  1437.                 Rex(reg1, 0);
  1438.                 OutByte2(81H + short(param2), reg1 MOD 8);
  1439.                 OutIntByte(param2)
  1440.             END;
  1441.             drop
  1442.  
  1443.         |IL.opDROP:
  1444.             UnOp(reg1);
  1445.             drop
  1446.  
  1447.         |IL.opSAVE, IL.opSAVE64:
  1448.             BinOp(reg2, reg1);
  1449.             movmr(reg1, 0, reg2);
  1450.             drop;
  1451.             drop
  1452.  
  1453.         |IL.opSAVE8:
  1454.             BinOp(reg2, reg1);
  1455.             X86.movmr8(reg1, 0, reg2);
  1456.             drop;
  1457.             drop
  1458.  
  1459.         |IL.opSAVE16:
  1460.             BinOp(reg2, reg1);
  1461.             X86.movmr16(reg1, 0, reg2);
  1462.             drop;
  1463.             drop
  1464.  
  1465.         |IL.opSAVE32:
  1466.             BinOp(reg2, reg1);
  1467.             movmr32(reg1, 0, reg2);
  1468.             drop;
  1469.             drop
  1470.  
  1471.         |IL.opMAX, IL.opMIN:
  1472.             BinOp(reg1, reg2);
  1473.             cmprr(reg1, reg2);
  1474.             OutByte2(7DH + ORD(opcode = IL.opMIN), 3); (* jge/jle L *)
  1475.             mov(reg1, reg2);
  1476.             (* L: *)
  1477.             drop
  1478.  
  1479.         |IL.opMAXC, IL.opMINC:
  1480.             UnOp(reg1);
  1481.             cmprc(reg1, param2);
  1482.             label := NewLabel();
  1483.             IF opcode = IL.opMINC THEN
  1484.                 cc := jle
  1485.             ELSE
  1486.                 cc := jge
  1487.             END;
  1488.             jcc(cc, label);
  1489.             movrc(reg1, param2);
  1490.             X86.SetLabel(label)
  1491.  
  1492.         |IL.opSBOOL:
  1493.             BinOp(reg2, reg1);
  1494.             test(reg2);
  1495.             IF reg1 >= 8 THEN
  1496.                 OutByte(41H)
  1497.             END;
  1498.             OutByte3(0FH, 95H, reg1 MOD 8); (* setne byte[reg1] *)
  1499.             drop;
  1500.             drop
  1501.  
  1502.         |IL.opSBOOLC:
  1503.             UnOp(reg1);
  1504.             IF reg1 >= 8 THEN
  1505.                 OutByte(41H)
  1506.             END;
  1507.             OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0)); (* mov byte[reg1], 0/1 *)
  1508.             drop
  1509.  
  1510.         |IL.opUMINUS:
  1511.             UnOp(reg1);
  1512.             neg(reg1)
  1513.  
  1514.         |IL.opADD:
  1515.             BinOp(reg1, reg2);
  1516.             add(reg1, reg2);
  1517.             drop
  1518.  
  1519.         |IL.opSUB:
  1520.             BinOp(reg1, reg2);
  1521.             sub(reg1, reg2);
  1522.             drop
  1523.  
  1524.         |IL.opSUBR, IL.opSUBL:
  1525.             UnOp(reg1);
  1526.             IF param2 = 1 THEN
  1527.                 decr(reg1)
  1528.             ELSIF param2 = -1 THEN
  1529.                 incr(reg1)
  1530.             ELSIF param2 # 0 THEN
  1531.                 subrc(reg1, param2)
  1532.             END;
  1533.             IF opcode = IL.opSUBL THEN
  1534.                 neg(reg1)
  1535.             END
  1536.  
  1537.         |IL.opADDC:
  1538.             IF (param2 # 0) & ~isLong(param2) THEN
  1539.                 UnOp(reg1);
  1540.                 next := cmd.next(COMMAND);
  1541.                 CASE next.opcode OF
  1542.                 |IL.opLOAD64:
  1543.                     movrm(reg1, reg1, param2);
  1544.                     cmd := next
  1545.                 |IL.opLOAD32:
  1546.                     movrm32(reg1, reg1, param2);
  1547.                     shiftrc(shl, reg1, 32);
  1548.                     shiftrc(shr, reg1, 32);
  1549.                     cmd := next
  1550.                 |IL.opLOAD16:
  1551.                     movzx(reg1, reg1, param2, TRUE);
  1552.                     cmd := next
  1553.                 |IL.opLOAD8:
  1554.                     movzx(reg1, reg1, param2, FALSE);
  1555.                     cmd := next
  1556.                 |IL.opLOAD64_PARAM:
  1557.                     X86.pushm(reg1, param2);
  1558.                     drop;
  1559.                     cmd := next
  1560.                 ELSE
  1561.                     IF param2 = 1 THEN
  1562.                         incr(reg1)
  1563.                     ELSIF param2 = -1 THEN
  1564.                         decr(reg1)
  1565.                     ELSE
  1566.                         addrc(reg1, param2)
  1567.                     END
  1568.                 END
  1569.             ELSIF isLong(param2) THEN
  1570.                 UnOp(reg1);
  1571.                 addrc(reg1, param2)
  1572.             END
  1573.  
  1574.         |IL.opDIV:
  1575.             PushAll(2);
  1576.             CallRTL(IL._divmod);
  1577.             GetRegA
  1578.  
  1579.         |IL.opDIVR:
  1580.             n := UTILS.Log2(param2);
  1581.             IF n > 0 THEN
  1582.                 UnOp(reg1);
  1583.                 shiftrc(sar, reg1, n)
  1584.             ELSIF n < 0 THEN
  1585.                 PushAll(1);
  1586.                 pushc(param2);
  1587.                 CallRTL(IL._divmod);
  1588.                 GetRegA
  1589.             END
  1590.  
  1591.         |IL.opDIVL:
  1592.             UnOp(reg1);
  1593.             REG.PushAll_1(R);
  1594.             pushc(param2);
  1595.             push(reg1);
  1596.             drop;
  1597.             CallRTL(IL._divmod);
  1598.             GetRegA
  1599.  
  1600.         |IL.opMOD:
  1601.             PushAll(2);
  1602.             CallRTL(IL._divmod);
  1603.             mov(rax, rdx);
  1604.             GetRegA
  1605.  
  1606.         |IL.opMODR:
  1607.             n := UTILS.Log2(param2);
  1608.             IF n > 0 THEN
  1609.                 UnOp(reg1);
  1610.                 andrc(reg1, param2 - 1);
  1611.             ELSIF n < 0 THEN
  1612.                 PushAll(1);
  1613.                 pushc(param2);
  1614.                 CallRTL(IL._divmod);
  1615.                 mov(rax, rdx);
  1616.                 GetRegA
  1617.             ELSE
  1618.                 UnOp(reg1);
  1619.                 xor(reg1, reg1)
  1620.             END
  1621.  
  1622.         |IL.opMODL:
  1623.             UnOp(reg1);
  1624.             REG.PushAll_1(R);
  1625.             pushc(param2);
  1626.             push(reg1);
  1627.             drop;
  1628.             CallRTL(IL._divmod);
  1629.             mov(rax, rdx);
  1630.             GetRegA
  1631.  
  1632.         |IL.opMUL:
  1633.             BinOp(reg1, reg2);
  1634.             oprr2(0FH, 0AFH, reg2, reg1); (* imul reg1, reg2 *)
  1635.             drop
  1636.  
  1637.         |IL.opMULC:
  1638.             IF (cmd.next(COMMAND).opcode = IL.opADD) & ((param2 = 2) OR (param2 = 4) OR (param2 = 8)) THEN
  1639.                 BinOp(reg1, reg2);
  1640.                 OutByte2(48H + 5 * (reg1 DIV 8) + 2 * (reg2 DIV 8), 8DH); (* lea reg1, [reg1 + reg2 * param2] *)
  1641.                 reg1 := reg1 MOD 8;
  1642.                 reg2 := reg2 MOD 8;
  1643.                 OutByte2(04H + reg1 * 8, reg1 + reg2 * 8 + 40H * UTILS.Log2(param2));
  1644.                 drop;
  1645.                 cmd := cmd.next(COMMAND)
  1646.             ELSE
  1647.                 UnOp(reg1);
  1648.  
  1649.                 a := param2;
  1650.                 IF a > 1 THEN
  1651.                     n := UTILS.Log2(a)
  1652.                 ELSIF a < -1 THEN
  1653.                     n := UTILS.Log2(-a)
  1654.                 ELSE
  1655.                     n := -1
  1656.                 END;
  1657.  
  1658.                 IF a = 1 THEN
  1659.  
  1660.                 ELSIF a = -1 THEN
  1661.                     neg(reg1)
  1662.                 ELSIF a = 0 THEN
  1663.                     xor(reg1, reg1)
  1664.                 ELSE
  1665.                     IF n > 0 THEN
  1666.                         IF a < 0 THEN
  1667.                             neg(reg1)
  1668.                         END;
  1669.                         shiftrc(shl, reg1, n)
  1670.                     ELSE
  1671.                         IF isLong(a) THEN
  1672.                             reg2 := GetAnyReg();
  1673.                             movabs(reg2, a);
  1674.                             ASSERT(reg1 # reg2);
  1675.                             oprr2(0FH, 0AFH, reg2, reg1); (* imul reg1, reg2 *)
  1676.                             drop
  1677.                         ELSE
  1678.                             (* imul reg1, a *)
  1679.                             Rex(reg1, reg1);
  1680.                             OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
  1681.                             OutIntByte(a)
  1682.                         END
  1683.                     END
  1684.                 END
  1685.             END
  1686.  
  1687.         |IL.opADDS:
  1688.             BinOp(reg1, reg2);
  1689.             _or(reg1, reg2);
  1690.             drop
  1691.  
  1692.         |IL.opSUBS:
  1693.             BinOp(reg1, reg2);
  1694.             not(reg2);
  1695.             and(reg1, reg2);
  1696.             drop
  1697.  
  1698.         |IL.opNOP, IL.opAND, IL.opOR:
  1699.  
  1700.         |IL.opSWITCH:
  1701.             UnOp(reg1);
  1702.             IF param2 = 0 THEN
  1703.                 reg2 := rax
  1704.             ELSE
  1705.                 reg2 := rcx
  1706.             END;
  1707.             IF reg1 # reg2 THEN
  1708.                 ASSERT(REG.GetReg(R, reg2));
  1709.                 ASSERT(REG.Exchange(R, reg1, reg2));
  1710.                 drop
  1711.             END;
  1712.             drop
  1713.  
  1714.         |IL.opENDSW:
  1715.  
  1716.         |IL.opCASEL:
  1717.             GetRegA;
  1718.             cmprc(rax, param1);
  1719.             jcc(jl, param2);
  1720.             drop
  1721.  
  1722.         |IL.opCASER:
  1723.             GetRegA;
  1724.             cmprc(rax, param1);
  1725.             jcc(jg, param2);
  1726.             drop
  1727.  
  1728.         |IL.opCASELR:
  1729.             GetRegA;
  1730.             cmprc(rax, param1);
  1731.             IF param2 = cmd.param3 THEN
  1732.                 jcc(jne, param2)
  1733.             ELSE
  1734.                 jcc(jl, param2);
  1735.                 jcc(jg, cmd.param3)
  1736.             END;
  1737.             drop
  1738.  
  1739.         |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR:
  1740.             UnOp(reg1);
  1741.             IF reg1 # rcx THEN
  1742.                 ASSERT(REG.GetReg(R, rcx));
  1743.                 ASSERT(REG.Exchange(R, reg1, rcx));
  1744.                 drop
  1745.             END;
  1746.  
  1747.             BinOp(reg1, reg2);
  1748.             ASSERT(reg2 = rcx);
  1749.             Rex(reg1, 0);
  1750.             OutByte(0D3H);
  1751.             X86.shift(opcode, reg1 MOD 8); (* shift reg1, cl *)
  1752.             drop
  1753.  
  1754.         |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1:
  1755.             UnOp(reg1);
  1756.             IF reg1 # rcx THEN
  1757.                 ASSERT(REG.GetReg(R, rcx));
  1758.                 ASSERT(REG.Exchange(R, reg1, rcx));
  1759.                 drop
  1760.             END;
  1761.  
  1762.             reg1 := GetAnyReg();
  1763.             movrc(reg1, param2);
  1764.             BinOp(reg1, reg2);
  1765.             ASSERT(reg1 = rcx);
  1766.             Rex(reg2, 0);
  1767.             OutByte(0D3H);
  1768.             X86.shift(opcode, reg2 MOD 8); (* shift reg2, cl *)
  1769.             drop;
  1770.             drop;
  1771.             ASSERT(REG.GetReg(R, reg2))
  1772.  
  1773.         |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2:
  1774.             UnOp(reg1);
  1775.             shiftrc(opcode, reg1, param2 MOD 64)
  1776.  
  1777.         |IL.opGET, IL.opGETC:
  1778.             IF opcode = IL.opGET THEN
  1779.                 BinOp(reg1, reg2)
  1780.             ELSIF opcode = IL.opGETC THEN
  1781.                 UnOp(reg2);
  1782.                 reg1 := GetAnyReg();
  1783.                 movrc(reg1, param1)
  1784.             END;
  1785.             drop;
  1786.             drop;
  1787.             X86._movrm(reg1, reg1, 0, param2 * 8, FALSE);
  1788.             X86._movrm(reg1, reg2, 0, param2 * 8, TRUE)
  1789.  
  1790.         |IL.opCHKBYTE:
  1791.             BinOp(reg1, reg2);
  1792.             cmprc(reg1, 256);
  1793.             jcc(jb, param1)
  1794.  
  1795.         |IL.opCHKIDX:
  1796.             UnOp(reg1);
  1797.             cmprc(reg1, param2);
  1798.             jcc(jb, param1)
  1799.  
  1800.         |IL.opCHKIDX2:
  1801.             BinOp(reg1, reg2);
  1802.             IF param2 # -1 THEN
  1803.                 cmprr(reg2, reg1);
  1804.                 jcc(jb, param1);
  1805.             END;
  1806.             INCL(R.regs, reg1);
  1807.             DEC(R.top);
  1808.             R.stk[R.top] := reg2
  1809.  
  1810.         |IL.opLENGTH:
  1811.             PushAll(2);
  1812.             CallRTL(IL._length);
  1813.             GetRegA
  1814.  
  1815.         |IL.opLENGTHW:
  1816.             PushAll(2);
  1817.             CallRTL(IL._lengthw);
  1818.             GetRegA
  1819.  
  1820.         |IL.opLEN:
  1821.             n := param2;
  1822.             UnOp(reg1);
  1823.             drop;
  1824.             EXCL(R.regs, reg1);
  1825.  
  1826.             WHILE n > 0 DO
  1827.                 UnOp(reg2);
  1828.                 drop;
  1829.                 DEC(n)
  1830.             END;
  1831.  
  1832.             INCL(R.regs, reg1);
  1833.             ASSERT(REG.GetReg(R, reg1))
  1834.  
  1835.         |IL.opCHR:
  1836.             UnOp(reg1);
  1837.             andrc(reg1, 255)
  1838.  
  1839.         |IL.opWCHR:
  1840.             UnOp(reg1);
  1841.             andrc(reg1, 65535)
  1842.  
  1843.         |IL.opEQP, IL.opNEP, IL.opEQIP, IL.opNEIP:
  1844.             UnOp(reg1);
  1845.             reg2 := GetAnyReg();
  1846.  
  1847.             CASE opcode OF
  1848.             |IL.opEQP, IL.opNEP:
  1849.                 lea(reg2, param1, sCODE)
  1850.  
  1851.             |IL.opEQIP, IL.opNEIP:
  1852.                 lea(reg2, param1, sIMP);
  1853.                 movrm(reg2, reg2, 0)
  1854.             END;
  1855.  
  1856.             cmprr(reg1, reg2);
  1857.             drop;
  1858.             drop;
  1859.             reg1 := GetAnyReg();
  1860.  
  1861.             CASE opcode OF
  1862.             |IL.opEQP, IL.opEQIP: X86.setcc(sete,  reg1)
  1863.             |IL.opNEP, IL.opNEIP: X86.setcc(setne, reg1)
  1864.             END;
  1865.  
  1866.             andrc(reg1, 1)
  1867.  
  1868.         |IL.opINCCB, IL.opDECCB:
  1869.             UnOp(reg1);
  1870.             IF reg1 >= 8 THEN
  1871.                 OutByte(41H)
  1872.             END;
  1873.             OutByte3(80H, 28H * ORD(opcode = IL.opDECCB) + reg1 MOD 8, param2 MOD 256); (* add/sub byte[reg1], param2 MOD 256 *)
  1874.             drop
  1875.  
  1876.         |IL.opINCB, IL.opDECB:
  1877.             BinOp(reg1, reg2);
  1878.             IF (reg1 >= 8) OR (reg2 >= 8) THEN
  1879.                 OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
  1880.             END;
  1881.             OutByte2(28H * ORD(opcode = IL.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); (* add/sub byte[reg2], reg1_8 *)
  1882.             drop;
  1883.             drop
  1884.  
  1885.         |IL.opSAVEIP:
  1886.             UnOp(reg1);
  1887.             reg2 := GetAnyReg();
  1888.             lea(reg2, param2, sIMP);
  1889.             movrm(reg2, reg2, 0);
  1890.             push(reg2);
  1891.             drop;
  1892.             IF reg1 >= 8 THEN
  1893.                 OutByte(41H)
  1894.             END;
  1895.             OutByte2(8FH, reg1 MOD 8); (* pop qword[reg1] *)
  1896.             drop
  1897.  
  1898.         |IL.opCLEANUP:
  1899.             IF param2 # 0 THEN
  1900.                 addrc(rsp, param2 * 8)
  1901.             END
  1902.  
  1903.         |IL.opPOPSP:
  1904.             pop(rsp)
  1905.  
  1906.         |IL.opLOADF:
  1907.             UnOp(reg1);
  1908.             INC(xmm);
  1909.             IF xmm > MAX_XMM THEN
  1910.                 ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR)
  1911.             END;
  1912.             movsdrm(xmm, reg1, 0);
  1913.             drop
  1914.  
  1915.         |IL.opPUSHF:
  1916.             ASSERT(xmm >= 0);
  1917.             subrc(rsp, 8);
  1918.             movsdmr(rsp, 0, xmm);
  1919.             DEC(xmm)
  1920.  
  1921.         |IL.opCONSTF:
  1922.             float := cmd.float;
  1923.             INC(xmm);
  1924.             IF xmm > MAX_XMM THEN
  1925.                 ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR)
  1926.             END;
  1927.             (* movsd xmm, qword ptr [rip + Numbers_Offs + Numbers_Count * 8 + DATA] *)
  1928.             OutByte(0F2H);
  1929.             IF xmm >= 8 THEN
  1930.                 OutByte(44H)
  1931.             END;
  1932.             OutByte3(0FH, 10H, 05H + 8 * (xmm MOD 8));
  1933.             X86.Reloc(sDATA, Numbers_Offs + Numbers_Count * 8);
  1934.             NewNumber(UTILS.splitf(float, a, b))
  1935.  
  1936.         |IL.opSAVEF, IL.opSAVEFI:
  1937.             ASSERT(xmm >= 0);
  1938.             UnOp(reg1);
  1939.             movsdmr(reg1, 0, xmm);
  1940.             DEC(xmm);
  1941.             drop
  1942.  
  1943.         |IL.opADDF:
  1944.             ASSERT(xmm >= 1);
  1945.             opxx(58H, xmm - 1, xmm);
  1946.             DEC(xmm)
  1947.  
  1948.         |IL.opSUBF:
  1949.             ASSERT(xmm >= 1);
  1950.             opxx(5CH, xmm - 1, xmm);
  1951.             DEC(xmm)
  1952.  
  1953.         |IL.opSUBFI:
  1954.             ASSERT(xmm >= 1);
  1955.             opxx(5CH, xmm, xmm - 1);
  1956.             opxx(10H, xmm - 1, xmm);
  1957.             DEC(xmm)
  1958.  
  1959.         |IL.opMULF:
  1960.             ASSERT(xmm >= 1);
  1961.             opxx(59H, xmm - 1, xmm);
  1962.             DEC(xmm)
  1963.  
  1964.         |IL.opDIVF:
  1965.             ASSERT(xmm >= 1);
  1966.             opxx(5EH, xmm - 1, xmm);
  1967.             DEC(xmm)
  1968.  
  1969.         |IL.opDIVFI:
  1970.             ASSERT(xmm >= 1);
  1971.             opxx(5EH, xmm, xmm - 1);
  1972.             opxx(10H, xmm - 1, xmm);
  1973.             DEC(xmm)
  1974.  
  1975.         |IL.opFABS, IL.opUMINF: (* andpd/xorpd xmm, xmmword[rip + Numbers_Offs + (16) + DATA] *)
  1976.             ASSERT(xmm >= 0);
  1977.             OutByte(66H);
  1978.             IF xmm >= 8 THEN
  1979.                 OutByte(44H)
  1980.             END;
  1981.             OutByte3(0FH, 54H + 3 * ORD(opcode = IL.opUMINF), 05H + (xmm MOD 8) * 8);
  1982.             X86.Reloc(sDATA, Numbers_Offs + 16 * ORD(opcode = IL.opFABS))
  1983.  
  1984.         |IL.opFLT:
  1985.             UnOp(reg1);
  1986.             INC(xmm);
  1987.             IF xmm > MAX_XMM THEN
  1988.                 ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR)
  1989.             END;
  1990.             OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); (* cvtsi2sd xmm, reg1 *)
  1991.             OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
  1992.             drop
  1993.  
  1994.         |IL.opFLOOR:
  1995.             ASSERT(xmm >= 0);
  1996.             reg1 := GetAnyReg();
  1997.             subrc(rsp, 8);
  1998.             OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H);                       (* stmxcsr dword[rsp+4];                              *)
  1999.             OutByte2(00FH, 0AEH); OutByte2(01CH, 024H);                             (* stmxcsr dword[rsp];                                *)
  2000.             OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); (* and dword[rsp],11111111111111111001111111111111b;  *)
  2001.             OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); (* or dword[rsp],00000000000000000010000000000000b;   *)
  2002.             OutByte2(00FH, 0AEH); OutByte2(014H, 024H);                             (* ldmxcsr dword[rsp];                                *)
  2003.             OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH);                            (* cvtsd2si reg1, xmm                                 *)
  2004.             OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
  2005.             OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H);                       (* ldmxcsr dword[rsp+4];                              *)
  2006.             addrc(rsp, 8);
  2007.             DEC(xmm)
  2008.  
  2009.         |IL.opEQF .. IL.opGEF:
  2010.             ASSERT(xmm >= 1);
  2011.             fcmp(opcode, xmm);
  2012.             DEC(xmm, 2)
  2013.  
  2014.         |IL.opINF:
  2015.             INC(xmm);
  2016.             IF xmm > MAX_XMM THEN
  2017.                 ERRORS.ErrorMsg(fname, param1, param2, FPR_ERR)
  2018.             END;
  2019.             (* movsd xmm, qword ptr [rip + Numbers_Offs + 32 + DATA] *)
  2020.             OutByte(0F2H);
  2021.             IF xmm >= 8 THEN
  2022.                 OutByte(44H)
  2023.             END;
  2024.             OutByte3(0FH, 10H, 05H + 8 * (xmm MOD 8));
  2025.             X86.Reloc(sDATA, Numbers_Offs + 32)
  2026.  
  2027.         |IL.opPACK, IL.opPACKC:
  2028.             IF opcode = IL.opPACK THEN
  2029.                 BinOp(reg1, reg2)
  2030.             ELSE
  2031.                 UnOp(reg1);
  2032.                 reg2 := GetAnyReg();
  2033.                 movrc(reg2, param2)
  2034.             END;
  2035.             push(reg1);
  2036.             movrm(reg1, reg1, 0);
  2037.             shiftrc(shl, reg1, 1);
  2038.             shiftrc(shr, reg1, 53);
  2039.             add(reg1, reg2);
  2040.             andrc(reg1, ORD({0..10}));
  2041.             shiftrc(shl, reg1, 52);
  2042.             movrm(reg2, rsp, 0);
  2043.             movrm(reg2, reg2, 0);
  2044.  
  2045.             push(reg1);
  2046.             lea(reg1, Numbers_Offs + 40, sDATA); (* {0..51, 63} *)
  2047.             movrm(reg1, reg1, 0);
  2048.             and(reg2, reg1);
  2049.             pop(reg1);
  2050.  
  2051.             _or(reg2, reg1);
  2052.             pop(reg1);
  2053.             movmr(reg1, 0, reg2);
  2054.             drop;
  2055.             drop
  2056.  
  2057.         |IL.opUNPK, IL.opLADR_UNPK:
  2058.  
  2059.             IF opcode = IL.opLADR_UNPK THEN
  2060.                 n := param2 * 8;
  2061.                 UnOp(reg1);
  2062.                 reg2 := GetAnyReg();
  2063.                 Rex(0, reg2);
  2064.                 OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8); (* lea reg2, qword[rbp+n] *)
  2065.                 OutIntByte(n)
  2066.             ELSE
  2067.                 BinOp(reg1, reg2)
  2068.             END;
  2069.  
  2070.             push(reg1);
  2071.             movrm(reg1, reg1, 0);
  2072.             shiftrc(shl, reg1, 1);
  2073.             shiftrc(shr, reg1, 53);
  2074.             subrc(reg1, 1023);
  2075.  
  2076.             movmr(reg2, 0, reg1);
  2077.  
  2078.             pop(reg2);
  2079.             movrm(reg1, reg2, 0);
  2080.  
  2081.             push(reg2);
  2082.             lea(reg2, Numbers_Offs + 48, sDATA); (* {52..61} *)
  2083.             movrm(reg2, reg2, 0);
  2084.             _or(reg1, reg2);
  2085.             pop(reg2);
  2086.  
  2087.             Rex(reg1, 0);
  2088.             OutByte2(0FH, 0BAH);
  2089.             OutByte2(0F0H + reg1 MOD 8, 3EH); (* btr reg1, 62 *)
  2090.             movmr(reg2, 0, reg1);
  2091.             drop;
  2092.             drop
  2093.  
  2094.         |IL.opSADR_PARAM:
  2095.             pushDA(stroffs + param2)
  2096.  
  2097.         |IL.opVADR_PARAM:
  2098.             X86.pushm(rbp, param2 * 8)
  2099.  
  2100.         |IL.opLOAD64_PARAM:
  2101.             UnOp(reg1);
  2102.             X86.pushm(reg1, 0);
  2103.             drop
  2104.  
  2105.         |IL.opLLOAD64_PARAM:
  2106.             X86.pushm(rbp, param2 * 8)
  2107.  
  2108.         |IL.opGLOAD64_PARAM:
  2109.             OutByte2(0FFH, 35H); (* push qword[rip + param2 + BSS] *)
  2110.             X86.Reloc(sBSS, param2)
  2111.  
  2112.         |IL.opCONST_PARAM:
  2113.             pushc(param2)
  2114.  
  2115.         |IL.opGLOAD32_PARAM, IL.opLOAD32_PARAM:
  2116.             IF opcode = IL.opGLOAD32_PARAM THEN
  2117.                 reg1 := GetAnyReg();
  2118.                 lea(reg1, param2, sBSS)
  2119.             ELSE
  2120.                 UnOp(reg1)
  2121.             END;
  2122.             movrm32(reg1, reg1, 0);
  2123.             shiftrc(shl, reg1, 32);
  2124.             shiftrc(shr, reg1, 32);
  2125.             push(reg1);
  2126.             drop
  2127.  
  2128.         |IL.opLLOAD32_PARAM:
  2129.             reg1 := GetAnyReg();
  2130.             movrm32(reg1, rbp, param2 * 8);
  2131.             shiftrc(shl, reg1, 32);
  2132.             shiftrc(shr, reg1, 32);
  2133.             push(reg1);
  2134.             drop
  2135.  
  2136.         |IL.opLADR_SAVEC:
  2137.             n := param1 * 8;
  2138.             IF isLong(param2) THEN
  2139.                 reg2 := GetAnyReg();
  2140.                 movrc(reg2, param2);
  2141.                 movmr(rbp, n, reg2);
  2142.                 drop
  2143.             ELSE
  2144.                 OutByte3(48H, 0C7H, 45H + long(n)); (* mov qword[rbp+n], param2 *)
  2145.                 OutIntByte(n);
  2146.                 OutInt(param2)
  2147.             END
  2148.  
  2149.         |IL.opGADR_SAVEC:
  2150.             IF isLong(param2) THEN
  2151.                 reg1 := GetAnyReg();
  2152.                 movrc(reg1, param2);
  2153.                 reg2 := GetAnyReg();
  2154.                 lea(reg2, param1, sBSS);
  2155.                 movmr(reg2, 0, reg1);
  2156.                 drop;
  2157.                 drop
  2158.             ELSE
  2159.                 (* mov qword[rip + param1 - 4 + BSS], param2 *)
  2160.                 OutByte3(48H, 0C7H, 05H);
  2161.                 X86.Reloc(sBSS, param1 - 4);
  2162.                 OutInt(param2)
  2163.             END
  2164.  
  2165.         |IL.opLADR_SAVE:
  2166.             UnOp(reg1);
  2167.             movmr(rbp, param2 * 8, reg1);
  2168.             drop
  2169.  
  2170.         |IL.opLADR_INCC:
  2171.             IF isLong(param2) THEN
  2172.                 reg2 := GetAnyReg();
  2173.                 movrc(reg2, param2);
  2174.                 n := param1 * 8;
  2175.                 Rex(0, reg2);
  2176.                 OutByte2(01H, 45H + long(n) + (reg2 MOD 8) * 8);
  2177.                 OutIntByte(n); (* add qword[rbp+n], reg2 *)
  2178.                 drop
  2179.             ELSIF ABS(param2) = 1 THEN
  2180.                 n := param1 * 8;
  2181.                 OutByte3(48H, 0FFH, 45H + 8 * ORD(param2 = -1) + long(n)); (* inc/dec qword[rbp+n] *)
  2182.                 OutIntByte(n)
  2183.             ELSE
  2184.                 n := param1 * 8;
  2185.                 OutByte3(48H, 81H + short(param2), 45H + long(n));
  2186.                 OutIntByte(n);
  2187.                 OutIntByte(param2) (* add qword[rbp+n], param2 *)
  2188.             END
  2189.  
  2190.         |IL.opLADR_INCCB, IL.opLADR_DECCB:
  2191.             param2 := param2 MOD 256;
  2192.             n := param1 * 8;
  2193.             OutByte2(80H, 45H + long(n) + 28H * ORD(opcode = IL.opLADR_DECCB));
  2194.             OutIntByte(n);
  2195.             OutByte(param2) (* add/sub byte[rbp+n], param2 *)
  2196.  
  2197.         |IL.opLADR_INC, IL.opLADR_DEC:
  2198.             UnOp(reg1);
  2199.             n := param2 * 8;
  2200.             Rex(0, reg1);
  2201.             OutByte2(01H + 28H * ORD(opcode = IL.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
  2202.             OutIntByte(n); (* add/sub qword[rbp+n], reg1 *)
  2203.             drop
  2204.  
  2205.         |IL.opLADR_INCB, IL.opLADR_DECB:
  2206.             UnOp(reg1);
  2207.             n := param2 * 8;
  2208.             IF reg1 >= 8 THEN
  2209.                 OutByte(44H)
  2210.             END;
  2211.             OutByte2(28H * ORD(opcode = IL.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
  2212.             OutIntByte(n); (* add/sub byte[rbp+n], reg1_8 *)
  2213.             drop
  2214.  
  2215.         |IL.opLADR_INCL, IL.opLADR_EXCL:
  2216.             UnOp(reg1);
  2217.             cmprc(reg1, 64);
  2218.             n := param2 * 8;
  2219.             OutByte2(73H, 5 + 3 * ORD(~X86.isByte(n))); (* jnb L *)
  2220.             Rex(0, reg1);
  2221.             OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
  2222.             OutIntByte(n); (* bts/btr qword[rbp+n], reg1 *)
  2223.             (* L: *)
  2224.             drop
  2225.  
  2226.         |IL.opLADR_INCLC, IL.opLADR_EXCLC:
  2227.             n := param1 * 8;
  2228.             OutByte3(48H, 0FH, 0BAH); (* bts/btr qword[rbp+n], param2 *)
  2229.             OutByte(6DH + long(n) + 8 * ORD(opcode = IL.opLADR_EXCLC));
  2230.             OutIntByte(n);
  2231.             OutByte(param2)
  2232.  
  2233.         |IL.opFNAME:
  2234.             fname := cmd(IL.FNAMECMD).fname
  2235.  
  2236.         END;
  2237.  
  2238.         cmd := cmd.next(COMMAND)
  2239.     END;
  2240.  
  2241.     ASSERT(R.pushed = 0);
  2242.     ASSERT(R.top = -1);
  2243.     ASSERT(xmm = -1)
  2244. END translate;
  2245.  
  2246.  
  2247. PROCEDURE prolog (modname: ARRAY OF CHAR; target, stack_size: INTEGER);
  2248. VAR
  2249.     ModName_Offs, entry, L: INTEGER;
  2250.  
  2251. BEGIN
  2252.     ModName_Offs := tcount * 8 + CHL.Length(IL.codes.data);
  2253.     Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
  2254.     ASSERT(UTILS.Align(Numbers_Offs, 16));
  2255.  
  2256.     entry := NewLabel();
  2257.     X86.SetLabel(entry);
  2258.  
  2259.     IF target = TARGETS.Win64DLL THEN
  2260.         dllret := NewLabel();
  2261.         push(r8);
  2262.         push(rdx);
  2263.         push(rcx);
  2264.         CallRTL(IL._dllentry);
  2265.         test(rax);
  2266.         jcc(je, dllret);
  2267.         pushc(0)
  2268.     ELSIF target = TARGETS.Linux64 THEN
  2269.         push(rsp)
  2270.     ELSE
  2271.         pushc(0)
  2272.     END;
  2273.  
  2274.     lea(rax, entry, sCODE);
  2275.     push(rax);
  2276.     pushDA(0); (* TYPES *)
  2277.     pushc(tcount);
  2278.     pushDA(ModName_Offs); (* MODNAME *)
  2279.     CallRTL(IL._init);
  2280.  
  2281.     IF target IN {TARGETS.Win64C, TARGETS.Win64GUI, TARGETS.Linux64} THEN
  2282.         L := NewLabel();
  2283.         pushc(0);
  2284.         push(rsp);
  2285.         pushc(1024 * 1024 * stack_size);
  2286.         pushc(0);
  2287.         CallRTL(IL._new);
  2288.         pop(rax);
  2289.         test(rax);
  2290.         jcc(je, L);
  2291.         GetRegA;
  2292.         addrc(rax, 1024 * 1024 * stack_size - 8);
  2293.         drop;
  2294.         mov(rsp, rax);
  2295.         X86.SetLabel(L)
  2296.     END
  2297. END prolog;
  2298.  
  2299.  
  2300. PROCEDURE epilog (modname: ARRAY OF CHAR; target: INTEGER);
  2301. VAR
  2302.     i, n: INTEGER;
  2303.     number: Number;
  2304.     exp: IL.EXPORT_PROC;
  2305.  
  2306.  
  2307.     PROCEDURE _import (imp: LISTS.LIST);
  2308.     VAR
  2309.         lib:  IL.IMPORT_LIB;
  2310.         proc: IL.IMPORT_PROC;
  2311.  
  2312.     BEGIN
  2313.  
  2314.         lib := imp.first(IL.IMPORT_LIB);
  2315.         WHILE lib # NIL DO
  2316.             BIN.Import(prog, lib.name, 0);
  2317.             proc := lib.procs.first(IL.IMPORT_PROC);
  2318.             WHILE proc # NIL DO
  2319.                 BIN.Import(prog, proc.name, proc.label);
  2320.                 proc := proc.next(IL.IMPORT_PROC)
  2321.             END;
  2322.             lib := lib.next(IL.IMPORT_LIB)
  2323.         END
  2324.  
  2325.     END _import;
  2326.  
  2327.  
  2328. BEGIN
  2329.     IF target = TARGETS.Win64DLL THEN
  2330.         X86.SetLabel(dllret);
  2331.         X86.ret
  2332.     ELSIF target = TARGETS.Linux64SO THEN
  2333.         sofinit := NewLabel();
  2334.         X86.ret;
  2335.         X86.SetLabel(sofinit);
  2336.         CallRTL(IL._sofinit);
  2337.         X86.ret
  2338.     ELSE
  2339.         pushc(0);
  2340.         CallRTL(IL._exit)
  2341.     END;
  2342.  
  2343.     X86.fixup;
  2344.  
  2345.     i := 0;
  2346.     WHILE i < tcount DO
  2347.         BIN.PutData64LE(prog, CHL.GetInt(IL.codes.types, i));
  2348.         INC(i)
  2349.     END;
  2350.  
  2351.     i := 0;
  2352.     WHILE i < CHL.Length(IL.codes.data) DO
  2353.         BIN.PutData(prog, CHL.GetByte(IL.codes.data, i));
  2354.         INC(i)
  2355.     END;
  2356.  
  2357.     BIN.PutDataStr(prog, modname);
  2358.     BIN.PutData(prog, 0);
  2359.     n := CHL.Length(prog.data);
  2360.     ASSERT(UTILS.Align(n, 16));
  2361.     i := n - CHL.Length(prog.data);
  2362.     WHILE i > 0 DO
  2363.         BIN.PutData(prog, 0);
  2364.         DEC(i)
  2365.     END;
  2366.     number := Numbers.first(Number);
  2367.     FOR i := 0 TO Numbers_Count - 1 DO
  2368.         BIN.PutData64LE(prog, number.value);
  2369.         number := number.next(Number)
  2370.     END;
  2371.  
  2372.     exp := IL.codes.export.first(IL.EXPORT_PROC);
  2373.     WHILE exp # NIL DO
  2374.         BIN.Export(prog, exp.name, exp.label);
  2375.         exp := exp.next(IL.EXPORT_PROC)
  2376.     END;
  2377.  
  2378.     _import(IL.codes._import)
  2379. END epilog;
  2380.  
  2381.  
  2382. PROCEDURE CodeGen* (outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
  2383. VAR
  2384.     path, modname, ext: PATHS.PATH;
  2385.  
  2386. BEGIN
  2387.     Xmm[0] := 0;
  2388.     tcount := CHL.Length(IL.codes.types);
  2389.  
  2390.     Win64RegPar[0] := rcx;
  2391.     Win64RegPar[1] := rdx;
  2392.     Win64RegPar[2] := r8;
  2393.     Win64RegPar[3] := r9;
  2394.  
  2395.     SystemVRegPar[0] := rdi;
  2396.     SystemVRegPar[1] := rsi;
  2397.     SystemVRegPar[2] := rdx;
  2398.     SystemVRegPar[3] := rcx;
  2399.     SystemVRegPar[4] := r8;
  2400.     SystemVRegPar[5] := r9;
  2401.  
  2402.     PATHS.split(outname, path, modname, ext);
  2403.     S.append(modname, ext);
  2404.  
  2405.     REG.Init(R, push, pop, mov, xchg, {rax, rcx, rdx, r8, r9, r10, r11});
  2406.  
  2407.     IL.set_bss(MAX(IL.codes.bss, MAX(IL.codes.dmin - CHL.Length(IL.codes.data), 8)));
  2408.  
  2409.     Numbers := LISTS.create(NIL);
  2410.     Numbers_Count := 0;
  2411.     NewNumber(ROR(1, 1));      (* 8000000000000000H *)
  2412.     NewNumber(0);
  2413.     NewNumber(ROR(-2, 1));     (* 7FFFFFFFFFFFFFFFH *)
  2414.     NewNumber(-1);
  2415.     NewNumber(ROR(7FFH, 12));  (* +Infinity *)
  2416.     NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1))));  (* {0..51, 63} *)
  2417.     NewNumber(LSR(ASR(ROR(1, 1), 9), 2));  (* {52..61} *)
  2418.  
  2419.     prog := BIN.create(IL.codes.lcount);
  2420.     BIN.SetParams(prog, IL.codes.bss, 1, WCHR(1), WCHR(0));
  2421.  
  2422.     X86.SetProgram(prog);
  2423.  
  2424.     prolog(modname, target, options.stack);
  2425.     translate(IL.codes.commands, tcount * 8);
  2426.     epilog(modname, target);
  2427.  
  2428.     BIN.fixup(prog);
  2429.     IF TARGETS.OS = TARGETS.osWIN64 THEN
  2430.         PE32.write(prog, outname, target = TARGETS.Win64C, target = TARGETS.Win64DLL, TRUE)
  2431.     ELSIF TARGETS.OS = TARGETS.osLINUX64 THEN
  2432.         ELF.write(prog, outname, sofinit, target = TARGETS.Linux64SO, TRUE)
  2433.     END
  2434. END CodeGen;
  2435.  
  2436.  
  2437. END AMD64.