Subversion Repositories Kolibri OS

Rev

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