Subversion Repositories Kolibri OS

Rev

Rev 7597 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
7597 akron1 1
(*
2
    BSD 2-Clause License
6613 leency 3
 
7597 akron1 4
    Copyright (c) 2018, 2019, Anton Krotov
5
    All rights reserved.
6613 leency 6
*)
7
 
8
MODULE X86;
9
 
7597 akron1 10
IMPORT CODE, REG, UTILS, LISTS, BIN, PE32, KOS, MSCOFF, ELF, mConst := CONSTANTS, MACHINE, CHL := CHUNKLISTS, PATHS;
6613 leency 11
 
7597 akron1 12
 
6613 leency 13
CONST
14
 
7597 akron1 15
    eax = REG.R0; ecx = REG.R1; edx = REG.R2;
6613 leency 16
 
7597 akron1 17
    al = eax; cl = ecx; dl = edx; ah = 4;
6613 leency 18
 
7597 akron1 19
    ax = eax; cx = ecx; dx = edx;
6613 leency 20
 
7597 akron1 21
    esp = 4;
22
    ebp = 5;
6613 leency 23
 
7597 akron1 24
    sete = 94H; setne = 95H; setl = 9CH; setge = 9DH; setle = 9EH; setg = 9FH; setc = 92H; setnc = 93H;
6613 leency 25
 
7597 akron1 26
    je = 84H; jne = 85H; jl = 8CH; jge = 8DH; jle = 8EH; jg = 8FH; jb = 82H; jnb = 83H;
6613 leency 27
 
28
 
7597 akron1 29
    CODECHUNK = 8;
6613 leency 30
 
31
 
32
TYPE
33
 
7597 akron1 34
    COMMAND = CODE.COMMAND;
6613 leency 35
 
36
 
7597 akron1 37
    ANYCODE = POINTER TO RECORD (LISTS.ITEM)
6613 leency 38
 
7597 akron1 39
        offset: INTEGER
6613 leency 40
 
7597 akron1 41
    END;
6613 leency 42
 
7597 akron1 43
    TCODE = POINTER TO RECORD (ANYCODE)
6613 leency 44
 
7597 akron1 45
        code:    ARRAY CODECHUNK OF BYTE;
46
        length:  INTEGER
6613 leency 47
 
7597 akron1 48
    END;
6613 leency 49
 
7597 akron1 50
    LABEL = POINTER TO RECORD (ANYCODE)
6613 leency 51
 
7597 akron1 52
        label: INTEGER
6613 leency 53
 
7597 akron1 54
    END;
6613 leency 55
 
7597 akron1 56
    JUMP = POINTER TO RECORD (ANYCODE)
7209 akron1 57
 
7597 akron1 58
        label, diff: INTEGER;
59
        short: BOOLEAN
6613 leency 60
 
7597 akron1 61
    END;
6613 leency 62
 
7597 akron1 63
    JMP = POINTER TO RECORD (JUMP)
6613 leency 64
 
7597 akron1 65
    END;
6613 leency 66
 
7597 akron1 67
    JCC = POINTER TO RECORD (JUMP)
6613 leency 68
 
7597 akron1 69
        jmp: INTEGER
6613 leency 70
 
71
    END;
72
 
7597 akron1 73
    CALL = POINTER TO RECORD (JUMP)
6613 leency 74
 
7597 akron1 75
    END;
6613 leency 76
 
7597 akron1 77
    RELOC = POINTER TO RECORD (ANYCODE)
6613 leency 78
 
7597 akron1 79
        op, value: INTEGER
6613 leency 80
 
7597 akron1 81
    END;
6613 leency 82
 
83
 
7597 akron1 84
VAR
6613 leency 85
 
7597 akron1 86
    R: REG.REGS;
6613 leency 87
 
7597 akron1 88
    program: BIN.PROGRAM;
6613 leency 89
 
7597 akron1 90
    CodeList: LISTS.LIST;
6613 leency 91
 
92
 
7597 akron1 93
PROCEDURE Byte (n: INTEGER): BYTE;
94
    RETURN MACHINE.Byte(n, 0)
