Subversion Repositories Kolibri OS

Rev

Rev 9873 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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