Subversion Repositories Kolibri OS

Rev

Rev 8859 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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