Subversion Repositories Kolibri OS

Rev

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.  
  670. BEGIN
  671.     loop := 1;
  672.     variables := cmd.variables;
  673.     leave := FALSE;
  674.     leaf := TRUE;
  675.  
  676.     cur := cmd.next(COMMAND);
  677.     REPEAT
  678.         CASE cur.opcode OF
  679.         |CODE.opLLOAD64,
  680.          CODE.opLLOAD8,
  681.          CODE.opLLOAD16,
  682.          CODE.opLLOAD32,
  683.          CODE.opLLOAD64_PARAM,
  684.          CODE.opLLOAD32_PARAM,
  685.          CODE.opLADR_SAVE,
  686.          CODE.opLADR_INC1,
  687.          CODE.opLADR_DEC1,
  688.          CODE.opLADR_INC,
  689.          CODE.opLADR_DEC,
  690.          CODE.opLADR_INC1B,
  691.          CODE.opLADR_DEC1B,
  692.          CODE.opLADR_INCB,
  693.          CODE.opLADR_DECB,
  694.          CODE.opLADR_INCL,
  695.          CODE.opLADR_EXCL,
  696.          CODE.opLADR_UNPK:
  697.             lvar := getVar(variables, cur.param2);
  698.             IF (lvar # NIL) & (lvar.count # -1) THEN
  699.                 INC(lvar.count, loop)
  700.             END
  701.  
  702.         |CODE.opLADR_SAVEC,
  703.          CODE.opLADR_INCC,
  704.          CODE.opLADR_DECC,
  705.          CODE.opLADR_INCCB,
  706.          CODE.opLADR_DECCB,
  707.          CODE.opLADR_INCLC,
  708.          CODE.opLADR_EXCLC:
  709.             lvar := getVar(variables, cur.param1);
  710.             IF (lvar # NIL) & (lvar.count # -1) THEN
  711.                 INC(lvar.count, loop)
  712.             END
  713.  
  714.         |CODE.opLADR:
  715.             lvar := getVar(variables, cur.param2);
  716.             IF (lvar # NIL) & (lvar.count # -1) THEN
  717.                 lvar.count := -1
  718.             END
  719.  
  720.         |CODE.opLOOP:
  721.             INC(loop, 10)
  722.  
  723.         |CODE.opENDLOOP:
  724.             DEC(loop, 10)
  725.  
  726.         |CODE.opLEAVE,
  727.          CODE.opLEAVER,
  728.          CODE.opLEAVEF:
  729.             leave := TRUE
  730.  
  731.         |CODE.opCALL, CODE.opCALLP, CODE.opCALLI,
  732.          CODE.opWIN64CALL, CODE.opWIN64CALLP, CODE.opWIN64CALLI,
  733.          CODE.opSYSVCALL, CODE.opSYSVCALLP, CODE.opSYSVCALLI:
  734.             leaf := FALSE
  735.  
  736.         ELSE
  737.  
  738.         END;
  739.         cur := cur.next(COMMAND)
  740.     UNTIL leave OR ~leaf;
  741.  
  742.     IF leaf THEN
  743.         REPEAT
  744.             reg := -1;
  745.             max := -1;
  746.             rvar := NIL;
  747.             lvar := variables.first(CODE.LOCALVAR);
  748.             WHILE lvar # NIL DO
  749.                 IF lvar.count > max THEN
  750.                     max := lvar.count;
  751.                     rvar := lvar
  752.                 END;
  753.                 lvar := lvar.next(CODE.LOCALVAR)
  754.             END;
  755.  
  756.             IF rvar # NIL THEN
  757.                 reg := REG.GetAnyVarReg(R);
  758.                 IF reg # -1 THEN
  759.                     REG.Lock(R, reg, rvar.offset, rvar.size);
  760.                     REG.Load(R, reg);
  761.                     rvar.count := -1
  762.                 END
  763.             END
  764.  
  765.         UNTIL (rvar = NIL) OR (reg = -1)
  766.     END
  767.  
  768. END allocReg;
  769.  
  770.  
  771. PROCEDURE GetRegA;
  772. BEGIN
  773.     ASSERT(REG.GetReg(R, rax))
  774. END GetRegA;
  775.  
  776.  
  777. PROCEDURE Win64Passing (params: INTEGER);
  778. VAR
  779.     n, i: INTEGER;
  780.  
  781. BEGIN
  782.     n := params MOD 32;
  783.     params := params DIV 32;
  784.     FOR i := 0 TO n - 1 DO
  785.         IF i IN BITS(params) THEN
  786.             movsdrm(i, rsp, i * 8)
  787.         ELSE
  788.             movrm(Win64RegPar[i], rsp, i * 8)
  789.         END
  790.     END
  791. END Win64Passing;
  792.  
  793.  
  794. PROCEDURE SysVPassing (params: INTEGER);
  795. VAR
  796.     n, i, s, p, ofs: INTEGER;
  797.     i_count, f_count: INTEGER;
  798.     reg: BOOLEAN;
  799.  
  800. BEGIN
  801.     ASSERT(r10 IN R.regs);
  802.     n := params MOD 32;
  803.     params := params DIV 32;
  804.     s := 0;
  805.  
  806.     i_count := 0;
  807.     f_count := 0;
  808.     FOR i := 0 TO n - 1 DO
  809.         IF i IN BITS(params) THEN
  810.             INC(f_count)
  811.         ELSE
  812.             INC(i_count)
  813.         END
  814.     END;
  815.  
  816.     s := MAX(0, f_count - 8) + MAX(0, i_count - 6);
  817.     p := 0;
  818.  
  819.     subrc(rsp, s * 8);
  820.  
  821.     i_count := 0;
  822.     f_count := 0;
  823.     FOR i := 0 TO n - 1 DO
  824.         ofs := (i + s) * 8;
  825.         IF i IN BITS(params) THEN
  826.             reg := f_count <= 7;
  827.             IF reg THEN
  828.                 movsdrm(f_count, rsp, ofs);
  829.                 INC(f_count)
  830.             END
  831.         ELSE
  832.             reg := i_count <= 5;
  833.             IF reg THEN
  834.                 movrm(SystemVRegPar[i_count], rsp, ofs);
  835.                 INC(i_count)
  836.             END
  837.         END;
  838.  
  839.         IF ~reg THEN
  840.             movrm(r10, rsp, ofs);
  841.             movmr(rsp, p, r10);
  842.             INC(p, 8)
  843.         END
  844.     END
  845. END SysVPassing;
  846.  
  847.  
  848. PROCEDURE fcmp (op: INTEGER; xmm: INTEGER);
  849. VAR
  850.     cc, reg: INTEGER;
  851.  
  852. BEGIN
  853.     reg := REG.GetAnyReg(R);
  854.     xor(reg, reg);
  855.     CASE op OF
  856.     |CODE.opEQF, CODE.opEQFI:
  857.         comisd(xmm - 1, xmm);
  858.         cc := sete
  859.  
  860.     |CODE.opNEF, CODE.opNEFI:
  861.         comisd(xmm - 1, xmm);
  862.         cc := setne
  863.  
  864.     |CODE.opLTF, CODE.opGTFI:
  865.         comisd(xmm - 1, xmm);
  866.         cc := setc
  867.  
  868.     |CODE.opGTF, CODE.opLTFI:
  869.         comisd(xmm, xmm - 1);
  870.         cc := setc
  871.  
  872.     |CODE.opLEF, CODE.opGEFI:
  873.         comisd(xmm, xmm - 1);
  874.         cc := setnc
  875.  
  876.     |CODE.opGEF, CODE.opLEFI:
  877.         comisd(xmm - 1, xmm);
  878.         cc := setnc
  879.     END;
  880.     OutByte2(7AH, 3 + reg DIV 8); // jp L
  881.     setcc(cc, reg);
  882.     //L:
  883. END fcmp;
  884.  
  885.  
  886. PROCEDURE translate (commands: LISTS.LIST; stroffs: INTEGER);
  887. VAR
  888.     cmd, next: COMMAND;
  889.  
  890.     param1, param2, param3, a, b, c, n, label, L, i, cc: INTEGER;
  891.  
  892.     reg1, reg2, xmm: INTEGER;
  893.  
  894.     float: REAL;
  895.  
  896.     regVar: BOOLEAN;
  897.  
  898. BEGIN
  899.     xmm := -1;
  900.     cmd := commands.first(COMMAND);
  901.     WHILE cmd # NIL DO
  902.  
  903.         param1 := cmd.param1;
  904.         param2 := cmd.param2;
  905.  
  906.         CASE cmd.opcode OF
  907.  
  908.         |CODE.opJMP:
  909.             jmp(param1)
  910.  
  911.         |CODE.opCALL, CODE.opWIN64CALL, CODE.opSYSVCALL:
  912.             REG.Store(R);
  913.             CASE cmd.opcode OF
  914.             |CODE.opCALL:
  915.             |CODE.opWIN64CALL: Win64Passing(param2)
  916.             |CODE.opSYSVCALL:  SysVPassing(param2)
  917.             END;
  918.             X86.call(param1);
  919.             REG.Restore(R)
  920.  
  921.         |CODE.opCALLP, CODE.opWIN64CALLP, CODE.opSYSVCALLP:
  922.             UnOp(reg1);
  923.             IF reg1 # rax THEN
  924.                 GetRegA;
  925.                 ASSERT(REG.Exchange(R, reg1, rax));
  926.                 drop
  927.             END;
  928.             drop;
  929.             REG.Store(R);
  930.             CASE cmd.opcode OF
  931.             |CODE.opCALLP:
  932.             |CODE.opWIN64CALLP: Win64Passing(param2)
  933.             |CODE.opSYSVCALLP:  SysVPassing(param2)
  934.             END;
  935.             OutByte2(0FFH, 0D0H); // call rax
  936.             REG.Restore(R);
  937.             ASSERT(R.top = -1)
  938.  
  939.         |CODE.opCALLI, CODE.opWIN64CALLI, CODE.opSYSVCALLI:
  940.             REG.Store(R);
  941.             CASE cmd.opcode OF
  942.             |CODE.opCALLI:
  943.             |CODE.opWIN64CALLI: Win64Passing(param2)
  944.             |CODE.opSYSVCALLI:  SysVPassing(param2)
  945.             END;
  946.             callimp(param1);
  947.             REG.Restore(R)
  948.  
  949.         |CODE.opLABEL:
  950.             X86.SetLabel(param2)
  951.  
  952.         |CODE.opERR:
  953.             CallRTL(CODE._error)
  954.  
  955.         |CODE.opERRC:
  956.             pushc(param2)
  957.  
  958.         |CODE.opPRECALL:
  959.             n := param2;
  960.             IF (param1 # 0) & (n # 0) THEN
  961.                 subrc(rsp, 8)
  962.             END;
  963.             WHILE n > 0 DO
  964.                 subrc(rsp, 8);
  965.                 movsdmr(rsp, 0, xmm);
  966.                 DEC(xmm);
  967.                 DEC(n)
  968.             END;
  969.             ASSERT(xmm = -1);
  970.             PushAll(0)
  971.  
  972.         |CODE.opWIN64ALIGN16:
  973.             ASSERT(rax IN R.regs);
  974.             mov(rax, rsp);
  975.             andrc(rsp, -16);
  976.             push(rax);
  977.             subrc(rsp, (MAX(param2 - 4, 0) MOD 2 + MAX(4 - param2, 0) + 1) * 8)
  978.  
  979.         |CODE.opSYSVALIGN16:
  980.             ASSERT(rax IN R.regs);
  981.             mov(rax, rsp);
  982.             andrc(rsp, -16);
  983.             push(rax);
  984.             IF ~ODD(param2) THEN
  985.                 push(rax)
  986.             END
  987.  
  988.         |CODE.opRESF:
  989.             ASSERT(xmm = -1);
  990.             INC(xmm);
  991.             n := param2;
  992.             IF n > 0 THEN
  993.                 movsdmr(rsp, n * 8, xmm);
  994.                 DEC(xmm);
  995.                 INC(n)
  996.             END;
  997.  
  998.             WHILE n > 0 DO
  999.                 INC(xmm);
  1000.                 movsdrm(xmm, rsp, 0);
  1001.                 addrc(rsp, 8);
  1002.                 DEC(n)
  1003.             END
  1004.  
  1005.         |CODE.opRES:
  1006.             ASSERT(R.top = -1);
  1007.             GetRegA;
  1008.             n := param2;
  1009.             WHILE n > 0 DO
  1010.                 INC(xmm);
  1011.                 movsdrm(xmm, rsp, 0);
  1012.                 addrc(rsp, 8);
  1013.                 DEC(n)
  1014.             END
  1015.  
  1016.         |CODE.opENTER:
  1017.             ASSERT(R.top = -1);
  1018.  
  1019.             X86.SetLabel(param1);
  1020.  
  1021.             param3 := cmd.param3;
  1022.  
  1023.             IF param3 > 0 THEN
  1024.                 push(rbp);
  1025.                 mov(rbp, rsp);
  1026.  
  1027.                 n := param3 MOD 32;
  1028.                 param3 := param3 DIV 32;
  1029.  
  1030.                 FOR i := 0 TO n - 1 DO
  1031.                     IF i IN BITS(param3) THEN
  1032.                         movsdmr(rbp, i * 8 + 16, i)
  1033.                     ELSE
  1034.                         movmr(rbp, i * 8 + 16, Win64RegPar[i])
  1035.                     END
  1036.                 END
  1037.             ELSIF param3 < 0 THEN
  1038.                 param3 := -param3;
  1039.                 n := (param3 MOD 32) * 8;
  1040.                 param3 := param3 DIV 32;
  1041.                 pop(r10);
  1042.                 subrc(rsp, n);
  1043.                 push(r10);
  1044.                 push(rbp);
  1045.                 mov(rbp, rsp);
  1046.  
  1047.                 a := 0;
  1048.                 b := 0;
  1049.                 c := 0;
  1050.  
  1051.                 INC(n, 16);
  1052.  
  1053.                 FOR i := 16 TO n - 8 BY 8 DO
  1054.                     IF ODD(param3) THEN
  1055.                         IF b <= 7 THEN
  1056.                             movsdmr(rbp, i, b);
  1057.                             INC(b)
  1058.                         ELSE
  1059.                             movrm(r10, rbp, n + c);
  1060.                             movmr(rbp, i, r10);
  1061.                             INC(c, 8)
  1062.                         END
  1063.                     ELSE
  1064.                         IF a <= 5 THEN
  1065.                             movmr(rbp, i, SystemVRegPar[a]);
  1066.                             INC(a)
  1067.                         ELSE
  1068.                             movrm(r10, rbp, n + c);
  1069.                             movmr(rbp, i, r10);
  1070.                             INC(c, 8)
  1071.                         END
  1072.                     END;
  1073.                     param3 := param3 DIV 2
  1074.                 END
  1075.             ELSE
  1076.                 push(rbp);
  1077.                 mov(rbp, rsp)
  1078.             END;
  1079.  
  1080.             n := param2;
  1081.             IF n > 4 THEN
  1082.                 movrc(rcx, n);
  1083.                                       // L:
  1084.                 pushc(0);
  1085.                 OutByte2(0E2H, 0FCH) // loop L
  1086.             ELSE
  1087.                 WHILE n > 0 DO
  1088.                     pushc(0);
  1089.                     DEC(n)
  1090.                 END
  1091.             END;
  1092.  
  1093.             IF cmd.allocReg THEN
  1094.                 allocReg(cmd)
  1095.             END
  1096.  
  1097.         |CODE.opLEAVE, CODE.opLEAVER, CODE.opLEAVEF:
  1098.             IF cmd.opcode = CODE.opLEAVER THEN
  1099.                 UnOp(reg1);
  1100.                 IF reg1 # rax THEN
  1101.                     GetRegA;
  1102.                     ASSERT(REG.Exchange(R, reg1, rax));
  1103.                     drop
  1104.                 END;
  1105.                 drop
  1106.             END;
  1107.  
  1108.             ASSERT(R.top = -1);
  1109.  
  1110.             IF cmd.opcode = CODE.opLEAVEF THEN
  1111.                 DEC(xmm)
  1112.             END;
  1113.  
  1114.             ASSERT(xmm = -1);
  1115.  
  1116.             mov(rsp, rbp);
  1117.             pop(rbp);
  1118.             IF param2 > 0 THEN
  1119.                 OutByte3(0C2H, (param2 * 8) MOD 256, (param2 * 8) DIV 256)  // ret param2
  1120.             ELSE
  1121.                 OutByte(0C3H) // ret
  1122.             END;
  1123.             REG.Reset(R)
  1124.  
  1125.         |CODE.opSAVES:
  1126.             UnOp(reg1);
  1127.             drop;
  1128.             PushAll(0);
  1129.             push(reg1);
  1130.             pushDA(stroffs + param2);
  1131.             pushc(param1);
  1132.             CallRTL(CODE._move)
  1133.  
  1134.         |CODE.opSADR:
  1135.             reg1 := REG.GetAnyReg(R);
  1136.             lea(reg1, stroffs + param2, sDATA)
  1137.  
  1138.         |CODE.opLOAD8:
  1139.             UnOp(reg1);
  1140.             movzx(reg1, reg1, 0, FALSE)
  1141.  
  1142.         |CODE.opLOAD16:
  1143.             UnOp(reg1);
  1144.             movzx(reg1, reg1, 0, TRUE)
  1145.  
  1146.         |CODE.opLOAD32:
  1147.             UnOp(reg1);
  1148.             movrm32(reg1, reg1, 0);
  1149.             shiftrc(shl, reg1, 32);
  1150.             shiftrc(shr, reg1, 32)
  1151.  
  1152.         |CODE.opLOAD64:
  1153.             UnOp(reg1);
  1154.             movrm(reg1, reg1, 0)
  1155.  
  1156.         |CODE.opLLOAD64:
  1157.             reg1 := REG.GetAnyReg(R);
  1158.             reg2 := REG.GetVarReg(R, param2);
  1159.             IF reg2 # -1 THEN
  1160.                 mov(reg1, reg2)
  1161.             ELSE
  1162.                 movrm(reg1, rbp, param2 * 8)
  1163.             END
  1164.  
  1165.         |CODE.opLLOAD8,
  1166.          CODE.opLLOAD16:
  1167.             reg1 := REG.GetAnyReg(R);
  1168.             reg2 := REG.GetVarReg(R, param2);
  1169.             IF reg2 # -1 THEN
  1170.                 mov(reg1, reg2)
  1171.             ELSE
  1172.                 movzx(reg1, rbp, param2 * 8, cmd.opcode = CODE.opLLOAD16)
  1173.             END
  1174.  
  1175.         |CODE.opLLOAD32:
  1176.             reg1 := REG.GetAnyReg(R);
  1177.             reg2 := REG.GetVarReg(R, param2);
  1178.             IF reg2 # -1 THEN
  1179.                 mov(reg1, reg2)
  1180.             ELSE
  1181.                 n := param2 * 8;
  1182.                 xor(reg1, reg1);
  1183.                 movrm32(reg1, rbp, n)
  1184.             END
  1185.  
  1186.         |CODE.opGLOAD64:
  1187.             reg1 := REG.GetAnyReg(R);
  1188.             lea(reg1, param2, sBSS);
  1189.             movrm(reg1, reg1, 0)
  1190.  
  1191.         |CODE.opGLOAD8:
  1192.             reg1 := REG.GetAnyReg(R);
  1193.             lea(reg1, param2, sBSS);
  1194.             movzx(reg1, reg1, 0, FALSE)
  1195.  
  1196.         |CODE.opGLOAD16:
  1197.             reg1 := REG.GetAnyReg(R);
  1198.             lea(reg1, param2, sBSS);
  1199.             movzx(reg1, reg1, 0, TRUE)
  1200.  
  1201.         |CODE.opGLOAD32:
  1202.             reg1 := REG.GetAnyReg(R);
  1203.             xor(reg1, reg1);
  1204.             lea(reg1, param2, sBSS);
  1205.             movrm32(reg1, reg1, 0)
  1206.  
  1207.         |CODE.opVLOAD64:
  1208.             reg1 := REG.GetAnyReg(R);
  1209.             movrm(reg1, rbp, param2 * 8);
  1210.             movrm(reg1, reg1, 0)
  1211.  
  1212.         |CODE.opVLOAD8,
  1213.          CODE.opVLOAD16:
  1214.             reg1 := REG.GetAnyReg(R);
  1215.             movrm(reg1, rbp, param2 * 8);
  1216.             movzx(reg1, reg1, 0, cmd.opcode = CODE.opVLOAD16)
  1217.  
  1218.         |CODE.opVLOAD32:
  1219.             reg1 := REG.GetAnyReg(R);
  1220.             reg2 := REG.GetAnyReg(R);
  1221.             xor(reg1, reg1);
  1222.             movrm(reg2, rbp, param2 * 8);
  1223.             movrm32(reg1, reg2, 0);
  1224.             drop
  1225.  
  1226.         |CODE.opLADR:
  1227.             n := param2 * 8;
  1228.             next := cmd.next(COMMAND);
  1229.             IF next.opcode = CODE.opSAVEF THEN
  1230.                 movsdmr(rbp, n, xmm);
  1231.                 DEC(xmm);
  1232.                 cmd := next
  1233.             ELSIF next.opcode = CODE.opLOADF THEN
  1234.                 INC(xmm);
  1235.                 movsdrm(xmm, rbp, n);
  1236.                 cmd := next
  1237.             ELSE
  1238.                 reg1 := REG.GetAnyReg(R);
  1239.                 Rex(0, reg1);
  1240.                 OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8);  // lea reg1, qword[rbp+n]
  1241.                 OutIntByte(n)
  1242.             END
  1243.  
  1244.         |CODE.opGADR:
  1245.             reg1 := REG.GetAnyReg(R);
  1246.             lea(reg1, param2, sBSS)
  1247.  
  1248.         |CODE.opVADR:
  1249.             reg1 := REG.GetAnyReg(R);
  1250.             movrm(reg1, rbp, param2 * 8)
  1251.  
  1252.         |CODE.opSAVE8C:
  1253.             UnOp(reg1);
  1254.             IF reg1 >= 8 THEN
  1255.                 OutByte(41H)
  1256.             END;
  1257.             OutByte3(0C6H, reg1 MOD 8, param2); // mov byte[reg1], param2
  1258.             drop
  1259.  
  1260.         |CODE.opSAVE16C:
  1261.             UnOp(reg1);
  1262.             OutByte(66H);
  1263.             IF reg1 >= 8 THEN
  1264.                 OutByte(41H)
  1265.             END;
  1266.             OutByte2(0C7H, reg1 MOD 8);
  1267.             OutByte2(param2 MOD 256, param2 DIV 256); // mov word[reg1], param2
  1268.             drop
  1269.  
  1270.         |CODE.opSAVEC:
  1271.             UnOp(reg1);
  1272.             IF isLong(param2) THEN
  1273.                 reg2 := REG.GetAnyReg(R);
  1274.                 movrc(reg2, param2);
  1275.                 movmr(reg1, 0, reg2);
  1276.                 drop
  1277.             ELSE
  1278.                 Rex(reg1, 0);
  1279.                 OutByte2(0C7H, reg1 MOD 8); // mov qword[reg1], param2
  1280.                 OutInt(param2)
  1281.             END;
  1282.             drop
  1283.  
  1284.         |CODE.opRSET:
  1285.             PushAll(2);
  1286.             CallRTL(CODE._set);
  1287.             GetRegA
  1288.  
  1289.         |CODE.opRSETR:
  1290.             PushAll(1);
  1291.             pushc(param2);
  1292.             CallRTL(CODE._set);
  1293.             GetRegA
  1294.  
  1295.         |CODE.opRSETL:
  1296.             PushAll(1);
  1297.             pushc(param2);
  1298.             CallRTL(CODE._set2);
  1299.             GetRegA
  1300.  
  1301.         |CODE.opRSET1:
  1302.             UnOp(reg1);
  1303.             PushAll(1);
  1304.             push(reg1);
  1305.             CallRTL(CODE._set);
  1306.             GetRegA
  1307.  
  1308.         |CODE.opINCL, CODE.opEXCL:
  1309.             BinOp(reg1, reg2);
  1310.             cmprc(reg1, 64);
  1311.             OutByte2(73H, 04H); // jnb L
  1312.             Rex(reg2, reg1);
  1313.             OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); // bts/btr qword[reg2], reg1
  1314.             // L:
  1315.             drop;
  1316.             drop
  1317.  
  1318.         |CODE.opINCLC, CODE.opEXCLC:
  1319.             UnOp(reg1);
  1320.             Rex(reg1, 0);
  1321.             OutByte2(0FH, 0BAH);  // bts/btr qword[reg1], param2
  1322.             OutByte2(28H + 8 * ORD(cmd.opcode = CODE.opEXCLC) + reg1 MOD 8, param2);
  1323.             drop
  1324.  
  1325.         |CODE.opEQS .. CODE.opGES:
  1326.             PushAll(4);
  1327.             pushc(cmd.opcode - CODE.opEQS);
  1328.             CallRTL(CODE._strcmp);
  1329.             GetRegA
  1330.  
  1331.         |CODE.opEQS2 .. CODE.opGES2:
  1332.             PushAll(4);
  1333.             pushc(cmd.opcode - CODE.opEQS2);
  1334.             CallRTL(CODE._strcmp2);
  1335.             GetRegA
  1336.  
  1337.         |CODE.opEQSW .. CODE.opGESW:
  1338.             PushAll(4);
  1339.             pushc(cmd.opcode - CODE.opEQSW);
  1340.             CallRTL(CODE._strcmpw);
  1341.             GetRegA
  1342.  
  1343.         |CODE.opEQSW2 .. CODE.opGESW2:
  1344.             PushAll(4);
  1345.             pushc(cmd.opcode - CODE.opEQSW2);
  1346.             CallRTL(CODE._strcmpw2);
  1347.             GetRegA
  1348.  
  1349.         |CODE.opINC1, CODE.opDEC1:
  1350.             UnOp(reg1);
  1351.             Rex(reg1, 0);
  1352.             OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opDEC1));
  1353.             drop
  1354.  
  1355.         |CODE.opCONST:
  1356.             reg1 := REG.GetAnyReg(R);
  1357.             movrc(reg1, param2)
  1358.  
  1359.         |CODE.opGT, CODE.opGE, CODE.opLT,
  1360.          CODE.opLE, CODE.opEQ, CODE.opNE:
  1361.             BinOp(reg1, reg2);
  1362.             cmprr(reg1, reg2);
  1363.             drop;
  1364.             drop;
  1365.             cc := X86.cond(cmd.opcode);
  1366.  
  1367.             IF cmd.next(COMMAND).opcode = CODE.opJE THEN
  1368.                 label := cmd.next(COMMAND).param1;
  1369.                 jcc(cc, label);
  1370.                 cmd := cmd.next(COMMAND)
  1371.  
  1372.             ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
  1373.                 label := cmd.next(COMMAND).param1;
  1374.                 jcc(X86.inv1(cc), label);
  1375.                 cmd := cmd.next(COMMAND)
  1376.  
  1377.             ELSE
  1378.                 reg1 := REG.GetAnyReg(R);
  1379.                 setcc(cc + 16, reg1);
  1380.                 andrc(reg1, 1)
  1381.             END
  1382.  
  1383.         |CODE.opGTR, CODE.opLTL, CODE.opGER, CODE.opLEL,
  1384.          CODE.opLER, CODE.opGEL, CODE.opLTR, CODE.opGTL,
  1385.          CODE.opEQR, CODE.opEQL, CODE.opNER, CODE.opNEL:
  1386.             UnOp(reg1);
  1387.             IF param2 = 0 THEN
  1388.                 test(reg1)
  1389.             ELSE
  1390.                 cmprc(reg1, param2)
  1391.             END;
  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.opCODE:
  1412.             OutByte(param2)
  1413.  
  1414.         |CODE.opPUSHIP:
  1415.             reg1 := REG.GetAnyReg(R);
  1416.             lea(reg1, param2, sIMP);
  1417.             movrm(reg1, reg1, 0)
  1418.  
  1419.         |CODE.opPARAM:
  1420.             n := param2;
  1421.             IF n = 1 THEN
  1422.                 UnOp(reg1);
  1423.                 push(reg1);
  1424.                 drop
  1425.             ELSE
  1426.                 ASSERT(R.top + 1 <= n);
  1427.                 PushAll(n)
  1428.             END
  1429.  
  1430.         |CODE.opJNZ:
  1431.             UnOp(reg1);
  1432.             test(reg1);
  1433.             jcc(jne, param1)
  1434.  
  1435.         |CODE.opJZ:
  1436.             UnOp(reg1);
  1437.             test(reg1);
  1438.             jcc(je, param1)
  1439.  
  1440.         |CODE.opJE:
  1441.             UnOp(reg1);
  1442.             test(reg1);
  1443.             jcc(jne, param1);
  1444.             drop
  1445.  
  1446.         |CODE.opJNE:
  1447.             UnOp(reg1);
  1448.             test(reg1);
  1449.             jcc(je, param1);
  1450.             drop
  1451.  
  1452.         |CODE.opIN:
  1453.             label := NewLabel();
  1454.             L := NewLabel();
  1455.             BinOp(reg1, reg2);
  1456.             cmprc(reg1, 64);
  1457.             jcc(jb, L);
  1458.             xor(reg1, reg1);
  1459.             jmp(label);
  1460.             X86.SetLabel(L);
  1461.             Rex(reg2, reg1);
  1462.             OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
  1463.             setcc(setc, reg1);
  1464.             andrc(reg1, 1);
  1465.             X86.SetLabel(label);
  1466.             drop
  1467.  
  1468.         |CODE.opINR:
  1469.             label := NewLabel();
  1470.             L := NewLabel();
  1471.             UnOp(reg1);
  1472.             reg2 := REG.GetAnyReg(R);
  1473.             cmprc(reg1, 64);
  1474.             jcc(jb, L);
  1475.             xor(reg1, reg1);
  1476.             jmp(label);
  1477.             X86.SetLabel(L);
  1478.             movrc(reg2, param2);
  1479.             Rex(reg2, reg1);
  1480.             OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
  1481.             setcc(setc, reg1);
  1482.             andrc(reg1, 1);
  1483.             X86.SetLabel(label);
  1484.             drop
  1485.  
  1486.         |CODE.opINL:
  1487.             UnOp(reg1);
  1488.             Rex(reg1, 0);
  1489.             OutByte2(0FH, 0BAH);  // bt reg1, param2
  1490.             OutByte2(0E0H + reg1 MOD 8, param2);
  1491.             setcc(setc, reg1);
  1492.             andrc(reg1, 1)
  1493.  
  1494.         |CODE.opNOT:
  1495.             UnOp(reg1);
  1496.             test(reg1);
  1497.             setcc(sete, reg1);
  1498.             andrc(reg1, 1)
  1499.  
  1500.         |CODE.opORD:
  1501.             UnOp(reg1);
  1502.             test(reg1);
  1503.             setcc(setne, reg1);
  1504.             andrc(reg1, 1)
  1505.  
  1506.         |CODE.opABS:
  1507.             UnOp(reg1);
  1508.             test(reg1);
  1509.             OutByte2(7DH, 03H); // jge L
  1510.             neg(reg1)
  1511.             // L:
  1512.  
  1513.         |CODE.opEQB, CODE.opNEB:
  1514.             BinOp(reg1, reg2);
  1515.             drop;
  1516.             drop;
  1517.  
  1518.             test(reg1);
  1519.             OutByte2(74H, 07H); // je L1
  1520.             movrc(reg1, 1);
  1521.             // L1:
  1522.             test(reg2);
  1523.             OutByte2(74H, 07H); // je L2
  1524.             movrc(reg2, 1);
  1525.             // L2:
  1526.             cmprr(reg1, reg2);
  1527.             reg1 := REG.GetAnyReg(R);
  1528.             IF cmd.opcode = CODE.opEQB THEN
  1529.                 setcc(sete, reg1)
  1530.             ELSE
  1531.                 setcc(setne, reg1)
  1532.             END;
  1533.             andrc(reg1, 1)
  1534.  
  1535.         |CODE.opMULSC:
  1536.             UnOp(reg1);
  1537.             andrc(reg1, param2)
  1538.  
  1539.         |CODE.opDIVSC, CODE.opADDSL, CODE.opADDSR:
  1540.             UnOp(reg1);
  1541.             Rex(reg1, 0);
  1542.             OutByte2(81H + short(param2), 0C8H + 28H * ORD(cmd.opcode = CODE.opDIVSC) + reg1 MOD 8); // or/xor reg1, param2
  1543.             OutIntByte(param2)
  1544.  
  1545.         |CODE.opSUBSL:
  1546.             UnOp(reg1);
  1547.             not(reg1);
  1548.             andrc(reg1, param2)
  1549.  
  1550.         |CODE.opSUBSR:
  1551.             UnOp(reg1);
  1552.             andrc(reg1, ORD(-BITS(param2)))
  1553.  
  1554.         |CODE.opMULS:
  1555.             BinOp(reg1, reg2);
  1556.             and(reg1, reg2);
  1557.             drop
  1558.  
  1559.         |CODE.opDIVS:
  1560.             BinOp(reg1, reg2);
  1561.             xor(reg1, reg2);
  1562.             drop
  1563.  
  1564.         |CODE.opUMINS:
  1565.             UnOp(reg1);
  1566.             not(reg1)
  1567.  
  1568.         |CODE.opCOPY:
  1569.             PushAll(2);
  1570.             pushc(param2);
  1571.             CallRTL(CODE._move2)
  1572.  
  1573.         |CODE.opMOVE:
  1574.             PushAll(3);
  1575.             CallRTL(CODE._move2)
  1576.  
  1577.         |CODE.opCOPYA:
  1578.             PushAll(4);
  1579.             pushc(param2);
  1580.             CallRTL(CODE._arrcpy);
  1581.             GetRegA
  1582.  
  1583.         |CODE.opCOPYS:
  1584.             PushAll(4);
  1585.             pushc(param2);
  1586.             CallRTL(CODE._strcpy)
  1587.  
  1588.         |CODE.opCOPYS2:
  1589.             PushAll(4);
  1590.             pushc(param2);
  1591.             CallRTL(CODE._strcpy2)
  1592.  
  1593.         |CODE.opROT:
  1594.             PushAll(0);
  1595.             push(rsp);
  1596.             pushc(param2);
  1597.             CallRTL(CODE._rot)
  1598.  
  1599.         |CODE.opNEW:
  1600.             PushAll(1);
  1601.             n := param2 + 16;
  1602.             ASSERT(MACHINE.Align(n, 64));
  1603.             pushc(n);
  1604.             pushc(param1);
  1605.             CallRTL(CODE._new)
  1606.  
  1607.         |CODE.opDISP:
  1608.             PushAll(1);
  1609.             CallRTL(CODE._dispose)
  1610.  
  1611.         |CODE.opPUSHT:
  1612.             UnOp(reg1);
  1613.             reg2 := REG.GetAnyReg(R);
  1614.             movrm(reg2, reg1, -8)
  1615.  
  1616.         |CODE.opISREC:
  1617.             PushAll(2);
  1618.             pushc(param2);
  1619.             CallRTL(CODE._isrec);
  1620.             GetRegA
  1621.  
  1622.         |CODE.opIS:
  1623.             PushAll(1);
  1624.             pushc(param2);
  1625.             CallRTL(CODE._is);
  1626.             GetRegA
  1627.  
  1628.         |CODE.opTYPEGR:
  1629.             PushAll(1);
  1630.             pushc(param2);
  1631.             CallRTL(CODE._guardrec);
  1632.             GetRegA
  1633.  
  1634.         |CODE.opTYPEGP:
  1635.             UnOp(reg1);
  1636.             PushAll(0);
  1637.             push(reg1);
  1638.             pushc(param2);
  1639.             CallRTL(CODE._guard);
  1640.             GetRegA
  1641.  
  1642.         |CODE.opTYPEGD:
  1643.             UnOp(reg1);
  1644.             PushAll(0);
  1645.             pushm(reg1, -8);
  1646.             pushc(param2);
  1647.             CallRTL(CODE._guardrec);
  1648.             GetRegA
  1649.  
  1650.         |CODE.opCASET:
  1651.             push(r10);
  1652.             push(r10);
  1653.             pushc(param2);
  1654.             CallRTL(CODE._guardrec);
  1655.             pop(r10);
  1656.             test(rax);
  1657.             jcc(jne, param1)
  1658.  
  1659.         |CODE.opSAVEP:
  1660.             UnOp(reg1);
  1661.             reg2 := REG.GetAnyReg(R);
  1662.             lea(reg2, param2, sCODE);
  1663.             movmr(reg1, 0, reg2);
  1664.             drop;
  1665.             drop
  1666.  
  1667.         |CODE.opPUSHP:
  1668.             reg1 := REG.GetAnyReg(R);
  1669.             lea(reg1, param2, sCODE)
  1670.  
  1671.         |CODE.opINC, CODE.opDEC:
  1672.             BinOp(reg1, reg2);
  1673.             // add/sub qword[reg2], reg1
  1674.             Rex(reg2, reg1);
  1675.             OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
  1676.             drop;
  1677.             drop
  1678.  
  1679.         |CODE.opINCC, CODE.opDECC:
  1680.             UnOp(reg1);
  1681.             IF isLong(param2) THEN
  1682.                 reg2 := REG.GetAnyReg(R);
  1683.                 movrc(reg2, param2);
  1684.                 // add/sub qword[reg1], reg2
  1685.                 Rex(reg1, reg2);
  1686.                 OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDECC), reg1 MOD 8 + (reg2 MOD 8) * 8);
  1687.                 drop
  1688.             ELSE
  1689.                 // add/sub qword[reg1], param2
  1690.                 Rex(reg1, 0);
  1691.                 OutByte2(81H + short(param2), 28H * ORD(cmd.opcode = CODE.opDECC) + reg1 MOD 8);
  1692.                 OutIntByte(param2)
  1693.             END;
  1694.             drop
  1695.  
  1696.         |CODE.opDROP:
  1697.             UnOp(reg1);
  1698.             drop
  1699.  
  1700.         |CODE.opSAVE, CODE.opSAVE64:
  1701.             BinOp(reg2, reg1);
  1702.             movmr(reg1, 0, reg2);
  1703.             drop;
  1704.             drop
  1705.  
  1706.         |CODE.opSAVE8:
  1707.             BinOp(reg2, reg1);
  1708.             movmr8(reg1, 0, reg2);
  1709.             drop;
  1710.             drop
  1711.  
  1712.         |CODE.opSAVE16:
  1713.             BinOp(reg2, reg1);
  1714.             movmr16(reg1, 0, reg2);
  1715.             drop;
  1716.             drop
  1717.  
  1718.         |CODE.opSAVE32:
  1719.             BinOp(reg2, reg1);
  1720.             movmr32(reg1, 0, reg2);
  1721.             drop;
  1722.             drop
  1723.  
  1724.         |CODE.opMIN:
  1725.             BinOp(reg1, reg2);
  1726.             cmprr(reg1, reg2);
  1727.             OutByte2(7EH, 3); // jle L
  1728.             mov(reg1, reg2);
  1729.             // L:
  1730.             drop
  1731.  
  1732.         |CODE.opMAX:
  1733.             BinOp(reg1, reg2);
  1734.             cmprr(reg1, reg2);
  1735.             OutByte2(7DH, 3);  // jge L
  1736.             mov(reg1, reg2);
  1737.             // L:
  1738.             drop
  1739.  
  1740.         |CODE.opMINC:
  1741.             UnOp(reg1);
  1742.             cmprc(reg1, param2);
  1743.             label := NewLabel();
  1744.             jcc(jle, label);
  1745.             movrc(reg1, param2);
  1746.             X86.SetLabel(label)
  1747.  
  1748.         |CODE.opMAXC:
  1749.             UnOp(reg1);
  1750.             cmprc(reg1, param2);
  1751.             label := NewLabel();
  1752.             jcc(jge, label);
  1753.             movrc(reg1, param2);
  1754.             X86.SetLabel(label)
  1755.  
  1756.         |CODE.opSBOOL:
  1757.             BinOp(reg2, reg1);
  1758.             test(reg2);
  1759.             setcc(setne, reg2);
  1760.             movmr8(reg1, 0, reg2);
  1761.             drop;
  1762.             drop
  1763.  
  1764.         |CODE.opSBOOLC:
  1765.             UnOp(reg1);
  1766.             IF reg1 >= 8 THEN
  1767.                 OutByte(41H)
  1768.             END;
  1769.             OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0));
  1770.             drop
  1771.  
  1772.         |CODE.opODD:
  1773.             UnOp(reg1);
  1774.             andrc(reg1, 1)
  1775.  
  1776.         |CODE.opUMINUS:
  1777.             UnOp(reg1);
  1778.             neg(reg1)
  1779.  
  1780.         |CODE.opADD:
  1781.             BinOp(reg1, reg2);
  1782.             add(reg1, reg2);
  1783.             drop
  1784.  
  1785.         |CODE.opSUB:
  1786.             BinOp(reg1, reg2);
  1787.             sub(reg1, reg2);
  1788.             drop
  1789.  
  1790.         |CODE.opSUBR, CODE.opSUBL:
  1791.             UnOp(reg1);
  1792.             n := param2;
  1793.             IF n = 1 THEN
  1794.                 decr(reg1)
  1795.             ELSIF n = -1 THEN
  1796.                 incr(reg1)
  1797.             ELSIF n # 0 THEN
  1798.                 subrc(reg1, n)
  1799.             END;
  1800.             IF cmd.opcode = CODE.opSUBL THEN
  1801.                 neg(reg1)
  1802.             END
  1803.  
  1804.         |CODE.opADDL, CODE.opADDR:
  1805.             IF param2 # 0 THEN
  1806.                 UnOp(reg1);
  1807.                 IF param2 = 1 THEN
  1808.                     incr(reg1)
  1809.                 ELSIF param2 = -1 THEN
  1810.                     decr(reg1)
  1811.                 ELSE
  1812.                     addrc(reg1, param2)
  1813.                 END
  1814.             END
  1815.  
  1816.         |CODE.opDIV:
  1817.             PushAll(2);
  1818.             CallRTL(CODE._div);
  1819.             GetRegA
  1820.  
  1821.         |CODE.opDIVR:
  1822.             a := param2;
  1823.             IF a > 1 THEN
  1824.                 n := X86.log2(a)
  1825.             ELSIF a < -1 THEN
  1826.                 n := X86.log2(-a)
  1827.             ELSE
  1828.                 n := -1
  1829.             END;
  1830.  
  1831.             IF a = 1 THEN
  1832.  
  1833.             ELSIF a = -1 THEN
  1834.                 UnOp(reg1);
  1835.                 neg(reg1)
  1836.             ELSE
  1837.                 IF n > 0 THEN
  1838.                     UnOp(reg1);
  1839.  
  1840.                     IF a < 0 THEN
  1841.                         reg2 := REG.GetAnyReg(R);
  1842.                         mov(reg2, reg1);
  1843.                         shiftrc(sar, reg1, n);
  1844.                         sub(reg1, reg2);
  1845.                         drop
  1846.                     ELSE
  1847.                         shiftrc(sar, reg1, n)
  1848.                     END
  1849.  
  1850.                 ELSE
  1851.                     PushAll(1);
  1852.                     pushc(param2);
  1853.                     CallRTL(CODE._div);
  1854.                     GetRegA
  1855.                 END
  1856.             END
  1857.  
  1858.         |CODE.opDIVL:
  1859.             PushAll(1);
  1860.             pushc(param2);
  1861.             CallRTL(CODE._div2);
  1862.             GetRegA
  1863.  
  1864.         |CODE.opMOD:
  1865.             PushAll(2);
  1866.             CallRTL(CODE._mod);
  1867.             GetRegA
  1868.  
  1869.         |CODE.opMODR:
  1870.             a := param2;
  1871.             IF a > 1 THEN
  1872.                 n := X86.log2(a)
  1873.             ELSIF a < -1 THEN
  1874.                 n := X86.log2(-a)
  1875.             ELSE
  1876.                 n := -1
  1877.             END;
  1878.  
  1879.             IF ABS(a) = 1 THEN
  1880.                 UnOp(reg1);
  1881.                 xor(reg1, reg1)
  1882.             ELSE
  1883.                 IF n > 0 THEN
  1884.                     UnOp(reg1);
  1885.                     andrc(reg1, ABS(a) - 1);
  1886.  
  1887.                     IF a < 0 THEN
  1888.                         test(reg1);
  1889.                         label := NewLabel();
  1890.                         jcc(je, label);
  1891.                         addrc(reg1, a);
  1892.                         X86.SetLabel(label)
  1893.                     END
  1894.  
  1895.                 ELSE
  1896.                     PushAll(1);
  1897.                     pushc(param2);
  1898.                     CallRTL(CODE._mod);
  1899.                     GetRegA
  1900.                 END
  1901.             END
  1902.  
  1903.         |CODE.opMODL:
  1904.             PushAll(1);
  1905.             pushc(param2);
  1906.             CallRTL(CODE._mod2);
  1907.             GetRegA
  1908.  
  1909.         |CODE.opMUL:
  1910.             BinOp(reg1, reg2);
  1911.             oprr2(0FH, 0AFH, reg2, reg1); // imul reg1, reg2
  1912.             drop
  1913.  
  1914.         |CODE.opMULC:
  1915.             UnOp(reg1);
  1916.  
  1917.             a := param2;
  1918.             IF a > 1 THEN
  1919.                 n := X86.log2(a)
  1920.             ELSIF a < -1 THEN
  1921.                 n := X86.log2(-a)
  1922.             ELSE
  1923.                 n := -1
  1924.             END;
  1925.  
  1926.             IF a = 1 THEN
  1927.  
  1928.             ELSIF a = -1 THEN
  1929.                 neg(reg1)
  1930.             ELSIF a = 0 THEN
  1931.                 xor(reg1, reg1)
  1932.             ELSE
  1933.                 IF n > 0 THEN
  1934.                     IF a < 0 THEN
  1935.                         neg(reg1)
  1936.                     END;
  1937.                     shiftrc(shl, reg1, n)
  1938.                 ELSE
  1939.                     // imul reg1, a
  1940.                     Rex(reg1, reg1);
  1941.                     OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
  1942.                     OutIntByte(a)
  1943.                 END
  1944.             END
  1945.  
  1946.         |CODE.opADDS:
  1947.             BinOp(reg1, reg2);
  1948.             or(reg1, reg2);
  1949.             drop
  1950.  
  1951.         |CODE.opSUBS:
  1952.             BinOp(reg1, reg2);
  1953.             not(reg2);
  1954.             and(reg1, reg2);
  1955.             drop
  1956.  
  1957.         |CODE.opNOP:
  1958.  
  1959.         |CODE.opSWITCH:
  1960.             UnOp(reg1);
  1961.             IF param2 = 0 THEN
  1962.                 reg2 := rax
  1963.             ELSE
  1964.                 reg2 := r10
  1965.             END;
  1966.             IF reg1 # reg2 THEN
  1967.                 ASSERT(REG.GetReg(R, reg2));
  1968.                 ASSERT(REG.Exchange(R, reg1, reg2));
  1969.                 drop
  1970.             END;
  1971.             drop
  1972.  
  1973.         |CODE.opENDSW:
  1974.  
  1975.         |CODE.opCASEL:
  1976.             cmprc(rax, param1);
  1977.             jcc(jl, param2)
  1978.  
  1979.         |CODE.opCASER:
  1980.             cmprc(rax, param1);
  1981.             jcc(jg, param2)
  1982.  
  1983.         |CODE.opCASELR:
  1984.             cmprc(rax, param1);
  1985.             jcc(jl, param2);
  1986.             jcc(jg, cmd.param3)
  1987.  
  1988.         |CODE.opASR, CODE.opROR, CODE.opLSL, CODE.opLSR:
  1989.             BinOp(reg1, reg2);
  1990.             xchg(reg2, rcx);
  1991.             Rex(reg1, 0);
  1992.             OutByte(0D3H);
  1993.             X86.shift(cmd.opcode, reg1 MOD 8); // shift reg1, cl
  1994.             xchg(reg2, rcx);
  1995.             drop
  1996.  
  1997.         |CODE.opASR1, CODE.opROR1, CODE.opLSL1, CODE.opLSR1:
  1998.             reg1 := REG.GetAnyReg(R);
  1999.             movrc(reg1, param2);
  2000.             BinOp(reg1, reg2);
  2001.             xchg(reg1, rcx);
  2002.             Rex(reg2, 0);
  2003.             OutByte(0D3H);
  2004.             X86.shift(cmd.opcode, reg2 MOD 8); // shift reg2, cl
  2005.             xchg(reg1, rcx);
  2006.             drop;
  2007.             drop;
  2008.             ASSERT(REG.GetReg(R, reg2))
  2009.  
  2010.         |CODE.opASR2, CODE.opROR2, CODE.opLSL2, CODE.opLSR2:
  2011.             UnOp(reg1);
  2012.             shiftrc(cmd.opcode, reg1, ORD(BITS(param2) * {0..5}))
  2013.  
  2014.         |CODE.opGET:
  2015.             BinOp(reg1, reg2);
  2016.             drop;
  2017.             drop;
  2018.             _movrm(reg1, reg1, 0, param2 * 8, FALSE);
  2019.             _movrm(reg1, reg2, 0, param2 * 8, TRUE)
  2020.  
  2021.         |CODE.opCHKBYTE:
  2022.             BinOp(reg1, reg2);
  2023.             cmprc(reg1, 256);
  2024.             jcc(jb, param1)
  2025.  
  2026.         |CODE.opCHKIDX:
  2027.             UnOp(reg1);
  2028.             cmprc(reg1, param2);
  2029.             jcc(jb, param1)
  2030.  
  2031.         |CODE.opCHKIDX2:
  2032.             BinOp(reg1, reg2);
  2033.             IF param2 # -1 THEN
  2034.                 cmprr(reg2, reg1);
  2035.                 mov(reg1, reg2);
  2036.                 drop;
  2037.                 jcc(jb, param1)
  2038.             ELSE
  2039.                 INCL(R.regs, reg1);
  2040.                 DEC(R.top);
  2041.                 R.stk[R.top] := reg2
  2042.             END
  2043.  
  2044.         |CODE.opLENGTH:
  2045.             PushAll(2);
  2046.             CallRTL(CODE._length);
  2047.             GetRegA
  2048.  
  2049.         |CODE.opLENGTHW:
  2050.             PushAll(2);
  2051.             CallRTL(CODE._lengthw);
  2052.             GetRegA
  2053.  
  2054.         |CODE.opLEN:
  2055.             n := param2;
  2056.             UnOp(reg1);
  2057.             drop;
  2058.             EXCL(R.regs, reg1);
  2059.  
  2060.             WHILE n > 0 DO
  2061.                 UnOp(reg2);
  2062.                 drop;
  2063.                 DEC(n)
  2064.             END;
  2065.  
  2066.             INCL(R.regs, reg1);
  2067.             ASSERT(REG.GetReg(R, reg1))
  2068.  
  2069.         |CODE.opCHR:
  2070.             UnOp(reg1);
  2071.             andrc(reg1, 255)
  2072.  
  2073.         |CODE.opWCHR:
  2074.             UnOp(reg1);
  2075.             andrc(reg1, 65535)
  2076.  
  2077.         |CODE.opEQP, CODE.opNEP, CODE.opEQIP, CODE.opNEIP:
  2078.             UnOp(reg1);
  2079.             reg2 := REG.GetAnyReg(R);
  2080.  
  2081.             CASE cmd.opcode OF
  2082.             |CODE.opEQP, CODE.opNEP:
  2083.                 lea(reg2, param1, sCODE)
  2084.  
  2085.             |CODE.opEQIP, CODE.opNEIP:
  2086.                 lea(reg2, param1, sIMP);
  2087.                 movrm(reg2, reg2, 0)
  2088.             END;
  2089.  
  2090.             cmprr(reg1, reg2);
  2091.             drop;
  2092.             drop;
  2093.             reg1 := REG.GetAnyReg(R);
  2094.  
  2095.             CASE cmd.opcode OF
  2096.             |CODE.opEQP, CODE.opEQIP: setcc(sete,  reg1)
  2097.             |CODE.opNEP, CODE.opNEIP: setcc(setne, reg1)
  2098.             END;
  2099.  
  2100.             andrc(reg1, 1)
  2101.  
  2102.         |CODE.opINC1B, CODE.opDEC1B:
  2103.             UnOp(reg1);
  2104.             IF reg1 >= 8 THEN
  2105.                 OutByte(41H)
  2106.             END;
  2107.             OutByte2(0FEH, 8 * ORD(cmd.opcode = CODE.opDEC1B) + reg1 MOD 8); // inc/dec byte[reg1]
  2108.             drop
  2109.  
  2110.         |CODE.opINCCB, CODE.opDECCB:
  2111.             UnOp(reg1);
  2112.             IF reg1 >= 8 THEN
  2113.                 OutByte(41H)
  2114.             END;
  2115.             OutByte3(80H, 28H * ORD(cmd.opcode = CODE.opDECCB) + reg1 MOD 8, param2 MOD 256); // add/sub byte[reg1], param2 MOD 256
  2116.             drop
  2117.  
  2118.         |CODE.opINCB, CODE.opDECB:
  2119.             BinOp(reg1, reg2);
  2120.             IF (reg1 >= 8) OR (reg2 >= 8) THEN
  2121.                 OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
  2122.             END;
  2123.             OutByte2(28H * ORD(cmd.opcode = CODE.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); // add/sub byte[reg2], reg1_8
  2124.             drop;
  2125.             drop
  2126.  
  2127.         |CODE.opSAVEIP:
  2128.             UnOp(reg1);
  2129.             reg2 := REG.GetAnyReg(R);
  2130.             lea(reg2, param2, sIMP);
  2131.             movrm(reg2, reg2, 0);
  2132.             push(reg2);
  2133.             drop;
  2134.             IF reg1 >= 8 THEN
  2135.                 OutByte(41H)
  2136.             END;
  2137.             OutByte2(8FH, reg1 MOD 8); // pop qword[reg1]
  2138.             drop
  2139.  
  2140.         |CODE.opCLEANUP:
  2141.             n := param2 * 8;
  2142.             IF n # 0 THEN
  2143.                 addrc(rsp, n)
  2144.             END
  2145.  
  2146.         |CODE.opPOPSP:
  2147.             pop(rsp)
  2148.  
  2149.         |CODE.opLOADF:
  2150.             UnOp(reg1);
  2151.             INC(xmm);
  2152.             movsdrm(xmm, reg1, 0);
  2153.             drop
  2154.  
  2155.         |CODE.opPUSHF:
  2156.             subrc(rsp, 8);
  2157.             movsdmr(rsp, 0, xmm);
  2158.             DEC(xmm)
  2159.  
  2160.         |CODE.opCONSTF:
  2161.             float := cmd.float;
  2162.             INC(xmm);
  2163.             reg1 := REG.GetAnyReg(R);
  2164.             lea(reg1, Numbers_Offs + Numbers_Count * 8, sDATA);
  2165.             movsdrm(xmm, reg1, 0);
  2166.             drop;
  2167.             NewNumber(UTILS.splitf(float, a, b))
  2168.  
  2169.         |CODE.opSAVEF:
  2170.             UnOp(reg1);
  2171.             movsdmr(reg1, 0, xmm);
  2172.             DEC(xmm);
  2173.             drop
  2174.  
  2175.         |CODE.opADDF, CODE.opADDFI:
  2176.             opxx(58H, xmm - 1, xmm);
  2177.             DEC(xmm)
  2178.  
  2179.         |CODE.opSUBF:
  2180.             opxx(5CH, xmm - 1, xmm);
  2181.             DEC(xmm)
  2182.  
  2183.         |CODE.opSUBFI:
  2184.             opxx(5CH, xmm, xmm - 1);
  2185.             opxx(10H, xmm - 1, xmm);
  2186.             DEC(xmm)
  2187.  
  2188.         |CODE.opMULF:
  2189.             opxx(59H, xmm - 1, xmm);
  2190.             DEC(xmm)
  2191.  
  2192.         |CODE.opDIVF:
  2193.             opxx(5EH, xmm - 1, xmm);
  2194.             DEC(xmm)
  2195.  
  2196.         |CODE.opDIVFI:
  2197.             opxx(5EH, xmm, xmm - 1);
  2198.             opxx(10H, xmm - 1, xmm);
  2199.             DEC(xmm)
  2200.  
  2201.         |CODE.opUMINF:
  2202.             reg1 := REG.GetAnyReg(R);
  2203.             lea(reg1, Numbers_Offs, sDATA);
  2204.             OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // xorpd xmm, xmmword[reg1]
  2205.             OutByte2(57H, reg1 MOD 8 + (xmm MOD 8) * 8);
  2206.             drop
  2207.  
  2208.         |CODE.opFABS:
  2209.             reg1 := REG.GetAnyReg(R);
  2210.             lea(reg1, Numbers_Offs + 16, sDATA);
  2211.             OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // andpd xmm, xmmword[reg1]
  2212.             OutByte2(54H, reg1 MOD 8 + (xmm MOD 8) * 8);
  2213.             drop
  2214.  
  2215.         |CODE.opFLT:
  2216.             UnOp(reg1);
  2217.             INC(xmm);
  2218.             OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); // cvtsi2sd xmm, reg1
  2219.             OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
  2220.             drop
  2221.  
  2222.         |CODE.opFLOOR:
  2223.             reg1 := REG.GetAnyReg(R);
  2224.             subrc(rsp, 8);
  2225.             OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); // stmxcsr dword[rsp+4];
  2226.             OutByte2(00FH, 0AEH); OutByte2(01CH, 024H);       // stmxcsr dword[rsp];
  2227.             OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); // and dword[rsp],11111111111111111001111111111111b;
  2228.             OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); // or dword[rsp],00000000000000000010000000000000b;
  2229.             OutByte2(00FH, 0AEH); OutByte2(014H, 024H); // ldmxcsr dword[rsp];
  2230.             OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); // cvtsd2si reg1, xmm
  2231.             OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
  2232.             OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); // ldmxcsr dword[rsp+4];
  2233.             addrc(rsp, 8);
  2234.             DEC(xmm)
  2235.  
  2236.         |CODE.opEQF .. CODE.opGEFI:
  2237.             fcmp(cmd.opcode, xmm);
  2238.             DEC(xmm, 2)
  2239.  
  2240.         |CODE.opINF:
  2241.             INC(xmm);
  2242.             reg1 := REG.GetAnyReg(R);
  2243.             lea(reg1, Numbers_Offs + 32, sDATA);
  2244.             movsdrm(xmm, reg1, 0);
  2245.             drop
  2246.  
  2247.         |CODE.opPACK, CODE.opPACKC:
  2248.             IF cmd.opcode = CODE.opPACK THEN
  2249.                 BinOp(reg1, reg2)
  2250.             ELSE
  2251.                 UnOp(reg1);
  2252.                 reg2 := REG.GetAnyReg(R);
  2253.                 movrc(reg2, param2)
  2254.             END;
  2255.             push(reg1);
  2256.             movrm(reg1, reg1, 0);
  2257.             shiftrc(shl, reg1, 1);
  2258.             shiftrc(shr, reg1, 53);
  2259.             add(reg1, reg2);
  2260.             andrc(reg1, ORD({0..10}));
  2261.             shiftrc(shl, reg1, 52);
  2262.             movrm(reg2, rsp, 0);
  2263.             movrm(reg2, reg2, 0);
  2264.  
  2265.             push(reg1);
  2266.             lea(reg1, Numbers_Offs + 40, sDATA); // {0..51, 63}
  2267.             movrm(reg1, reg1, 0);
  2268.             and(reg2, reg1);
  2269.             pop(reg1);
  2270.  
  2271.             or(reg2, reg1);
  2272.             pop(reg1);
  2273.             movmr(reg1, 0, reg2);
  2274.             drop;
  2275.             drop
  2276.  
  2277.         |CODE.opUNPK, CODE.opLADR_UNPK:
  2278.  
  2279.             IF cmd.opcode = CODE.opLADR_UNPK THEN
  2280.                 n := param2 * 8;
  2281.                 UnOp(reg1);
  2282.                 reg2 := REG.GetVarReg(R, param2);
  2283.                 regVar := reg2 # -1;
  2284.                 IF ~regVar THEN
  2285.                     reg2 := REG.GetAnyReg(R);
  2286.                     Rex(0, reg2);
  2287.                     OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8);  // lea reg2, qword[rbp+n]
  2288.                     OutIntByte(n)
  2289.                 END
  2290.             ELSE
  2291.                 BinOp(reg1, reg2);
  2292.                 regVar := FALSE
  2293.             END;
  2294.  
  2295.             push(reg1);
  2296.             movrm(reg1, reg1, 0);
  2297.             shiftrc(shl, reg1, 1);
  2298.             shiftrc(shr, reg1, 53);
  2299.             subrc(reg1, 1023);
  2300.  
  2301.             IF regVar THEN
  2302.                 mov(reg2, reg1);
  2303.                 reg2 := REG.GetAnyReg(R)
  2304.             ELSE
  2305.                 movmr(reg2, 0, reg1)
  2306.             END;
  2307.  
  2308.             pop(reg2);
  2309.             movrm(reg1, reg2, 0);
  2310.  
  2311.             push(reg2);
  2312.             lea(reg2, Numbers_Offs + 48, sDATA); // {52..61}
  2313.             movrm(reg2, reg2, 0);
  2314.             or(reg1, reg2);
  2315.             pop(reg2);
  2316.  
  2317.             Rex(reg1, 0);
  2318.             OutByte2(0FH, 0BAH);
  2319.             OutByte2(0F0H + reg1 MOD 8, 3EH); // btr reg1, 62
  2320.             movmr(reg2, 0, reg1);
  2321.             drop;
  2322.             drop
  2323.  
  2324.         |CODE.opSADR_PARAM:
  2325.             pushDA(stroffs + param2)
  2326.  
  2327.         |CODE.opVADR_PARAM:
  2328.             pushm(rbp, param2 * 8)
  2329.  
  2330.         |CODE.opLOAD64_PARAM:
  2331.             UnOp(reg1);
  2332.             pushm(reg1, 0);
  2333.             drop
  2334.  
  2335.         |CODE.opLLOAD64_PARAM:
  2336.             reg1 := REG.GetVarReg(R, param2);
  2337.             IF reg1 # -1 THEN
  2338.                 push(reg1)
  2339.             ELSE
  2340.                 pushm(rbp, param2 * 8)
  2341.             END
  2342.  
  2343.         |CODE.opGLOAD64_PARAM:
  2344.             reg2 := REG.GetAnyReg(R);
  2345.             lea(reg2, param2, sBSS);
  2346.             movrm(reg2, reg2, 0);
  2347.             push(reg2);
  2348.             drop
  2349.  
  2350.         |CODE.opCONST_PARAM:
  2351.             pushc(param2)
  2352.  
  2353.         |CODE.opGLOAD32_PARAM:
  2354.             reg1 := REG.GetAnyReg(R);
  2355.             xor(reg1, reg1);
  2356.             lea(reg1, param2, sBSS);
  2357.             movrm32(reg1, reg1, 0);
  2358.             push(reg1);
  2359.             drop
  2360.  
  2361.         |CODE.opLOAD32_PARAM:
  2362.             UnOp(reg1);
  2363.             movrm32(reg1, reg1, 0);
  2364.             shiftrc(shl, reg1, 32);
  2365.             shiftrc(shr, reg1, 32);
  2366.             push(reg1);
  2367.             drop
  2368.  
  2369.         |CODE.opLLOAD32_PARAM:
  2370.             reg1 := REG.GetAnyReg(R);
  2371.             xor(reg1, reg1);
  2372.             reg2 := REG.GetVarReg(R, param2);
  2373.             IF reg2 # -1 THEN
  2374.                 mov(reg1, reg2)
  2375.             ELSE
  2376.                 movrm32(reg1, rbp, param2 * 8)
  2377.             END;
  2378.             push(reg1);
  2379.             drop
  2380.  
  2381.         |CODE.opLADR_SAVEC:
  2382.             n := param1 * 8;
  2383.             reg1 := REG.GetVarReg(R, param1);
  2384.             IF reg1 # -1 THEN
  2385.                 movrc(reg1, param2)
  2386.             ELSE
  2387.                 IF isLong(param2) THEN
  2388.                     reg2 := REG.GetAnyReg(R);
  2389.                     movrc(reg2, param2);
  2390.                     movmr(rbp, n, reg2);
  2391.                     drop
  2392.                 ELSE
  2393.                     OutByte3(48H, 0C7H, 45H + long(n)); // mov qword[rbp+n],param2
  2394.                     OutIntByte(n);
  2395.                     OutInt(param2)
  2396.                 END
  2397.             END
  2398.  
  2399.         |CODE.opGADR_SAVEC:
  2400.             IF isLong(param2) THEN
  2401.                 reg1 := REG.GetAnyReg(R);
  2402.                 movrc(reg1, param2);
  2403.                 reg2 := REG.GetAnyReg(R);
  2404.                 lea(reg2, param1, sBSS);
  2405.                 movmr(reg2, 0, reg1);
  2406.                 drop;
  2407.                 drop
  2408.             ELSE
  2409.                 reg2 := REG.GetAnyReg(R);
  2410.                 lea(reg2, param1, sBSS);
  2411.                 Rex(reg2, 0);
  2412.                 OutByte2(0C7H, reg2 MOD 8); // mov qword[reg2], param2
  2413.                 OutInt(param2);
  2414.                 drop
  2415.             END
  2416.  
  2417.         |CODE.opLADR_SAVE:
  2418.             UnOp(reg1);
  2419.             reg2 := REG.GetVarReg(R, param2);
  2420.             IF reg2 # -1 THEN
  2421.                 mov(reg2, reg1)
  2422.             ELSE
  2423.                 movmr(rbp, param2 * 8, reg1)
  2424.             END;
  2425.             drop
  2426.  
  2427.         |CODE.opLADR_INC1:
  2428.             reg1 := REG.GetVarReg(R, param2);
  2429.             IF reg1 # -1 THEN
  2430.                 incr(reg1)
  2431.             ELSE
  2432.                 n := param2 * 8;
  2433.                 OutByte3(48H, 0FFH, 45H + long(n)); // inc qword[rbp+n]
  2434.                 OutIntByte(n)
  2435.             END
  2436.  
  2437.         |CODE.opLADR_DEC1:
  2438.             reg1 := REG.GetVarReg(R, param2);
  2439.             IF reg1 # -1 THEN
  2440.                 decr(reg1)
  2441.             ELSE
  2442.                 n := param2 * 8;
  2443.                 OutByte3(48H, 0FFH, 4DH + long(n)); // dec qword[rbp+n]
  2444.                 OutIntByte(n)
  2445.             END
  2446.  
  2447.         |CODE.opLADR_INCC, CODE.opLADR_DECC:
  2448.             reg1 := REG.GetVarReg(R, param1);
  2449.             IF isLong(param2) THEN
  2450.                 reg2 := REG.GetAnyReg(R);
  2451.                 movrc(reg2, param2);
  2452.                 IF reg1 # -1 THEN
  2453.                     IF cmd.opcode = CODE.opLADR_DECC THEN
  2454.                         sub(reg1, reg2)
  2455.                     ELSE
  2456.                         add(reg1, reg2)
  2457.                     END
  2458.                 ELSE
  2459.                     n := param1 * 8;
  2460.                     Rex(0, reg2);
  2461.                     OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DECC), 45H + long(n) + (reg2 MOD 8) * 8);
  2462.                     OutIntByte(n) // add/sub qword[rbp+n],reg2
  2463.                 END;
  2464.                 drop
  2465.             ELSE
  2466.                 IF reg1 # -1 THEN
  2467.                     IF cmd.opcode = CODE.opLADR_DECC THEN
  2468.                         subrc(reg1, param2)
  2469.                     ELSE
  2470.                         addrc(reg1, param2)
  2471.                     END
  2472.                 ELSE
  2473.                     n := param1 * 8;
  2474.                     OutByte3(48H, 81H + short(param2), 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECC));
  2475.                     OutIntByte(n);
  2476.                     OutIntByte(param2) // add/sub qword[rbp+n],param2
  2477.                 END
  2478.             END
  2479.  
  2480.         |CODE.opLADR_INC1B, CODE.opLADR_DEC1B:
  2481.             reg1 := REG.GetVarReg(R, param2);
  2482.             IF reg1 # -1 THEN
  2483.                 IF cmd.opcode = CODE.opLADR_DEC1B THEN
  2484.                     decr(reg1)
  2485.                 ELSE
  2486.                     incr(reg1)
  2487.                 END;
  2488.                 andrc(reg1, 255)
  2489.             ELSE
  2490.                 n := param2 * 8;
  2491.                 OutByte2(0FEH, 45H + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_DEC1B));
  2492.                 OutIntByte(n)  // inc/dec byte[rbp+n]
  2493.             END
  2494.  
  2495.         |CODE.opLADR_INCCB, CODE.opLADR_DECCB:
  2496.             reg1 := REG.GetVarReg(R, param1);
  2497.             param2 := param2 MOD 256;
  2498.             IF reg1 # -1 THEN
  2499.                 IF cmd.opcode = CODE.opLADR_DECCB THEN
  2500.                     subrc(reg1, param2)
  2501.                 ELSE
  2502.                     addrc(reg1, param2)
  2503.                 END;
  2504.                 andrc(reg1, 255)
  2505.             ELSE
  2506.                 n := param1 * 8;
  2507.                 OutByte2(80H, 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECCB));
  2508.                 OutIntByte(n);
  2509.                 OutByte(param2) // add/sub byte[rbp+n],param2
  2510.             END
  2511.  
  2512.         |CODE.opLADR_INC, CODE.opLADR_DEC:
  2513.             UnOp(reg1);
  2514.             reg2 := REG.GetVarReg(R, param2);
  2515.             IF reg2 # -1 THEN
  2516.                 IF cmd.opcode = CODE.opLADR_DEC THEN
  2517.                     sub(reg2, reg1)
  2518.                 ELSE
  2519.                     add(reg2, reg1)
  2520.                 END
  2521.             ELSE
  2522.                 n := param2 * 8;
  2523.                 Rex(0, reg1);
  2524.                 OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
  2525.                 OutIntByte(n) // add/sub qword[rbp+n],reg1
  2526.             END;
  2527.             drop
  2528.  
  2529.         |CODE.opLADR_INCB, CODE.opLADR_DECB:
  2530.             UnOp(reg1);
  2531.             reg2 := REG.GetVarReg(R, param2);
  2532.             IF reg2 # -1 THEN
  2533.                 IF cmd.opcode = CODE.opLADR_DECB THEN
  2534.                     sub(reg2, reg1)
  2535.                 ELSE
  2536.                     add(reg2, reg1)
  2537.                 END;
  2538.                 andrc(reg2, 255)
  2539.             ELSE
  2540.                 n := param2 * 8;
  2541.                 IF reg1 >= 8 THEN
  2542.                     OutByte(44H)
  2543.                 END;
  2544.                 OutByte2(28H * ORD(cmd.opcode = CODE.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
  2545.                 OutIntByte(n) // add/sub byte[rbp+n], reg1_8
  2546.             END;
  2547.             drop
  2548.  
  2549.         |CODE.opLADR_INCL, CODE.opLADR_EXCL:
  2550.             UnOp(reg1);
  2551.             cmprc(reg1, 64);
  2552.             reg2 := REG.GetVarReg(R, param2);
  2553.             IF reg2 # -1 THEN
  2554.                 OutByte2(73H, 4); // jnb L
  2555.                 oprr2(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), reg2, reg1) // bts/btr reg2, reg1
  2556.             ELSE
  2557.                 n := param2 * 8;
  2558.                 OutByte2(73H, 5 + 3 * ORD(~isByte(n))); // jnb L
  2559.                 Rex(0, reg1);
  2560.                 OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
  2561.                 OutIntByte(n) // bts/btr qword[rbp+n], reg1
  2562.             END;
  2563.             // L:
  2564.             drop
  2565.  
  2566.         |CODE.opLADR_INCLC, CODE.opLADR_EXCLC:
  2567.             reg1 := REG.GetVarReg(R, param1);
  2568.             IF reg1 # -1 THEN
  2569.                 Rex(reg1, 0);
  2570.                 OutByte3(0FH, 0BAH, 0E8H);  // bts/btr reg1, param2
  2571.                 OutByte2(reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC), param2)
  2572.             ELSE
  2573.                 n := param1 * 8;
  2574.                 OutByte3(48H, 0FH, 0BAH);  // bts/btr qword[rbp+n], param2
  2575.                 OutByte(6DH + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC));
  2576.                 OutIntByte(n);
  2577.                 OutByte(param2)
  2578.             END
  2579.  
  2580.         |CODE.opLOOP, CODE.opENDLOOP:
  2581.  
  2582.         END;
  2583.  
  2584.         cmd := cmd.next(COMMAND)
  2585.     END;
  2586.  
  2587.     ASSERT(R.pushed = 0);
  2588.     ASSERT(R.top = -1);
  2589.     ASSERT(xmm = -1)
  2590. END translate;
  2591.  
  2592.  
  2593. PROCEDURE prolog (code: CODE.CODES; modname: ARRAY OF CHAR; target, stack_size: INTEGER);
  2594. VAR
  2595.     ModName_Offs, entry: INTEGER;
  2596.  
  2597. BEGIN
  2598.     ModName_Offs := CHL.Length(code.types) * 8 + CHL.Length(code.data);
  2599.     Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
  2600.     ASSERT(MACHINE.Align(Numbers_Offs, 16));
  2601.  
  2602.     entry := NewLabel();
  2603.     X86.SetLabel(entry);
  2604.  
  2605.     IF target = mConst.Target_iDLL64 THEN
  2606.         dllret := NewLabel();
  2607.         push(r8);
  2608.         push(rdx);
  2609.         push(rcx);
  2610.         CallRTL(CODE._dllentry);
  2611.         test(rax);
  2612.         jcc(je, dllret)
  2613.     END;
  2614.  
  2615.     push(rsp);
  2616.     lea(rax, entry, sCODE);
  2617.     push(rax);
  2618.     pushDA(0); //TYPES
  2619.     pushc(CHL.Length(code.types));
  2620.     pushDA(ModName_Offs); //MODNAME
  2621.     CallRTL(CODE._init)
  2622. END prolog;
  2623.  
  2624.  
  2625. PROCEDURE epilog (code: CODE.CODES; modname: ARRAY OF CHAR; target: INTEGER);
  2626. VAR
  2627.     i, n: INTEGER;
  2628.     number: Number;
  2629.     exp: CODE.EXPORT_PROC;
  2630.  
  2631.  
  2632.     PROCEDURE import (imp: LISTS.LIST);
  2633.     VAR
  2634.         lib:  CODE.IMPORT_LIB;
  2635.         proc: CODE.IMPORT_PROC;
  2636.  
  2637.     BEGIN
  2638.  
  2639.         lib := imp.first(CODE.IMPORT_LIB);
  2640.         WHILE lib # NIL DO
  2641.             BIN.Import(prog, lib.name, 0);
  2642.             proc := lib.procs.first(CODE.IMPORT_PROC);
  2643.             WHILE proc # NIL DO
  2644.                 BIN.Import(prog, proc.name, proc.label);
  2645.                 proc := proc.next(CODE.IMPORT_PROC)
  2646.             END;
  2647.             lib := lib.next(CODE.IMPORT_LIB)
  2648.         END
  2649.  
  2650.     END import;
  2651.  
  2652.  
  2653. BEGIN
  2654.     IF target = mConst.Target_iDLL64 THEN
  2655.         X86.SetLabel(dllret);
  2656.         OutByte(0C3H) // ret
  2657.     ELSE
  2658.         pushc(0);
  2659.         CallRTL(CODE._exit)
  2660.     END;
  2661.  
  2662.     X86.fixup;
  2663.  
  2664.     i := 0;
  2665.     WHILE i < CHL.Length(code.types) DO
  2666.         BIN.PutData64LE(prog, CHL.GetInt(code.types, i));
  2667.         INC(i)
  2668.     END;
  2669.  
  2670.     i := 0;
  2671.     WHILE i < CHL.Length(code.data) DO
  2672.         BIN.PutData(prog, CHL.GetByte(code.data, i));
  2673.         INC(i)
  2674.     END;
  2675.  
  2676.     BIN.PutDataStr(prog, modname);
  2677.     BIN.PutData(prog, 0);
  2678.     n := CHL.Length(prog.data);
  2679.     ASSERT(MACHINE.Align(n, 16));
  2680.     i := n - CHL.Length(prog.data);
  2681.     WHILE i > 0 DO
  2682.         BIN.PutData(prog, 0);
  2683.         DEC(i)
  2684.     END;
  2685.     number := Numbers.first(Number);
  2686.     FOR i := 0 TO Numbers_Count - 1 DO
  2687.         BIN.PutData64LE(prog, number.value);
  2688.         number := number.next(Number)
  2689.     END;
  2690.  
  2691.     exp := code.export.first(CODE.EXPORT_PROC);
  2692.     WHILE exp # NIL DO
  2693.         BIN.Export(prog, exp.name, exp.label);
  2694.         exp := exp.next(CODE.EXPORT_PROC)
  2695.     END;
  2696.  
  2697.     import(code.import)
  2698. END epilog;
  2699.  
  2700.  
  2701. PROCEDURE rload (reg, offs, size: INTEGER);
  2702. BEGIN
  2703.     offs := offs * 8;
  2704.     CASE size OF
  2705.     |1: movzx(reg, rbp, offs, FALSE)
  2706.     |2: movzx(reg, rbp, offs, TRUE)
  2707.     |4: xor(reg, reg); movrm32(reg, rbp, offs)
  2708.     |8: movrm(reg, rbp, offs)
  2709.     END
  2710. END rload;
  2711.  
  2712.  
  2713. PROCEDURE rsave (reg, offs, size: INTEGER);
  2714. BEGIN
  2715.     offs := offs * 8;
  2716.     CASE size OF
  2717.     |1: movmr8(rbp, offs, reg)
  2718.     |2: movmr16(rbp, offs, reg)
  2719.     |4: movmr32(rbp, offs, reg)
  2720.     |8: movmr(rbp, offs, reg)
  2721.     END
  2722. END rsave;
  2723.  
  2724.  
  2725. PROCEDURE CodeGen* (code: CODE.CODES; outname: ARRAY OF CHAR; target, stack, base: INTEGER);
  2726. VAR
  2727.     path, modname, ext: PATHS.PATH;
  2728.     n: INTEGER;
  2729.  
  2730. BEGIN
  2731.     Win64RegPar[0] := rcx;
  2732.     Win64RegPar[1] := rdx;
  2733.     Win64RegPar[2] := r8;
  2734.     Win64RegPar[3] := r9;
  2735.  
  2736.     SystemVRegPar[0] := rdi;
  2737.     SystemVRegPar[1] := rsi;
  2738.     SystemVRegPar[2] := rdx;
  2739.     SystemVRegPar[3] := rcx;
  2740.     SystemVRegPar[4] := r8;
  2741.     SystemVRegPar[5] := r9;
  2742.  
  2743.     PATHS.split(outname, path, modname, ext);
  2744.     S.append(modname, ext);
  2745.  
  2746.     R := REG.Create(push, pop, mov, xchg, rload, rsave, {rax, r10, r11}, {rcx, rdx, r8, r9});
  2747.  
  2748.     n := code.dmin - CHL.Length(code.data);
  2749.     IF n > 0 THEN
  2750.         INC(code.bss, n)
  2751.     END;
  2752.     code.bss := MAX(code.bss, 8);
  2753.  
  2754.     Numbers := LISTS.create(NIL);
  2755.     Numbers_Count := 0;
  2756.     NewNumber(ROR(1, 1));      (* 8000000000000000H *)
  2757.     NewNumber(0);
  2758.     NewNumber(ROR(-2, 1));     (* 7FFFFFFFFFFFFFFFH *)
  2759.     NewNumber(-1);
  2760.     NewNumber(ROR(7FFH, 12));  (* +Infinity *)
  2761.     NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1))));  (* {0..51, 63} *)
  2762.     NewNumber(LSR(ASR(ROR(1, 1), 9), 2));  (* {52..61} *)
  2763.  
  2764.     prog := BIN.create(code.lcount);
  2765.     BIN.SetParams(prog, code.bss, stack, WCHR(1), WCHR(0));
  2766.  
  2767.     X86.SetProgram(prog);
  2768.  
  2769.     prolog(code, modname, target, stack);
  2770.     translate(code.commands, CHL.Length(code.types) * 8);
  2771.     epilog(code, modname, target);
  2772.  
  2773.     BIN.fixup(prog);
  2774.     IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
  2775.         PE32.write(prog, outname, base, target = mConst.Target_iConsole64, target = mConst.Target_iDLL64, TRUE)
  2776.     ELSIF target = mConst.Target_iELF64 THEN
  2777.         ELF.write(prog, outname, TRUE)
  2778.     END
  2779. END CodeGen;
  2780.  
  2781.  
  2782. END AMD64.