95
END Byte;
6613 leency 96
 
97
 
7597 akron1 98
PROCEDURE Word (n: INTEGER): INTEGER;
99
    RETURN MACHINE.Byte(n, 0) + MACHINE.Byte(n, 1) * 256
100
END Word;
6613 leency 101
 
102
 
7597 akron1 103
PROCEDURE OutByte* (n: BYTE);
104
VAR
105
    c: TCODE;
106
    last: ANYCODE;
6613 leency 107
 
7597 akron1 108
BEGIN
109
    last := CodeList.last(ANYCODE);
6613 leency 110
 
7597 akron1 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
6613 leency 121
 
7597 akron1 122
END OutByte;
6613 leency 123
 
124
 
7597 akron1 125
PROCEDURE OutInt (n: INTEGER);
6613 leency 126
BEGIN
7597 akron1 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;
6613 leency 132
 
133
 
7597 akron1 134
PROCEDURE OutByte2 (a, b: BYTE);
6613 leency 135
BEGIN
7597 akron1 136
    OutByte(a);
137
    OutByte(b)
138
END OutByte2;
6613 leency 139
 
140
 
7597 akron1 141
PROCEDURE OutByte3 (a, b, c: BYTE);
6613 leency 142
BEGIN
7597 akron1 143
    OutByte(a);
144
    OutByte(b);
145
    OutByte(c)
146
END OutByte3;
6613 leency 147
 
148
 
7597 akron1 149
PROCEDURE OutWord (n: INTEGER);
6613 leency 150
BEGIN
7597 akron1 151
    ASSERT((0 <= n) & (n <= 65535));
152
    OutByte2(n MOD 256, n DIV 256)
153
END OutWord;
6613 leency 154
 
155
 
7597 akron1 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);
6613 leency 172
BEGIN
7597 akron1 173
    IF isByte(n) THEN
174
        OutByte(Byte(n))
175
    ELSE
176
        OutInt(n)
177
    END
178
END OutIntByte;
6613 leency 179
 
7597 akron1 180
 
181
PROCEDURE shift* (op, reg: INTEGER);
6613 leency 182
BEGIN
7597 akron1 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;
6613 leency 190
 
7597 akron1 191
 
192
PROCEDURE mov (reg1, reg2: INTEGER);
6613 leency 193
BEGIN
7597 akron1 194
    OutByte2(89H, 0C0H + reg2 * 8 + reg1)  // mov reg1, reg2
195
END mov;
6613 leency 196
 
7597 akron1 197
 
198
PROCEDURE xchg (reg1, reg2: INTEGER);
199
VAR
200
    regs: SET;
201
 
6613 leency 202
BEGIN
7597 akron1 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;
6613 leency 212
 
7597 akron1 213
 
214
PROCEDURE pop (reg: INTEGER);
6613 leency 215
BEGIN
7597 akron1 216
    OutByte(58H + reg) // pop reg
217
END pop;
6613 leency 218
 
7597 akron1 219
 
220
PROCEDURE push (reg: INTEGER);
6613 leency 221
BEGIN
7597 akron1 222
    OutByte(50H + reg) // push reg
223
END push;
6613 leency 224
 
7597 akron1 225
 
226
PROCEDURE movrc (reg, n: INTEGER);
6613 leency 227
BEGIN
7597 akron1 228
    OutByte(0B8H + reg); // mov reg, n
229
    OutInt(n)
230
END movrc;
6613 leency 231
 
7597 akron1 232
 
233
PROCEDURE pushc (n: INTEGER);
6613 leency 234
BEGIN
7597 akron1 235
    OutByte(68H + short(n)); // push n
236
    OutIntByte(n)
237
END pushc;
6613 leency 238
 
7597 akron1 239
 
240
PROCEDURE test (reg: INTEGER);
6613 leency 241
BEGIN
7597 akron1 242
    OutByte2(85H, 0C0H + reg * 9)  // test reg, reg
243
END test;
6613 leency 244
 
7597 akron1 245
 
