Subversion Repositories Kolibri OS

Rev

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