Subversion Repositories Kolibri OS

Rev

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

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