246
PROCEDURE neg (reg: INTEGER);
6613 leency 247
BEGIN
7597 akron1 248
    OutByte2(0F7H, 0D8H + reg)  // neg reg
249
END neg;
6613 leency 250
 
7597 akron1 251
 
252
PROCEDURE not (reg: INTEGER);
6613 leency 253
BEGIN
7597 akron1 254
    OutByte2(0F7H, 0D0H + reg)  // not reg
255
END not;
6613 leency 256
 
7597 akron1 257
 
258
PROCEDURE add (reg1, reg2: INTEGER);
6613 leency 259
BEGIN
7597 akron1 260
    OutByte2(01H, 0C0H + reg2 * 8 + reg1)  // add reg1, reg2
261
END add;
6613 leency 262
 
7597 akron1 263
 
264
PROCEDURE andrc (reg, n: INTEGER);
6613 leency 265
BEGIN
7597 akron1 266
    OutByte2(81H + short(n), 0E0H + reg);  // and reg, n
267
    OutIntByte(n)
268
END andrc;
6613 leency 269
 
7597 akron1 270
 
271
PROCEDURE orrc (reg, n: INTEGER);
6613 leency 272
BEGIN
7597 akron1 273
    OutByte2(81H + short(n), 0C8H + reg);  // or reg, n
274
    OutIntByte(n)
275
END orrc;
6613 leency 276
 
7597 akron1 277
 
278
PROCEDURE addrc (reg, n: INTEGER);
6613 leency 279
BEGIN
7597 akron1 280
    OutByte2(81H + short(n), 0C0H + reg);  // add reg, n
281
    OutIntByte(n)
282
END addrc;
6613 leency 283
 
7597 akron1 284
 
285
PROCEDURE subrc (reg, n: INTEGER);
6613 leency 286
BEGIN
7597 akron1 287
    OutByte2(81H + short(n), 0E8H + reg);  // sub reg, n
288
    OutIntByte(n)
289
END subrc;
6613 leency 290
 
7597 akron1 291
 
292
PROCEDURE cmprr (reg1, reg2: INTEGER);
6613 leency 293
BEGIN
7597 akron1 294
    OutByte2(39H, 0C0H + reg2 * 8 + reg1)  // cmp reg1, reg2
295
END cmprr;
6613 leency 296
 
7597 akron1 297
 
298
PROCEDURE cmprc (reg, n: INTEGER);
6613 leency 299
BEGIN
7597 akron1 300
    OutByte2(81H + short(n), 0F8H + reg);  // cmp reg, n
301
    OutIntByte(n)
302
END cmprc;
6613 leency 303
 
7597 akron1 304
 
305
PROCEDURE setcc (cond, reg: INTEGER);
6613 leency 306
BEGIN
7597 akron1 307
    OutByte3(0FH, cond, 0C0H + reg)  // setcc reg
308
END setcc;
6613 leency 309
 
7597 akron1 310
 
7667 akron1 311
PROCEDURE xor (reg1, reg2: INTEGER);
312
BEGIN
313
    OutByte2(31H, 0C0H + reg2 * 8 + reg1) // xor reg1, reg2
314
END xor;
315
 
316
 
7597 akron1 317
PROCEDURE drop;
6613 leency 318
BEGIN
7597 akron1 319
    REG.Drop(R)
320
END drop;
6613 leency 321
 
7597 akron1 322
 
323
PROCEDURE log2* (x: INTEGER): INTEGER;
324
VAR
325
    n: INTEGER;
326
 
6613 leency 327
BEGIN
7597 akron1 328
    ASSERT(x > 0);
6613 leency 329
 
7597 akron1 330
    n := 0;
331
    WHILE ~ODD(x) DO
332
        x := x DIV 2;
333
        INC(n)
6613 leency 334
    END;
7597 akron1 335
 
336
    IF x # 1 THEN
337
        n := -1
6613 leency 338
    END
339
 
7597 akron1 340
    RETURN n
341
END log2;
6613 leency 342
 
343
 
7597 akron1 344
PROCEDURE cond* (op: INTEGER): INTEGER;
345
VAR
346
    res: INTEGER;
