Subversion Repositories Kolibri OS

Rev

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

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