Subversion Repositories Kolibri OS

Rev

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