Subversion Repositories Kolibri OS

Rev

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

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