Subversion Repositories Kolibri OS

Rev

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

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