Subversion Repositories Kolibri OS

Rev

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

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