6613 leency 347
 
348
BEGIN
7597 akron1 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
6613 leency 357
 
7597 akron1 358
    RETURN res
359
END cond;
360
 
361
 
362
PROCEDURE inv1* (op: INTEGER): INTEGER;
6613 leency 363
BEGIN
7597 akron1 364
    IF ODD(op) THEN
365
        DEC(op)
6613 leency 366
    ELSE
7597 akron1 367
        INC(op)
6613 leency 368
    END
369
 
7597 akron1 370
    RETURN op
371
END inv1;
6613 leency 372
 
373
 
7597 akron1 374
PROCEDURE Reloc* (op, value: INTEGER);
375
VAR
376
    reloc: RELOC;
6613 leency 377
 
378
BEGIN
7597 akron1 379
    NEW(reloc);
380
    reloc.op := op;
381
    reloc.value := value;
382
    LISTS.push(CodeList, reloc)
383
END Reloc;
6613 leency 384
 
385
 
7597 akron1 386
PROCEDURE jcc* (cc, label: INTEGER);
387
VAR
388
    j: JCC;
6613 leency 389
 
390
BEGIN
7597 akron1 391
    NEW(j);
392
    j.label := label;
393
    j.jmp   := cc;
394
    j.short := FALSE;
395
    LISTS.push(CodeList, j)
396
END jcc;
6613 leency 397
 
398
 
7597 akron1 399
PROCEDURE jmp* (label: INTEGER);
400
VAR
401
    j: JMP;
6613 leency 402
 
403
BEGIN
7597 akron1 404
    NEW(j);
405
    j.label := label;
406
    j.short := FALSE;
407
    LISTS.push(CodeList, j)
408
END jmp;
6613 leency 409
 
410
 
7597 akron1 411
PROCEDURE call* (label: INTEGER);
412
VAR
413
    c: CALL;
6613 leency 414
 
415
BEGIN
7597 akron1 416
    NEW(c);
417
    c.label := label;
418
    c.short := TRUE;
419
    LISTS.push(CodeList, c)
420
END call;
6613 leency 421
 
422
 
7597 akron1 423
PROCEDURE Pic (reg, opcode, value: INTEGER);
6613 leency 424
BEGIN
7597 akron1 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;
6613 leency 431
 
432
 
7597 akron1 433
PROCEDURE CallRTL (pic: BOOLEAN; proc: INTEGER);
434
VAR
435
    label: INTEGER;
436
    reg1:  INTEGER;
6613 leency 437
 
438
BEGIN
7597 akron1 439
    label := CODE.codes.rtl[proc];
6613 leency 440
 
7597 akron1 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;
6613 leency 456
 
457
 
7597 akron1 458
PROCEDURE SetLabel* (label: INTEGER);
459
VAR
460
    L: LABEL;
6613 leency 461
 
462
BEGIN
7597 akron1 463
    NEW(L);
464
    L.label := label;
465
    LISTS.push(CodeList, L)
466
END SetLabel;
6613 leency 467
 
468
 
7597 akron1 469
PROCEDURE fixup*;
470
VAR
471
    code:      ANYCODE;
472
    count, i:  INTEGER;
473
    shorted:   BOOLEAN;
474
    jump:      JUMP;
6613 leency 475
 
476
BEGIN
477
 
7597 akron1 478
    REPEAT
6613 leency 479
 
7597 akron1 480
        shorted := FALSE;
481
        count := 0;
6613 leency 482
 
7597 akron1 483
        code := CodeList.first(ANYCODE);
484
        WHILE code # NIL DO
485
            code.offset := count;
6613 leency 486
 
7597 akron1 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;
6613 leency 495
 
7597 akron1 496
            code := code.next(ANYCODE)
497
        END;
6613 leency 498
 
7597 akron1 499
        code := CodeList.first(ANYCODE);
500
        WHILE code # NIL DO
6613 leency 501
 
7597 akron1 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;
6613 leency 510
 
7597 akron1 511
            code := code.next(ANYCODE)
512
        END
6613 leency 513
 
7597 akron1 514
    UNTIL ~shorted;
6613 leency 515
 
7597 akron1 516
    code := CodeList.first(ANYCODE);
517
    WHILE code # NIL DO
6613 leency 518
 
7597 akron1 519
        CASE code OF
6613 leency 520
 
7597 akron1 521
        |TCODE:
522
                FOR i := 0 TO code.length - 1 DO
523
                    BIN.PutCode(program, code.code[i])
524
                END
6613 leency 525
 
7597 akron1 526
        |LABEL:
527
                BIN.SetLabel(program, code.label, code.offset)
6613 leency 528
 
7597 akron1 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
6613 leency 537
 
7597 akron1 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
6613 leency 547
 
7597 akron1 548
        |CALL:
549
                BIN.PutCode(program, 0E8H);
550
                BIN.PutCode32LE(program, code.diff)
6613 leency 551
 
7597 akron1 552
        |RELOC:
553
                BIN.PutReloc(program, code.op);
554
                BIN.PutCode32LE(program, code.value)
6613 leency 555
 
7597 akron1 556
        END;
557
 
558
        code := code.next(ANYCODE)
6613 leency 559
    END
560
 
7597 akron1 561
END fixup;
6613 leency 562
 
563
 
7597 akron1 564
PROCEDURE UnOp (VAR reg: INTEGER);
6613 leency 565
BEGIN
7597 akron1 566
    REG.UnOp(R, reg)
567
END UnOp;
6613 leency 568
 
569
 
7597 akron1 570
PROCEDURE BinOp (VAR reg1, reg2: INTEGER);
6613 leency 571
BEGIN
7597 akron1 572
    REG.BinOp(R, reg1, reg2)
573
END BinOp;
6613 leency 574
 
575
 
7597 akron1 576
PROCEDURE PushAll (NumberOfParameters: INTEGER);
6613 leency 577
BEGIN
7597 akron1 578
    REG.PushAll(R);
579
    R.pushed := R.pushed - NumberOfParameters
580
END PushAll;
6613 leency 581
 
582
 
7597 akron1 583
PROCEDURE NewLabel (): INTEGER;
6613 leency 584
BEGIN
7597 akron1 585
    BIN.NewLabel(program)
586
    RETURN CODE.NewLabel()
587
END NewLabel;
6613 leency 588
 
589
 
7597 akron1 590
PROCEDURE GetRegA;
6613 leency 591
BEGIN
7597 akron1 592
    ASSERT(REG.GetReg(R, eax))
593
END GetRegA;
6613 leency 594
 
595
 
7597 akron1 596
PROCEDURE translate (code: CODE.CODES; pic: BOOLEAN; stroffs: INTEGER);
597
VAR
598
    cmd: COMMAND;
6613 leency 599
 
7597 akron1 600
    reg1, reg2: INTEGER;
6613 leency 601
 
7597 akron1 602
    n, a, b, label, cc: INTEGER;
6613 leency 603
 
7597 akron1 604
    param1, param2: INTEGER;
6613 leency 605
 
7597 akron1 606
    float: REAL;
6613 leency 607
 
608
BEGIN
7597 akron1 609
    cmd := code.commands.first(COMMAND);
6613 leency 610
 
7597 akron1 611
    WHILE cmd # NIL DO
6613 leency 612
 
7597 akron1 613
        param1 := cmd.param1;
614
        param2 := cmd.param2;
6613 leency 615
 
7597 akron1 616
        CASE cmd.opcode OF
6613 leency 617
 
7597 akron1 618
        |CODE.opJMP:
619
            jmp(param1)
6613 leency 620
 
7597 akron1 621
        |CODE.opCALL:
622
            call(param1)
6613 leency 623
 
7597 akron1 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
6613 leency 634
 
7597 akron1 635
        |CODE.opCALLP:
636
            UnOp(reg1);
637
            OutByte2(0FFH, 0D0H + reg1);    // call reg1
638
            drop;
639
            ASSERT(R.top = -1)
6613 leency 640
 
7597 akron1 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)
6613 leency 652
 
7597 akron1 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
7667 akron1 946
                xor(reg1, reg1)
7597 akron1 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)
7667 akron1 1089
            END
7597 akron1 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)
7667 akron1 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
7597 akron1 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);
7667 akron1 1361
            xor(reg1, reg2);
7597 akron1 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
7667 akron1 1495
            xor(reg1, reg1);
7597 akron1 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
7667 akron1 1510
            xor(reg1, reg1);
7597 akron1 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);
7667 akron1 1648
                xor(reg1, reg1)
7597 akron1 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
 
6613 leency 2198
        END;
7597 akron1 2199
 
2200
        cmd := cmd.next(COMMAND)
6613 leency 2201
    END;
2202
 
7597 akron1 2203
    ASSERT(R.pushed = 0);
2204
    ASSERT(R.top = -1)
6613 leency 2205
 
7597 akron1 2206
END translate;
6613 leency 2207
 
2208
 
7597 akron1 2209
PROCEDURE prolog (code: CODE.CODES; pic: BOOLEAN; target, stack, dllinit, dllret: INTEGER);
2210
VAR
2211
    reg1, entry, tcount, dcount: INTEGER;
6613 leency 2212
 
7597 akron1 2213
BEGIN
6613 leency 2214
 
7597 akron1 2215
    entry := NewLabel();
2216
    SetLabel(entry);
6613 leency 2217
 
7597 akron1 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;
6613 leency 2230
 
7597 akron1 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)
7667 akron1 2243
    END;
2244
 
7597 akron1 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;
6613 leency 2254
 
7597 akron1 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;
6613 leency 2264
 
7597 akron1 2265
    tcount := CHL.Length(code.types);
2266
    dcount := CHL.Length(code.data);
6613 leency 2267
 
7597 akron1 2268
    pushc(tcount);
6613 leency 2269
 
7597 akron1 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;
6613 leency 2279
 
7597 akron1 2280
    CallRTL(pic, CODE._init)
2281
END prolog;
6613 leency 2282
 
2283
 
7597 akron1 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;
6613 leency 2289
 
7597 akron1 2290
    tcount, dcount: INTEGER;
6613 leency 2291
 
7597 akron1 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
 
6613 leency 2314
BEGIN
2315
 
7597 akron1 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;
6613 leency 2328
 
7597 akron1 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))
6613 leency 2336
    END;
2337
 
7597 akron1 2338
    FOR i := 0 TO dcount - 1 DO
2339
        BIN.PutData(program, CHL.GetByte(code.data, i))
6613 leency 2340
    END;
2341
 
7597 akron1 2342
    program.modname := CHL.Length(program.data);
6613 leency 2343
 
7597 akron1 2344
    PATHS.split(modname, path, name, ext);
2345
    BIN.PutDataStr(program, name);
2346
    BIN.PutDataStr(program, ext);
2347
    BIN.PutData(program, 0);
6613 leency 2348
 
7597 akron1 2349
    IF target = mConst.Target_iObject THEN
2350
        BIN.Export(program, "lib_init", dllinit);
2351
    END;
6613 leency 2352
 
7597 akron1 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)
6613 leency 2357
    END;
2358
 
7597 akron1 2359
    import(code.import);
6613 leency 2360
 
7597 akron1 2361
    n := code.dmin - CHL.Length(code.data);
2362
    IF n > 0 THEN
2363
        INC(code.bss, n)
6613 leency 2364
    END;
2365
 
7597 akron1 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
 
6613 leency 2375
BEGIN
2376
 
7597 akron1 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
6613 leency 2386
    END;
7597 akron1 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)
6613 leency 2408
    END
2409
 
7597 akron1 2410
END CodeGen;
7209 akron1 2411
 
7597 akron1 2412
 
2413
PROCEDURE SetProgram* (prog: BIN.PROGRAM);
7209 akron1 2414
BEGIN
7597 akron1 2415
    program := prog;
2416
    CodeList := LISTS.create(NIL)
2417
END SetProgram;
2418
 
2419
 
6613 leency 2420
END X86.