Subversion Repositories Kolibri OS

Rev

Rev 7667 | 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
3
 
4
    Copyright (c) 2018, 2019, Anton Krotov
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,
753
         IL.opCASET, IL.opDIV,
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:
1166
            PushAll(1);
7597 akron1 1167
            pushDA(stroffs + param2);
1168
            pushc(param1);
7693 akron1 1169
            CallRTL(IL._move)
7597 akron1 1170
 
7693 akron1 1171
        |IL.opSADR:
1172
            lea(GetAnyReg(), stroffs + param2, sDATA)
7597 akron1 1173
 
7693 akron1 1174
        |IL.opLOAD8:
7597 akron1 1175
            UnOp(reg1);
1176
            movzx(reg1, reg1, 0, FALSE)
1177
 
7693 akron1 1178
        |IL.opLOAD16:
7597 akron1 1179
            UnOp(reg1);
1180
            movzx(reg1, reg1, 0, TRUE)
1181
 
7693 akron1 1182
        |IL.opLOAD32:
7597 akron1 1183
            UnOp(reg1);
1184
            movrm32(reg1, reg1, 0);
1185
            shiftrc(shl, reg1, 32);
1186
            shiftrc(shr, reg1, 32)
1187
 
7693 akron1 1188
        |IL.opLOAD64:
7597 akron1 1189
            UnOp(reg1);
1190
            movrm(reg1, reg1, 0)
1191
 
7693 akron1 1192
        |IL.opLLOAD64:
1193
            reg1 := GetAnyReg();
1194
            reg2 := GetVarReg(param2);
7597 akron1 1195
            IF reg2 # -1 THEN
1196
                mov(reg1, reg2)
1197
            ELSE
1198
                movrm(reg1, rbp, param2 * 8)
1199
            END
1200
 
7693 akron1 1201
        |IL.opLLOAD8,
1202
         IL.opLLOAD16:
1203
            reg1 := GetAnyReg();
1204
            reg2 := GetVarReg(param2);
7597 akron1 1205
            IF reg2 # -1 THEN
1206
                mov(reg1, reg2)
1207
            ELSE
7693 akron1 1208
                movzx(reg1, rbp, param2 * 8, opcode = IL.opLLOAD16)
7597 akron1 1209
            END
1210
 
7693 akron1 1211
        |IL.opLLOAD32:
1212
            reg1 := GetAnyReg();
1213
            reg2 := GetVarReg(param2);
7597 akron1 1214
            IF reg2 # -1 THEN
1215
                mov(reg1, reg2)
1216
            ELSE
1217
                n := param2 * 8;
1218
                xor(reg1, reg1);
1219
                movrm32(reg1, rbp, n)
1220
            END
1221
 
7693 akron1 1222
        |IL.opGLOAD64:
1223
            reg1 := GetAnyReg();
7597 akron1 1224
            lea(reg1, param2, sBSS);
1225
            movrm(reg1, reg1, 0)
1226
 
7693 akron1 1227
        |IL.opGLOAD8:
1228
            reg1 := GetAnyReg();
7597 akron1 1229
            lea(reg1, param2, sBSS);
1230
            movzx(reg1, reg1, 0, FALSE)
1231
 
7693 akron1 1232
        |IL.opGLOAD16:
1233
            reg1 := GetAnyReg();
7597 akron1 1234
            lea(reg1, param2, sBSS);
1235
            movzx(reg1, reg1, 0, TRUE)
1236
 
7693 akron1 1237
        |IL.opGLOAD32:
1238
            reg1 := GetAnyReg();
7597 akron1 1239
            xor(reg1, reg1);
1240
            lea(reg1, param2, sBSS);
1241
            movrm32(reg1, reg1, 0)
1242
 
7693 akron1 1243
        |IL.opVLOAD64:
1244
            reg1 := GetAnyReg();
7597 akron1 1245
            movrm(reg1, rbp, param2 * 8);
1246
            movrm(reg1, reg1, 0)
1247
 
7693 akron1 1248
        |IL.opVLOAD8,
1249
         IL.opVLOAD16:
1250
            reg1 := GetAnyReg();
7597 akron1 1251
            movrm(reg1, rbp, param2 * 8);
7693 akron1 1252
            movzx(reg1, reg1, 0, opcode = IL.opVLOAD16)
7597 akron1 1253
 
7693 akron1 1254
        |IL.opVLOAD32:
1255
            reg1 := GetAnyReg();
1256
            reg2 := GetAnyReg();
7597 akron1 1257
            xor(reg1, reg1);
1258
            movrm(reg2, rbp, param2 * 8);
1259
            movrm32(reg1, reg2, 0);
1260
            drop
1261
 
7693 akron1 1262
        |IL.opLADR:
7597 akron1 1263
            n := param2 * 8;
1264
            next := cmd.next(COMMAND);
7693 akron1 1265
            IF next.opcode = IL.opSAVEF THEN
7597 akron1 1266
                movsdmr(rbp, n, xmm);
1267
                DEC(xmm);
1268
                cmd := next
7693 akron1 1269
            ELSIF next.opcode = IL.opLOADF THEN
7597 akron1 1270
                INC(xmm);
1271
                movsdrm(xmm, rbp, n);
1272
                cmd := next
1273
            ELSE
7693 akron1 1274
                reg1 := GetAnyReg();
7597 akron1 1275
                Rex(0, reg1);
1276
                OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8);  // lea reg1, qword[rbp+n]
1277
                OutIntByte(n)
1278
            END
1279
 
7693 akron1 1280
        |IL.opGADR:
1281
            lea(GetAnyReg(), param2, sBSS)
7597 akron1 1282
 
7693 akron1 1283
        |IL.opVADR:
1284
            movrm(GetAnyReg(), rbp, param2 * 8)
7597 akron1 1285
 
7693 akron1 1286
        |IL.opSAVE8C:
7597 akron1 1287
            UnOp(reg1);
1288
            IF reg1 >= 8 THEN
1289
                OutByte(41H)
1290
            END;
1291
            OutByte3(0C6H, reg1 MOD 8, param2); // mov byte[reg1], param2
1292
            drop
1293
 
7693 akron1 1294
        |IL.opSAVE16C:
7597 akron1 1295
            UnOp(reg1);
1296
            OutByte(66H);
1297
            IF reg1 >= 8 THEN
1298
                OutByte(41H)
1299
            END;
1300
            OutByte2(0C7H, reg1 MOD 8);
1301
            OutByte2(param2 MOD 256, param2 DIV 256); // mov word[reg1], param2
1302
            drop
1303
 
7693 akron1 1304
        |IL.opSAVEC:
7597 akron1 1305
            UnOp(reg1);
1306
            IF isLong(param2) THEN
7693 akron1 1307
                reg2 := GetAnyReg();
7597 akron1 1308
                movrc(reg2, param2);
1309
                movmr(reg1, 0, reg2);
1310
                drop
1311
            ELSE
1312
                Rex(reg1, 0);
1313
                OutByte2(0C7H, reg1 MOD 8); // mov qword[reg1], param2
1314
                OutInt(param2)
1315
            END;
1316
            drop
1317
 
7693 akron1 1318
        |IL.opRSET:
7597 akron1 1319
            PushAll(2);
7693 akron1 1320
            CallRTL(IL._set);
7597 akron1 1321
            GetRegA
1322
 
7693 akron1 1323
        |IL.opRSETR:
7597 akron1 1324
            PushAll(1);
1325
            pushc(param2);
7693 akron1 1326
            CallRTL(IL._set);
7597 akron1 1327
            GetRegA
1328
 
7693 akron1 1329
        |IL.opRSETL:
7597 akron1 1330
            PushAll(1);
1331
            pushc(param2);
7693 akron1 1332
            CallRTL(IL._set2);
7597 akron1 1333
            GetRegA
1334
 
7693 akron1 1335
        |IL.opRSET1:
7597 akron1 1336
            UnOp(reg1);
1337
            PushAll(1);
1338
            push(reg1);
7693 akron1 1339
            CallRTL(IL._set);
7597 akron1 1340
            GetRegA
1341
 
7693 akron1 1342
        |IL.opINCL, IL.opEXCL:
7597 akron1 1343
            BinOp(reg1, reg2);
1344
            cmprc(reg1, 64);
1345
            OutByte2(73H, 04H); // jnb L
1346
            Rex(reg2, reg1);
7693 akron1 1347
            OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); // bts/btr qword[reg2], reg1
7597 akron1 1348
            // L:
1349
            drop;
1350
            drop
1351
 
7693 akron1 1352
        |IL.opINCLC, IL.opEXCLC:
7597 akron1 1353
            UnOp(reg1);
1354
            Rex(reg1, 0);
1355
            OutByte2(0FH, 0BAH);  // bts/btr qword[reg1], param2
7693 akron1 1356
            OutByte2(28H + 8 * ORD(opcode = IL.opEXCLC) + reg1 MOD 8, param2);
7597 akron1 1357
            drop
1358
 
7693 akron1 1359
        |IL.opEQS .. IL.opGES:
7597 akron1 1360
            PushAll(4);
7693 akron1 1361
            pushc(opcode - IL.opEQS);
1362
            CallRTL(IL._strcmp);
7597 akron1 1363
            GetRegA
1364
 
7693 akron1 1365
        |IL.opEQSW .. IL.opGESW:
7597 akron1 1366
            PushAll(4);
7693 akron1 1367
            pushc(opcode - IL.opEQSW);
1368
            CallRTL(IL._strcmpw);
7597 akron1 1369
            GetRegA
1370
 
7693 akron1 1371
        |IL.opCONST:
1372
            movrc(GetAnyReg(), param2)
7597 akron1 1373
 
7693 akron1 1374
        |IL.opEQ..IL.opGE,
1375
         IL.opEQC..IL.opGEC:
7597 akron1 1376
 
7693 akron1 1377
            IF (IL.opEQ <= opcode) & (opcode <= IL.opGE) THEN
1378
                BinOp(reg1, reg2);
1379
                cmprr(reg1, reg2);
1380
                drop
7597 akron1 1381
            ELSE
7693 akron1 1382
                UnOp(reg1);
1383
                IF param2 = 0 THEN
1384
                    test(reg1)
1385
                ELSE
1386
                    cmprc(reg1, param2)
1387
                END
1388
            END;
7597 akron1 1389
 
1390
            drop;
7693 akron1 1391
            cc := X86.cond(opcode);
7597 akron1 1392
 
7693 akron1 1393
            IF cmd.next(COMMAND).opcode = IL.opJE THEN
7597 akron1 1394
                label := cmd.next(COMMAND).param1;
1395
                jcc(cc, label);
1396
                cmd := cmd.next(COMMAND)
1397
 
7693 akron1 1398
            ELSIF cmd.next(COMMAND).opcode = IL.opJNE THEN
7597 akron1 1399
                label := cmd.next(COMMAND).param1;
7693 akron1 1400
                jcc(X86.inv0(cc), label);
7597 akron1 1401
                cmd := cmd.next(COMMAND)
1402
 
1403
            ELSE
7693 akron1 1404
                reg1 := GetAnyReg();
7597 akron1 1405
                setcc(cc + 16, reg1);
1406
                andrc(reg1, 1)
1407
            END
1408
 
7693 akron1 1409
        |IL.opCODE:
7597 akron1 1410
            OutByte(param2)
1411
 
7693 akron1 1412
        |IL.opPUSHIP:
1413
            reg1 := GetAnyReg();
7597 akron1 1414
            lea(reg1, param2, sIMP);
1415
            movrm(reg1, reg1, 0)
1416
 
7693 akron1 1417
        |IL.opPARAM:
7597 akron1 1418
            n := param2;
1419
            IF n = 1 THEN
1420
                UnOp(reg1);
1421
                push(reg1);
1422
                drop
1423
            ELSE
1424
                ASSERT(R.top + 1 <= n);
1425
                PushAll(n)
7693 akron1 1426
            END
1427
 
1428
        |IL.opACC:
7667 akron1 1429
            IF (R.top # 0) OR (R.stk[0] # rax) THEN
1430
                PushAll(0);
1431
                GetRegA;
1432
                pop(rax);
1433
                DEC(R.pushed)
7597 akron1 1434
            END
1435
 
7693 akron1 1436
        |IL.opJNZ:
7597 akron1 1437
            UnOp(reg1);
1438
            test(reg1);
1439
            jcc(jne, param1)
1440
 
7693 akron1 1441
        |IL.opJZ:
7597 akron1 1442
            UnOp(reg1);
1443
            test(reg1);
1444
            jcc(je, param1)
1445
 
7693 akron1 1446
        |IL.opJE:
7597 akron1 1447
            UnOp(reg1);
1448
            test(reg1);
1449
            jcc(jne, param1);
1450
            drop
1451
 
7693 akron1 1452
        |IL.opJNE:
7597 akron1 1453
            UnOp(reg1);
1454
            test(reg1);
1455
            jcc(je, param1);
1456
            drop
1457
 
7693 akron1 1458
        |IL.opIN:
7597 akron1 1459
            label := NewLabel();
1460
            L := NewLabel();
1461
            BinOp(reg1, reg2);
1462
            cmprc(reg1, 64);
1463
            jcc(jb, L);
1464
            xor(reg1, reg1);
1465
            jmp(label);
1466
            X86.SetLabel(L);
1467
            Rex(reg2, reg1);
1468
            OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
1469
            setcc(setc, reg1);
1470
            andrc(reg1, 1);
1471
            X86.SetLabel(label);
1472
            drop
1473
 
7693 akron1 1474
        |IL.opINR:
7597 akron1 1475
            label := NewLabel();
1476
            L := NewLabel();
1477
            UnOp(reg1);
7693 akron1 1478
            reg2 := GetAnyReg();
7597 akron1 1479
            cmprc(reg1, 64);
1480
            jcc(jb, L);
1481
            xor(reg1, reg1);
1482
            jmp(label);
1483
            X86.SetLabel(L);
1484
            movrc(reg2, param2);
1485
            Rex(reg2, reg1);
1486
            OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
1487
            setcc(setc, reg1);
1488
            andrc(reg1, 1);
1489
            X86.SetLabel(label);
1490
            drop
1491
 
7693 akron1 1492
        |IL.opINL:
7597 akron1 1493
            UnOp(reg1);
1494
            Rex(reg1, 0);
1495
            OutByte2(0FH, 0BAH);  // bt reg1, param2
1496
            OutByte2(0E0H + reg1 MOD 8, param2);
1497
            setcc(setc, reg1);
1498
            andrc(reg1, 1)
1499
 
7693 akron1 1500
        |IL.opNOT:
7597 akron1 1501
            UnOp(reg1);
1502
            test(reg1);
1503
            setcc(sete, reg1);
1504
            andrc(reg1, 1)
1505
 
7693 akron1 1506
        |IL.opORD:
7597 akron1 1507
            UnOp(reg1);
1508
            test(reg1);
1509
            setcc(setne, reg1);
1510
            andrc(reg1, 1)
1511
 
7693 akron1 1512
        |IL.opABS:
7597 akron1 1513
            UnOp(reg1);
1514
            test(reg1);
1515
            OutByte2(7DH, 03H); // jge L
1516
            neg(reg1)
1517
            // L:
1518
 
7693 akron1 1519
        |IL.opEQB, IL.opNEB:
7597 akron1 1520
            BinOp(reg1, reg2);
1521
            drop;
1522
            test(reg1);
7693 akron1 1523
            label := NewLabel();
1524
            jcc(je, label);
7597 akron1 1525
            movrc(reg1, 1);
7693 akron1 1526
            X86.SetLabel(label);
7597 akron1 1527
            test(reg2);
7693 akron1 1528
            label := NewLabel();
1529
            jcc(je, label);
7597 akron1 1530
            movrc(reg2, 1);
7693 akron1 1531
            X86.SetLabel(label);
7597 akron1 1532
            cmprr(reg1, reg2);
7693 akron1 1533
            IF opcode = IL.opEQB THEN
7597 akron1 1534
                setcc(sete, reg1)
1535
            ELSE
1536
                setcc(setne, reg1)
1537
            END;
1538
            andrc(reg1, 1)
1539
 
7693 akron1 1540
        |IL.opMULSC:
7597 akron1 1541
            UnOp(reg1);
1542
            andrc(reg1, param2)
1543
 
7693 akron1 1544
        |IL.opDIVSC, IL.opADDSL, IL.opADDSR:
7597 akron1 1545
            UnOp(reg1);
1546
            Rex(reg1, 0);
7693 akron1 1547
            OutByte2(81H + short(param2), 0C8H + 28H * ORD(opcode = IL.opDIVSC) + reg1 MOD 8); // or/xor reg1, param2
7597 akron1 1548
            OutIntByte(param2)
1549
 
7693 akron1 1550
        |IL.opSUBSL:
7597 akron1 1551
            UnOp(reg1);
1552
            not(reg1);
1553
            andrc(reg1, param2)
1554
 
7693 akron1 1555
        |IL.opSUBSR:
7597 akron1 1556
            UnOp(reg1);
1557
            andrc(reg1, ORD(-BITS(param2)))
1558
 
7693 akron1 1559
        |IL.opMULS:
7597 akron1 1560
            BinOp(reg1, reg2);
1561
            and(reg1, reg2);
1562
            drop
1563
 
7693 akron1 1564
        |IL.opDIVS:
7597 akron1 1565
            BinOp(reg1, reg2);
1566
            xor(reg1, reg2);
1567
            drop
1568
 
7693 akron1 1569
        |IL.opUMINS:
7597 akron1 1570
            UnOp(reg1);
1571
            not(reg1)
1572
 
7693 akron1 1573
        |IL.opCOPY:
7597 akron1 1574
            PushAll(2);
1575
            pushc(param2);
7693 akron1 1576
            CallRTL(IL._move2)
7597 akron1 1577
 
7693 akron1 1578
        |IL.opMOVE:
7597 akron1 1579
            PushAll(3);
7693 akron1 1580
            CallRTL(IL._move2)
7597 akron1 1581
 
7693 akron1 1582
        |IL.opCOPYA:
7597 akron1 1583
            PushAll(4);
1584
            pushc(param2);
7693 akron1 1585
            CallRTL(IL._arrcpy);
7597 akron1 1586
            GetRegA
1587
 
7693 akron1 1588
        |IL.opCOPYS:
7597 akron1 1589
            PushAll(4);
1590
            pushc(param2);
7693 akron1 1591
            CallRTL(IL._strcpy)
7597 akron1 1592
 
7693 akron1 1593
        |IL.opROT:
7597 akron1 1594
            PushAll(0);
1595
            push(rsp);
1596
            pushc(param2);
7693 akron1 1597
            CallRTL(IL._rot)
7597 akron1 1598
 
7693 akron1 1599
        |IL.opNEW:
7597 akron1 1600
            PushAll(1);
1601
            n := param2 + 16;
7693 akron1 1602
            ASSERT(UTILS.Align(n, 64));
7597 akron1 1603
            pushc(n);
1604
            pushc(param1);
7693 akron1 1605
            CallRTL(IL._new)
7597 akron1 1606
 
7693 akron1 1607
        |IL.opDISP:
7597 akron1 1608
            PushAll(1);
7693 akron1 1609
            CallRTL(IL._dispose)
7597 akron1 1610
 
7693 akron1 1611
        |IL.opPUSHT:
7597 akron1 1612
            UnOp(reg1);
7693 akron1 1613
            reg2 := GetAnyReg();
7597 akron1 1614
            movrm(reg2, reg1, -8)
1615
 
7693 akron1 1616
        |IL.opISREC:
7597 akron1 1617
            PushAll(2);
7693 akron1 1618
            pushc(param2 * tcount);
1619
            CallRTL(IL._isrec);
7597 akron1 1620
            GetRegA
1621
 
7693 akron1 1622
        |IL.opIS:
7597 akron1 1623
            PushAll(1);
7693 akron1 1624
            pushc(param2 * tcount);
1625
            CallRTL(IL._is);
7597 akron1 1626
            GetRegA
1627
 
7693 akron1 1628
        |IL.opTYPEGR:
7597 akron1 1629
            PushAll(1);
7693 akron1 1630
            pushc(param2 * tcount);
1631
            CallRTL(IL._guardrec);
7597 akron1 1632
            GetRegA
1633
 
7693 akron1 1634
        |IL.opTYPEGP:
7597 akron1 1635
            UnOp(reg1);
1636
            PushAll(0);
1637
            push(reg1);
7693 akron1 1638
            pushc(param2 * tcount);
1639
            CallRTL(IL._guard);
7597 akron1 1640
            GetRegA
1641
 
7693 akron1 1642
        |IL.opTYPEGD:
7597 akron1 1643
            UnOp(reg1);
1644
            PushAll(0);
1645
            pushm(reg1, -8);
7693 akron1 1646
            pushc(param2 * tcount);
1647
            CallRTL(IL._guardrec);
7597 akron1 1648
            GetRegA
1649
 
7693 akron1 1650
        |IL.opCASET:
7597 akron1 1651
            push(r10);
1652
            push(r10);
7693 akron1 1653
            pushc(param2 * tcount);
1654
            CallRTL(IL._guardrec);
7597 akron1 1655
            pop(r10);
1656
            test(rax);
1657
            jcc(jne, param1)
1658
 
7693 akron1 1659
        |IL.opSAVEP:
7597 akron1 1660
            UnOp(reg1);
7693 akron1 1661
            reg2 := GetAnyReg();
7597 akron1 1662
            lea(reg2, param2, sCODE);
1663
            movmr(reg1, 0, reg2);
1664
            drop;
1665
            drop
1666
 
7693 akron1 1667
        |IL.opPUSHP:
1668
            lea(GetAnyReg(), param2, sCODE)
7597 akron1 1669
 
7693 akron1 1670
        |IL.opINC, IL.opDEC:
7597 akron1 1671
            BinOp(reg1, reg2);
1672
            // add/sub qword[reg2], reg1
1673
            Rex(reg2, reg1);
7693 akron1 1674
            OutByte2(01H + 28H * ORD(opcode = IL.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
7597 akron1 1675
            drop;
1676
            drop
1677
 
7693 akron1 1678
        |IL.opINCC:
7597 akron1 1679
            UnOp(reg1);
1680
            IF isLong(param2) THEN
7693 akron1 1681
                reg2 := GetAnyReg();
7597 akron1 1682
                movrc(reg2, param2);
7693 akron1 1683
                // add qword[reg1], reg2
7597 akron1 1684
                Rex(reg1, reg2);
7693 akron1 1685
                OutByte2(01H, reg1 MOD 8 + (reg2 MOD 8) * 8);
7597 akron1 1686
                drop
7693 akron1 1687
            ELSIF ABS(param2) = 1 THEN
1688
                Rex(reg1, 0);
1689
                OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(param2 = -1)) // inc/dec qword[reg1]
7597 akron1 1690
            ELSE
7693 akron1 1691
                // add qword[reg1], param2
7597 akron1 1692
                Rex(reg1, 0);
7693 akron1 1693
                OutByte2(81H + short(param2), reg1 MOD 8);
7597 akron1 1694
                OutIntByte(param2)
1695
            END;
1696
            drop
1697
 
7693 akron1 1698
        |IL.opDROP:
7597 akron1 1699
            UnOp(reg1);
1700
            drop
1701
 
7693 akron1 1702
        |IL.opSAVE, IL.opSAVE64:
7597 akron1 1703
            BinOp(reg2, reg1);
1704
            movmr(reg1, 0, reg2);
1705
            drop;
1706
            drop
1707
 
7693 akron1 1708
        |IL.opSAVE8:
7597 akron1 1709
            BinOp(reg2, reg1);
1710
            movmr8(reg1, 0, reg2);
1711
            drop;
1712
            drop
1713
 
7693 akron1 1714
        |IL.opSAVE16:
7597 akron1 1715
            BinOp(reg2, reg1);
1716
            movmr16(reg1, 0, reg2);
1717
            drop;
1718
            drop
1719
 
7693 akron1 1720
        |IL.opSAVE32:
7597 akron1 1721
            BinOp(reg2, reg1);
1722
            movmr32(reg1, 0, reg2);
1723
            drop;
1724
            drop
1725
 
7693 akron1 1726
        |IL.opMIN:
7597 akron1 1727
            BinOp(reg1, reg2);
1728
            cmprr(reg1, reg2);
1729
            OutByte2(7EH, 3); // jle L
1730
            mov(reg1, reg2);
1731
            // L:
1732
            drop
1733
 
7693 akron1 1734
        |IL.opMAX:
7597 akron1 1735
            BinOp(reg1, reg2);
1736
            cmprr(reg1, reg2);
1737
            OutByte2(7DH, 3);  // jge L
1738
            mov(reg1, reg2);
1739
            // L:
1740
            drop
1741
 
7693 akron1 1742
        |IL.opMINC:
7597 akron1 1743
            UnOp(reg1);
1744
            cmprc(reg1, param2);
1745
            label := NewLabel();
1746
            jcc(jle, label);
1747
            movrc(reg1, param2);
1748
            X86.SetLabel(label)
1749
 
7693 akron1 1750
        |IL.opMAXC:
7597 akron1 1751
            UnOp(reg1);
1752
            cmprc(reg1, param2);
1753
            label := NewLabel();
1754
            jcc(jge, label);
1755
            movrc(reg1, param2);
1756
            X86.SetLabel(label)
1757
 
7693 akron1 1758
        |IL.opSBOOL:
7597 akron1 1759
            BinOp(reg2, reg1);
1760
            test(reg2);
7693 akron1 1761
            IF reg1 >= 8 THEN
1762
                OutByte(41H)
1763
            END;
1764
            OutByte3(0FH, 95H, reg1 MOD 8); // setne byte[reg1]
7597 akron1 1765
            drop;
1766
            drop
1767
 
7693 akron1 1768
        |IL.opSBOOLC:
7597 akron1 1769
            UnOp(reg1);
1770
            IF reg1 >= 8 THEN
1771
                OutByte(41H)
1772
            END;
7693 akron1 1773
            OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0)); // mov byte[reg1], 0/1
7597 akron1 1774
            drop
1775
 
7693 akron1 1776
        |IL.opODD:
7597 akron1 1777
            UnOp(reg1);
1778
            andrc(reg1, 1)
1779
 
7693 akron1 1780
        |IL.opUMINUS:
7597 akron1 1781
            UnOp(reg1);
1782
            neg(reg1)
1783
 
7693 akron1 1784
        |IL.opADD:
7597 akron1 1785
            BinOp(reg1, reg2);
1786
            add(reg1, reg2);
1787
            drop
1788
 
7693 akron1 1789
        |IL.opSUB:
7597 akron1 1790
            BinOp(reg1, reg2);
1791
            sub(reg1, reg2);
1792
            drop
1793
 
7693 akron1 1794
        |IL.opSUBR, IL.opSUBL:
7597 akron1 1795
            UnOp(reg1);
1796
            n := param2;
1797
            IF n = 1 THEN
1798
                decr(reg1)
1799
            ELSIF n = -1 THEN
1800
                incr(reg1)
1801
            ELSIF n # 0 THEN
1802
                subrc(reg1, n)
1803
            END;
7693 akron1 1804
            IF opcode = IL.opSUBL THEN
7597 akron1 1805
                neg(reg1)
1806
            END
1807
 
7693 akron1 1808
        |IL.opADDL, IL.opADDR:
7597 akron1 1809
            IF param2 # 0 THEN
1810
                UnOp(reg1);
1811
                IF param2 = 1 THEN
1812
                    incr(reg1)
1813
                ELSIF param2 = -1 THEN
1814
                    decr(reg1)
1815
                ELSE
1816
                    addrc(reg1, param2)
1817
                END
1818
            END
1819
 
7693 akron1 1820
        |IL.opDIV:
7597 akron1 1821
            PushAll(2);
7693 akron1 1822
            CallRTL(IL._div);
7597 akron1 1823
            GetRegA
1824
 
7693 akron1 1825
        |IL.opDIVR:
7597 akron1 1826
            a := param2;
1827
            IF a > 1 THEN
7693 akron1 1828
                n := UTILS.Log2(a)
7597 akron1 1829
            ELSIF a < -1 THEN
7693 akron1 1830
                n := UTILS.Log2(-a)
7597 akron1 1831
            ELSE
1832
                n := -1
1833
            END;
1834
 
1835
            IF a = 1 THEN
1836
 
1837
            ELSIF a = -1 THEN
1838
                UnOp(reg1);
1839
                neg(reg1)
1840
            ELSE
1841
                IF n > 0 THEN
1842
                    UnOp(reg1);
1843
 
1844
                    IF a < 0 THEN
7693 akron1 1845
                        reg2 := GetAnyReg();
7597 akron1 1846
                        mov(reg2, reg1);
1847
                        shiftrc(sar, reg1, n);
1848
                        sub(reg1, reg2);
1849
                        drop
1850
                    ELSE
1851
                        shiftrc(sar, reg1, n)
1852
                    END
1853
 
1854
                ELSE
1855
                    PushAll(1);
1856
                    pushc(param2);
7693 akron1 1857
                    CallRTL(IL._div);
7597 akron1 1858
                    GetRegA
1859
                END
1860
            END
1861
 
7693 akron1 1862
        |IL.opDIVL:
7597 akron1 1863
            PushAll(1);
1864
            pushc(param2);
7693 akron1 1865
            CallRTL(IL._div2);
7597 akron1 1866
            GetRegA
1867
 
7693 akron1 1868
        |IL.opMOD:
7597 akron1 1869
            PushAll(2);
7693 akron1 1870
            CallRTL(IL._mod);
7597 akron1 1871
            GetRegA
1872
 
7693 akron1 1873
        |IL.opMODR:
7597 akron1 1874
            a := param2;
1875
            IF a > 1 THEN
7693 akron1 1876
                n := UTILS.Log2(a)
7597 akron1 1877
            ELSIF a < -1 THEN
7693 akron1 1878
                n := UTILS.Log2(-a)
7597 akron1 1879
            ELSE
1880
                n := -1
1881
            END;
1882
 
1883
            IF ABS(a) = 1 THEN
1884
                UnOp(reg1);
1885
                xor(reg1, reg1)
1886
            ELSE
1887
                IF n > 0 THEN
1888
                    UnOp(reg1);
1889
                    andrc(reg1, ABS(a) - 1);
1890
 
1891
                    IF a < 0 THEN
1892
                        test(reg1);
1893
                        label := NewLabel();
1894
                        jcc(je, label);
1895
                        addrc(reg1, a);
1896
                        X86.SetLabel(label)
1897
                    END
1898
 
1899
                ELSE
1900
                    PushAll(1);
1901
                    pushc(param2);
7693 akron1 1902
                    CallRTL(IL._mod);
7597 akron1 1903
                    GetRegA
1904
                END
1905
            END
1906
 
7693 akron1 1907
        |IL.opMODL:
7597 akron1 1908
            PushAll(1);
1909
            pushc(param2);
7693 akron1 1910
            CallRTL(IL._mod2);
7597 akron1 1911
            GetRegA
1912
 
7693 akron1 1913
        |IL.opMUL:
7597 akron1 1914
            BinOp(reg1, reg2);
1915
            oprr2(0FH, 0AFH, reg2, reg1); // imul reg1, reg2
1916
            drop
1917
 
7693 akron1 1918
        |IL.opMULC:
7597 akron1 1919
            UnOp(reg1);
1920
 
1921
            a := param2;
1922
            IF a > 1 THEN
7693 akron1 1923
                n := UTILS.Log2(a)
7597 akron1 1924
            ELSIF a < -1 THEN
7693 akron1 1925
                n := UTILS.Log2(-a)
7597 akron1 1926
            ELSE
1927
                n := -1
1928
            END;
1929
 
1930
            IF a = 1 THEN
1931
 
1932
            ELSIF a = -1 THEN
1933
                neg(reg1)
1934
            ELSIF a = 0 THEN
1935
                xor(reg1, reg1)
1936
            ELSE
1937
                IF n > 0 THEN
1938
                    IF a < 0 THEN
1939
                        neg(reg1)
1940
                    END;
1941
                    shiftrc(shl, reg1, n)
1942
                ELSE
1943
                    // imul reg1, a
1944
                    Rex(reg1, reg1);
1945
                    OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
1946
                    OutIntByte(a)
1947
                END
1948
            END
1949
 
7693 akron1 1950
        |IL.opADDS:
7597 akron1 1951
            BinOp(reg1, reg2);
1952
            or(reg1, reg2);
1953
            drop
1954
 
7693 akron1 1955
        |IL.opSUBS:
7597 akron1 1956
            BinOp(reg1, reg2);
1957
            not(reg2);
1958
            and(reg1, reg2);
1959
            drop
1960
 
7693 akron1 1961
        |IL.opNOP:
7597 akron1 1962
 
7693 akron1 1963
        |IL.opSWITCH:
7597 akron1 1964
            UnOp(reg1);
1965
            IF param2 = 0 THEN
1966
                reg2 := rax
1967
            ELSE
1968
                reg2 := r10
1969
            END;
1970
            IF reg1 # reg2 THEN
1971
                ASSERT(REG.GetReg(R, reg2));
1972
                ASSERT(REG.Exchange(R, reg1, reg2));
1973
                drop
1974
            END;
1975
            drop
1976
 
7693 akron1 1977
        |IL.opENDSW:
7597 akron1 1978
 
7693 akron1 1979
        |IL.opCASEL:
7597 akron1 1980
            cmprc(rax, param1);
1981
            jcc(jl, param2)
1982
 
7693 akron1 1983
        |IL.opCASER:
7597 akron1 1984
            cmprc(rax, param1);
1985
            jcc(jg, param2)
1986
 
7693 akron1 1987
        |IL.opCASELR:
7597 akron1 1988
            cmprc(rax, param1);
1989
            jcc(jl, param2);
1990
            jcc(jg, cmd.param3)
1991
 
7693 akron1 1992
        |IL.opASR, IL.opROR, IL.opLSL, IL.opLSR:
7597 akron1 1993
            BinOp(reg1, reg2);
1994
            xchg(reg2, rcx);
1995
            Rex(reg1, 0);
1996
            OutByte(0D3H);
7693 akron1 1997
            X86.shift(opcode, reg1 MOD 8); // shift reg1, cl
7597 akron1 1998
            xchg(reg2, rcx);
1999
            drop
2000
 
7693 akron1 2001
        |IL.opASR1, IL.opROR1, IL.opLSL1, IL.opLSR1:
2002
            reg1 := GetAnyReg();
7597 akron1 2003
            movrc(reg1, param2);
2004
            BinOp(reg1, reg2);
2005
            xchg(reg1, rcx);
2006
            Rex(reg2, 0);
2007
            OutByte(0D3H);
7693 akron1 2008
            X86.shift(opcode, reg2 MOD 8); // shift reg2, cl
7597 akron1 2009
            xchg(reg1, rcx);
2010
            drop;
2011
            drop;
2012
            ASSERT(REG.GetReg(R, reg2))
2013
 
7693 akron1 2014
        |IL.opASR2, IL.opROR2, IL.opLSL2, IL.opLSR2:
7597 akron1 2015
            UnOp(reg1);
7693 akron1 2016
            shiftrc(opcode, reg1, param2 MOD 64)
7597 akron1 2017
 
7693 akron1 2018
        |IL.opGET, IL.opGETC:
2019
            IF opcode = IL.opGET THEN
2020
                BinOp(reg1, reg2)
2021
            ELSIF opcode = IL.opGETC THEN
2022
                UnOp(reg2);
2023
                reg1 := GetAnyReg();
2024
                movrc(reg1, param1)
2025
            END;
7597 akron1 2026
            drop;
2027
            drop;
2028
            _movrm(reg1, reg1, 0, param2 * 8, FALSE);
2029
            _movrm(reg1, reg2, 0, param2 * 8, TRUE)
2030
 
7693 akron1 2031
        |IL.opCHKBYTE:
7597 akron1 2032
            BinOp(reg1, reg2);
2033
            cmprc(reg1, 256);
2034
            jcc(jb, param1)
2035
 
7693 akron1 2036
        |IL.opCHKIDX:
7597 akron1 2037
            UnOp(reg1);
2038
            cmprc(reg1, param2);
2039
            jcc(jb, param1)
2040
 
7693 akron1 2041
        |IL.opCHKIDX2:
7597 akron1 2042
            BinOp(reg1, reg2);
2043
            IF param2 # -1 THEN
2044
                cmprr(reg2, reg1);
2045
                mov(reg1, reg2);
2046
                drop;
2047
                jcc(jb, param1)
2048
            ELSE
2049
                INCL(R.regs, reg1);
2050
                DEC(R.top);
2051
                R.stk[R.top] := reg2
2052
            END
2053
 
7693 akron1 2054
        |IL.opLENGTH:
7597 akron1 2055
            PushAll(2);
7693 akron1 2056
            CallRTL(IL._length);
7597 akron1 2057
            GetRegA
2058
 
7693 akron1 2059
        |IL.opLENGTHW:
7597 akron1 2060
            PushAll(2);
7693 akron1 2061
            CallRTL(IL._lengthw);
7597 akron1 2062
            GetRegA
2063
 
7693 akron1 2064
        |IL.opLEN:
7597 akron1 2065
            n := param2;
2066
            UnOp(reg1);
2067
            drop;
2068
            EXCL(R.regs, reg1);
2069
 
2070
            WHILE n > 0 DO
2071
                UnOp(reg2);
2072
                drop;
2073
                DEC(n)
2074
            END;
2075
 
2076
            INCL(R.regs, reg1);
2077
            ASSERT(REG.GetReg(R, reg1))
2078
 
7693 akron1 2079
        |IL.opCHR:
7597 akron1 2080
            UnOp(reg1);
2081
            andrc(reg1, 255)
2082
 
7693 akron1 2083
        |IL.opWCHR:
7597 akron1 2084
            UnOp(reg1);
2085
            andrc(reg1, 65535)
2086
 
7693 akron1 2087
        |IL.opEQP, IL.opNEP, IL.opEQIP, IL.opNEIP:
7597 akron1 2088
            UnOp(reg1);
7693 akron1 2089
            reg2 := GetAnyReg();
7597 akron1 2090
 
7693 akron1 2091
            CASE opcode OF
2092
            |IL.opEQP, IL.opNEP:
7597 akron1 2093
                lea(reg2, param1, sCODE)
2094
 
7693 akron1 2095
            |IL.opEQIP, IL.opNEIP:
7597 akron1 2096
                lea(reg2, param1, sIMP);
2097
                movrm(reg2, reg2, 0)
2098
            END;
2099
 
2100
            cmprr(reg1, reg2);
2101
            drop;
2102
            drop;
7693 akron1 2103
            reg1 := GetAnyReg();
7597 akron1 2104
 
7693 akron1 2105
            CASE opcode OF
2106
            |IL.opEQP, IL.opEQIP: setcc(sete,  reg1)
2107
            |IL.opNEP, IL.opNEIP: setcc(setne, reg1)
7597 akron1 2108
            END;
2109
 
2110
            andrc(reg1, 1)
2111
 
7693 akron1 2112
        |IL.opINCCB, IL.opDECCB:
7597 akron1 2113
            UnOp(reg1);
2114
            IF reg1 >= 8 THEN
2115
                OutByte(41H)
2116
            END;
7693 akron1 2117
            OutByte3(80H, 28H * ORD(opcode = IL.opDECCB) + reg1 MOD 8, param2 MOD 256); // add/sub byte[reg1], param2 MOD 256
7597 akron1 2118
            drop
2119
 
7693 akron1 2120
        |IL.opINCB, IL.opDECB:
7597 akron1 2121
            BinOp(reg1, reg2);
2122
            IF (reg1 >= 8) OR (reg2 >= 8) THEN
2123
                OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
2124
            END;
7693 akron1 2125
            OutByte2(28H * ORD(opcode = IL.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); // add/sub byte[reg2], reg1_8
7597 akron1 2126
            drop;
2127
            drop
2128
 
7693 akron1 2129
        |IL.opSAVEIP:
7597 akron1 2130
            UnOp(reg1);
7693 akron1 2131
            reg2 := GetAnyReg();
7597 akron1 2132
            lea(reg2, param2, sIMP);
2133
            movrm(reg2, reg2, 0);
2134
            push(reg2);
2135
            drop;
2136
            IF reg1 >= 8 THEN
2137
                OutByte(41H)
2138
            END;
2139
            OutByte2(8FH, reg1 MOD 8); // pop qword[reg1]
2140
            drop
2141
 
7693 akron1 2142
        |IL.opCLEANUP:
7597 akron1 2143
            n := param2 * 8;
2144
            IF n # 0 THEN
2145
                addrc(rsp, n)
2146
            END
2147
 
7693 akron1 2148
        |IL.opPOPSP:
7597 akron1 2149
            pop(rsp)
2150
 
7693 akron1 2151
        |IL.opLOADF:
7597 akron1 2152
            UnOp(reg1);
2153
            INC(xmm);
2154
            movsdrm(xmm, reg1, 0);
2155
            drop
2156
 
7693 akron1 2157
        |IL.opPUSHF:
7597 akron1 2158
            subrc(rsp, 8);
2159
            movsdmr(rsp, 0, xmm);
2160
            DEC(xmm)
2161
 
7693 akron1 2162
        |IL.opCONSTF:
7597 akron1 2163
            float := cmd.float;
2164
            INC(xmm);
7693 akron1 2165
            reg1 := GetAnyReg();
7597 akron1 2166
            lea(reg1, Numbers_Offs + Numbers_Count * 8, sDATA);
2167
            movsdrm(xmm, reg1, 0);
2168
            drop;
2169
            NewNumber(UTILS.splitf(float, a, b))
2170
 
7693 akron1 2171
        |IL.opSAVEF:
7597 akron1 2172
            UnOp(reg1);
2173
            movsdmr(reg1, 0, xmm);
2174
            DEC(xmm);
2175
            drop
2176
 
7693 akron1 2177
        |IL.opADDF, IL.opADDFI:
7597 akron1 2178
            opxx(58H, xmm - 1, xmm);
2179
            DEC(xmm)
2180
 
7693 akron1 2181
        |IL.opSUBF:
7597 akron1 2182
            opxx(5CH, xmm - 1, xmm);
2183
            DEC(xmm)
2184
 
7693 akron1 2185
        |IL.opSUBFI:
7597 akron1 2186
            opxx(5CH, xmm, xmm - 1);
2187
            opxx(10H, xmm - 1, xmm);
2188
            DEC(xmm)
2189
 
7693 akron1 2190
        |IL.opMULF:
7597 akron1 2191
            opxx(59H, xmm - 1, xmm);
2192
            DEC(xmm)
2193
 
7693 akron1 2194
        |IL.opDIVF:
7597 akron1 2195
            opxx(5EH, xmm - 1, xmm);
2196
            DEC(xmm)
2197
 
7693 akron1 2198
        |IL.opDIVFI:
7597 akron1 2199
            opxx(5EH, xmm, xmm - 1);
2200
            opxx(10H, xmm - 1, xmm);
2201
            DEC(xmm)
2202
 
7693 akron1 2203
        |IL.opUMINF:
2204
            reg1 := GetAnyReg();
7597 akron1 2205
            lea(reg1, Numbers_Offs, sDATA);
2206
            OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // xorpd xmm, xmmword[reg1]
2207
            OutByte2(57H, reg1 MOD 8 + (xmm MOD 8) * 8);
2208
            drop
2209
 
7693 akron1 2210
        |IL.opFABS:
2211
            reg1 := GetAnyReg();
7597 akron1 2212
            lea(reg1, Numbers_Offs + 16, sDATA);
2213
            OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // andpd xmm, xmmword[reg1]
2214
            OutByte2(54H, reg1 MOD 8 + (xmm MOD 8) * 8);
2215
            drop
2216
 
7693 akron1 2217
        |IL.opFLT:
7597 akron1 2218
            UnOp(reg1);
2219
            INC(xmm);
2220
            OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); // cvtsi2sd xmm, reg1
2221
            OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
2222
            drop
2223
 
7693 akron1 2224
        |IL.opFLOOR:
2225
            reg1 := GetAnyReg();
7597 akron1 2226
            subrc(rsp, 8);
2227
            OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); // stmxcsr dword[rsp+4];
2228
            OutByte2(00FH, 0AEH); OutByte2(01CH, 024H);       // stmxcsr dword[rsp];
2229
            OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); // and dword[rsp],11111111111111111001111111111111b;
2230
            OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); // or dword[rsp],00000000000000000010000000000000b;
2231
            OutByte2(00FH, 0AEH); OutByte2(014H, 024H); // ldmxcsr dword[rsp];
2232
            OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); // cvtsd2si reg1, xmm
2233
            OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
2234
            OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); // ldmxcsr dword[rsp+4];
2235
            addrc(rsp, 8);
2236
            DEC(xmm)
2237
 
7693 akron1 2238
        |IL.opEQF .. IL.opGEF:
2239
            fcmp(opcode, xmm);
7597 akron1 2240
            DEC(xmm, 2)
2241
 
7693 akron1 2242
        |IL.opINF:
7597 akron1 2243
            INC(xmm);
7693 akron1 2244
            reg1 := GetAnyReg();
7597 akron1 2245
            lea(reg1, Numbers_Offs + 32, sDATA);
2246
            movsdrm(xmm, reg1, 0);
2247
            drop
2248
 
7693 akron1 2249
        |IL.opPACK, IL.opPACKC:
2250
            IF opcode = IL.opPACK THEN
7597 akron1 2251
                BinOp(reg1, reg2)
2252
            ELSE
2253
                UnOp(reg1);
7693 akron1 2254
                reg2 := GetAnyReg();
7597 akron1 2255
                movrc(reg2, param2)
2256
            END;
2257
            push(reg1);
2258
            movrm(reg1, reg1, 0);
2259
            shiftrc(shl, reg1, 1);
2260
            shiftrc(shr, reg1, 53);
2261
            add(reg1, reg2);
2262
            andrc(reg1, ORD({0..10}));
2263
            shiftrc(shl, reg1, 52);
2264
            movrm(reg2, rsp, 0);
2265
            movrm(reg2, reg2, 0);
2266
 
2267
            push(reg1);
2268
            lea(reg1, Numbers_Offs + 40, sDATA); // {0..51, 63}
2269
            movrm(reg1, reg1, 0);
2270
            and(reg2, reg1);
2271
            pop(reg1);
2272
 
2273
            or(reg2, reg1);
2274
            pop(reg1);
2275
            movmr(reg1, 0, reg2);
2276
            drop;
2277
            drop
2278
 
7693 akron1 2279
        |IL.opUNPK, IL.opLADR_UNPK:
7597 akron1 2280
 
7693 akron1 2281
            IF opcode = IL.opLADR_UNPK THEN
7597 akron1 2282
                n := param2 * 8;
2283
                UnOp(reg1);
7693 akron1 2284
                reg2 := GetVarReg(param2);
7597 akron1 2285
                regVar := reg2 # -1;
2286
                IF ~regVar THEN
7693 akron1 2287
                    reg2 := GetAnyReg();
7597 akron1 2288
                    Rex(0, reg2);
2289
                    OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8);  // lea reg2, qword[rbp+n]
2290
                    OutIntByte(n)
2291
                END
2292
            ELSE
2293
                BinOp(reg1, reg2);
2294
                regVar := FALSE
2295
            END;
2296
 
2297
            push(reg1);
2298
            movrm(reg1, reg1, 0);
2299
            shiftrc(shl, reg1, 1);
2300
            shiftrc(shr, reg1, 53);
2301
            subrc(reg1, 1023);
2302
 
2303
            IF regVar THEN
2304
                mov(reg2, reg1);
7693 akron1 2305
                reg2 := GetAnyReg()
7597 akron1 2306
            ELSE
2307
                movmr(reg2, 0, reg1)
2308
            END;
2309
 
2310
            pop(reg2);
2311
            movrm(reg1, reg2, 0);
2312
 
2313
            push(reg2);
2314
            lea(reg2, Numbers_Offs + 48, sDATA); // {52..61}
2315
            movrm(reg2, reg2, 0);
2316
            or(reg1, reg2);
2317
            pop(reg2);
2318
 
2319
            Rex(reg1, 0);
2320
            OutByte2(0FH, 0BAH);
2321
            OutByte2(0F0H + reg1 MOD 8, 3EH); // btr reg1, 62
2322
            movmr(reg2, 0, reg1);
2323
            drop;
2324
            drop
2325
 
7693 akron1 2326
        |IL.opSADR_PARAM:
7597 akron1 2327
            pushDA(stroffs + param2)
2328
 
7693 akron1 2329
        |IL.opVADR_PARAM:
7597 akron1 2330
            pushm(rbp, param2 * 8)
2331
 
7693 akron1 2332
        |IL.opLOAD64_PARAM:
7597 akron1 2333
            UnOp(reg1);
2334
            pushm(reg1, 0);
2335
            drop
2336
 
7693 akron1 2337
        |IL.opLLOAD64_PARAM:
2338
            reg1 := GetVarReg(param2);
7597 akron1 2339
            IF reg1 # -1 THEN
2340
                push(reg1)
2341
            ELSE
2342
                pushm(rbp, param2 * 8)
2343
            END
2344
 
7693 akron1 2345
        |IL.opGLOAD64_PARAM:
2346
            reg2 := GetAnyReg();
7597 akron1 2347
            lea(reg2, param2, sBSS);
2348
            movrm(reg2, reg2, 0);
2349
            push(reg2);
2350
            drop
2351
 
7693 akron1 2352
        |IL.opCONST_PARAM:
7597 akron1 2353
            pushc(param2)
2354
 
7693 akron1 2355
        |IL.opGLOAD32_PARAM:
2356
            reg1 := GetAnyReg();
7597 akron1 2357
            xor(reg1, reg1);
2358
            lea(reg1, param2, sBSS);
2359
            movrm32(reg1, reg1, 0);
2360
            push(reg1);
2361
            drop
2362
 
7693 akron1 2363
        |IL.opLOAD32_PARAM:
7597 akron1 2364
            UnOp(reg1);
2365
            movrm32(reg1, reg1, 0);
2366
            shiftrc(shl, reg1, 32);
2367
            shiftrc(shr, reg1, 32);
2368
            push(reg1);
2369
            drop
2370
 
7693 akron1 2371
        |IL.opLLOAD32_PARAM:
2372
            reg1 := GetAnyReg();
7597 akron1 2373
            xor(reg1, reg1);
7693 akron1 2374
            reg2 := GetVarReg(param2);
7597 akron1 2375
            IF reg2 # -1 THEN
2376
                mov(reg1, reg2)
2377
            ELSE
2378
                movrm32(reg1, rbp, param2 * 8)
2379
            END;
2380
            push(reg1);
2381
            drop
2382
 
7693 akron1 2383
        |IL.opLADR_SAVEC:
7597 akron1 2384
            n := param1 * 8;
7693 akron1 2385
            reg1 := GetVarReg(param1);
7597 akron1 2386
            IF reg1 # -1 THEN
2387
                movrc(reg1, param2)
2388
            ELSE
2389
                IF isLong(param2) THEN
7693 akron1 2390
                    reg2 := GetAnyReg();
7597 akron1 2391
                    movrc(reg2, param2);
2392
                    movmr(rbp, n, reg2);
2393
                    drop
2394
                ELSE
2395
                    OutByte3(48H, 0C7H, 45H + long(n)); // mov qword[rbp+n],param2
2396
                    OutIntByte(n);
2397
                    OutInt(param2)
2398
                END
2399
            END
2400
 
7693 akron1 2401
        |IL.opGADR_SAVEC:
7597 akron1 2402
            IF isLong(param2) THEN
7693 akron1 2403
                reg1 := GetAnyReg();
7597 akron1 2404
                movrc(reg1, param2);
7693 akron1 2405
                reg2 := GetAnyReg();
7597 akron1 2406
                lea(reg2, param1, sBSS);
2407
                movmr(reg2, 0, reg1);
2408
                drop;
2409
                drop
2410
            ELSE
7693 akron1 2411
                reg2 := GetAnyReg();
7597 akron1 2412
                lea(reg2, param1, sBSS);
2413
                Rex(reg2, 0);
2414
                OutByte2(0C7H, reg2 MOD 8); // mov qword[reg2], param2
2415
                OutInt(param2);
2416
                drop
2417
            END
2418
 
7693 akron1 2419
        |IL.opLADR_SAVE:
7597 akron1 2420
            UnOp(reg1);
7693 akron1 2421
            reg2 := GetVarReg(param2);
7597 akron1 2422
            IF reg2 # -1 THEN
2423
                mov(reg2, reg1)
2424
            ELSE
2425
                movmr(rbp, param2 * 8, reg1)
2426
            END;
2427
            drop
2428
 
7693 akron1 2429
        |IL.opLADR_INCC:
2430
            reg1 := GetVarReg(param1);
7597 akron1 2431
            IF isLong(param2) THEN
7693 akron1 2432
                reg2 := GetAnyReg();
7597 akron1 2433
                movrc(reg2, param2);
2434
                IF reg1 # -1 THEN
7693 akron1 2435
                    add(reg1, reg2)
7597 akron1 2436
                ELSE
2437
                    n := param1 * 8;
2438
                    Rex(0, reg2);
7693 akron1 2439
                    OutByte2(01H, 45H + long(n) + (reg2 MOD 8) * 8);
2440
                    OutIntByte(n) // add qword[rbp+n],reg2
7597 akron1 2441
                END;
2442
                drop
7693 akron1 2443
            ELSIF ABS(param2) = 1 THEN
7597 akron1 2444
                IF reg1 # -1 THEN
7693 akron1 2445
                    IF param2 = 1 THEN
2446
                        incr(reg1)
7597 akron1 2447
                    ELSE
7693 akron1 2448
                        decr(reg1)
7597 akron1 2449
                    END
2450
                ELSE
2451
                    n := param1 * 8;
7693 akron1 2452
                    OutByte3(48H, 0FFH, 45H + 8 * ORD(param2 = -1) + long(n)); // inc/dec qword[rbp+n]
2453
                    OutIntByte(n)
2454
                END
2455
            ELSE
2456
                IF reg1 # -1 THEN
2457
                    addrc(reg1, param2)
2458
                ELSE
2459
                    n := param1 * 8;
2460
                    OutByte3(48H, 81H + short(param2), 45H + long(n));
7597 akron1 2461
                    OutIntByte(n);
7693 akron1 2462
                    OutIntByte(param2) // add qword[rbp+n],param2
7597 akron1 2463
                END
2464
            END
2465
 
7693 akron1 2466
        |IL.opLADR_INCCB, IL.opLADR_DECCB:
2467
            reg1 := GetVarReg(param1);
7597 akron1 2468
            param2 := param2 MOD 256;
2469
            IF reg1 # -1 THEN
7693 akron1 2470
                IF opcode = IL.opLADR_DECCB THEN
7597 akron1 2471
                    subrc(reg1, param2)
2472
                ELSE
2473
                    addrc(reg1, param2)
2474
                END;
2475
                andrc(reg1, 255)
2476
            ELSE
2477
                n := param1 * 8;
7693 akron1 2478
                OutByte2(80H, 45H + long(n) + 28H * ORD(opcode = IL.opLADR_DECCB));
7597 akron1 2479
                OutIntByte(n);
2480
                OutByte(param2) // add/sub byte[rbp+n],param2
2481
            END
2482
 
7693 akron1 2483
        |IL.opLADR_INC, IL.opLADR_DEC:
7597 akron1 2484
            UnOp(reg1);
7693 akron1 2485
            reg2 := GetVarReg(param2);
7597 akron1 2486
            IF reg2 # -1 THEN
7693 akron1 2487
                IF opcode = IL.opLADR_DEC THEN
7597 akron1 2488
                    sub(reg2, reg1)
2489
                ELSE
2490
                    add(reg2, reg1)
2491
                END
2492
            ELSE
2493
                n := param2 * 8;
2494
                Rex(0, reg1);
7693 akron1 2495
                OutByte2(01H + 28H * ORD(opcode = IL.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
7597 akron1 2496
                OutIntByte(n) // add/sub qword[rbp+n],reg1
2497
            END;
2498
            drop
2499
 
7693 akron1 2500
        |IL.opLADR_INCB, IL.opLADR_DECB:
7597 akron1 2501
            UnOp(reg1);
7693 akron1 2502
            reg2 := GetVarReg(param2);
7597 akron1 2503
            IF reg2 # -1 THEN
7693 akron1 2504
                IF opcode = IL.opLADR_DECB THEN
7597 akron1 2505
                    sub(reg2, reg1)
2506
                ELSE
2507
                    add(reg2, reg1)
2508
                END;
2509
                andrc(reg2, 255)
2510
            ELSE
2511
                n := param2 * 8;
2512
                IF reg1 >= 8 THEN
2513
                    OutByte(44H)
2514
                END;
7693 akron1 2515
                OutByte2(28H * ORD(opcode = IL.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
7597 akron1 2516
                OutIntByte(n) // add/sub byte[rbp+n], reg1_8
2517
            END;
2518
            drop
2519
 
7693 akron1 2520
        |IL.opLADR_INCL, IL.opLADR_EXCL:
7597 akron1 2521
            UnOp(reg1);
2522
            cmprc(reg1, 64);
7693 akron1 2523
            reg2 := GetVarReg(param2);
7597 akron1 2524
            IF reg2 # -1 THEN
2525
                OutByte2(73H, 4); // jnb L
7693 akron1 2526
                oprr2(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), reg2, reg1) // bts/btr reg2, reg1
7597 akron1 2527
            ELSE
2528
                n := param2 * 8;
2529
                OutByte2(73H, 5 + 3 * ORD(~isByte(n))); // jnb L
2530
                Rex(0, reg1);
7693 akron1 2531
                OutByte3(0FH, 0ABH + 8 * ORD(opcode = IL.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
7597 akron1 2532
                OutIntByte(n) // bts/btr qword[rbp+n], reg1
2533
            END;
2534
            // L:
2535
            drop
2536
 
7693 akron1 2537
        |IL.opLADR_INCLC, IL.opLADR_EXCLC:
2538
            reg1 := GetVarReg(param1);
7597 akron1 2539
            IF reg1 # -1 THEN
2540
                Rex(reg1, 0);
2541
                OutByte3(0FH, 0BAH, 0E8H);  // bts/btr reg1, param2
7693 akron1 2542
                OutByte2(reg1 MOD 8 + 8 * ORD(opcode = IL.opLADR_EXCLC), param2)
7597 akron1 2543
            ELSE
2544
                n := param1 * 8;
2545
                OutByte3(48H, 0FH, 0BAH);  // bts/btr qword[rbp+n], param2
7693 akron1 2546
                OutByte(6DH + long(n) + 8 * ORD(opcode = IL.opLADR_EXCLC));
7597 akron1 2547
                OutIntByte(n);
2548
                OutByte(param2)
2549
            END
2550
 
7693 akron1 2551
        |IL.opLOOP, IL.opENDLOOP:
7597 akron1 2552
 
2553
        END;
2554
 
2555
        cmd := cmd.next(COMMAND)
2556
    END;
2557
 
2558
    ASSERT(R.pushed = 0);
2559
    ASSERT(R.top = -1);
2560
    ASSERT(xmm = -1)
2561
END translate;
2562
 
2563
 
7693 akron1 2564
PROCEDURE prolog (code: IL.CODES; modname: ARRAY OF CHAR; target, stack_size: INTEGER);
7597 akron1 2565
VAR
7693 akron1 2566
    ModName_Offs, entry, L: INTEGER;
7597 akron1 2567
 
2568
BEGIN
7693 akron1 2569
    ModName_Offs := tcount * 8 + CHL.Length(code.data);
7597 akron1 2570
    Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
7693 akron1 2571
    ASSERT(UTILS.Align(Numbers_Offs, 16));
7597 akron1 2572
 
2573
    entry := NewLabel();
2574
    X86.SetLabel(entry);
2575
 
2576
    IF target = mConst.Target_iDLL64 THEN
2577
        dllret := NewLabel();
2578
        push(r8);
2579
        push(rdx);
2580
        push(rcx);
7693 akron1 2581
        CallRTL(IL._dllentry);
7597 akron1 2582
        test(rax);
2583
        jcc(je, dllret)
2584
    END;
2585
 
7693 akron1 2586
    IF target = mConst.Target_iELF64 THEN
2587
        push(rsp)
2588
    ELSE
2589
        pushc(0)
2590
    END;
2591
 
7597 akron1 2592
    lea(rax, entry, sCODE);
2593
    push(rax);
2594
    pushDA(0); //TYPES
7693 akron1 2595
    pushc(tcount);
7597 akron1 2596
    pushDA(ModName_Offs); //MODNAME
7693 akron1 2597
    CallRTL(IL._init);
2598
 
2599
    IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64} THEN
2600
        L := NewLabel();
2601
        pushc(0);
2602
        push(rsp);
2603
        pushc(1024 * 1024 * stack_size);
2604
        pushc(0);
2605
        CallRTL(IL._new);
2606
        pop(rax);
2607
        test(rax);
2608
        jcc(je, L);
2609
        addrc(rax, 1024 * 1024 * stack_size - 8);
2610
        mov(rsp, rax);
2611
        X86.SetLabel(L)
2612
    END
7597 akron1 2613
END prolog;
2614
 
2615
 
7693 akron1 2616
PROCEDURE epilog (code: IL.CODES; modname: ARRAY OF CHAR; target: INTEGER);
7597 akron1 2617
VAR
2618
    i, n: INTEGER;
2619
    number: Number;
7693 akron1 2620
    exp: IL.EXPORT_PROC;
7597 akron1 2621
 
2622
 
2623
    PROCEDURE import (imp: LISTS.LIST);
2624
    VAR
7693 akron1 2625
        lib:  IL.IMPORT_LIB;
2626
        proc: IL.IMPORT_PROC;
7597 akron1 2627
 
2628
    BEGIN
2629
 
7693 akron1 2630
        lib := imp.first(IL.IMPORT_LIB);
7597 akron1 2631
        WHILE lib # NIL DO
2632
            BIN.Import(prog, lib.name, 0);
7693 akron1 2633
            proc := lib.procs.first(IL.IMPORT_PROC);
7597 akron1 2634
            WHILE proc # NIL DO
2635
                BIN.Import(prog, proc.name, proc.label);
7693 akron1 2636
                proc := proc.next(IL.IMPORT_PROC)
7597 akron1 2637
            END;
7693 akron1 2638
            lib := lib.next(IL.IMPORT_LIB)
7597 akron1 2639
        END
2640
 
2641
    END import;
2642
 
2643
 
2644
BEGIN
2645
    IF target = mConst.Target_iDLL64 THEN
2646
        X86.SetLabel(dllret);
2647
        OutByte(0C3H) // ret
7693 akron1 2648
    ELSIF target = mConst.Target_iELFSO64 THEN
2649
        sofinit := NewLabel();
2650
        OutByte(0C3H);  // ret
2651
        X86.SetLabel(sofinit);
2652
        CallRTL(IL._sofinit);
2653
        OutByte(0C3H)   // ret
7597 akron1 2654
    ELSE
2655
        pushc(0);
7693 akron1 2656
        CallRTL(IL._exit)
7597 akron1 2657
    END;
2658
 
2659
    X86.fixup;
2660
 
2661
    i := 0;
7693 akron1 2662
    WHILE i < tcount DO
7597 akron1 2663
        BIN.PutData64LE(prog, CHL.GetInt(code.types, i));
2664
        INC(i)
2665
    END;
2666
 
2667
    i := 0;
2668
    WHILE i < CHL.Length(code.data) DO
2669
        BIN.PutData(prog, CHL.GetByte(code.data, i));
2670
        INC(i)
2671
    END;
2672
 
2673
    BIN.PutDataStr(prog, modname);
2674
    BIN.PutData(prog, 0);
2675
    n := CHL.Length(prog.data);
7693 akron1 2676
    ASSERT(UTILS.Align(n, 16));
7597 akron1 2677
    i := n - CHL.Length(prog.data);
2678
    WHILE i > 0 DO
2679
        BIN.PutData(prog, 0);
2680
        DEC(i)
2681
    END;
2682
    number := Numbers.first(Number);
2683
    FOR i := 0 TO Numbers_Count - 1 DO
2684
        BIN.PutData64LE(prog, number.value);
2685
        number := number.next(Number)
2686
    END;
2687
 
7693 akron1 2688
    exp := code.export.first(IL.EXPORT_PROC);
7597 akron1 2689
    WHILE exp # NIL DO
2690
        BIN.Export(prog, exp.name, exp.label);
7693 akron1 2691
        exp := exp.next(IL.EXPORT_PROC)
7597 akron1 2692
    END;
2693
 
2694
    import(code.import)
2695
END epilog;
2696
 
2697
 
2698
PROCEDURE rload (reg, offs, size: INTEGER);
2699
BEGIN
2700
    offs := offs * 8;
2701
    CASE size OF
2702
    |1: movzx(reg, rbp, offs, FALSE)
2703
    |2: movzx(reg, rbp, offs, TRUE)
2704
    |4: xor(reg, reg); movrm32(reg, rbp, offs)
2705
    |8: movrm(reg, rbp, offs)
2706
    END
2707
END rload;
2708
 
2709
 
2710
PROCEDURE rsave (reg, offs, size: INTEGER);
2711
BEGIN
2712
    offs := offs * 8;
2713
    CASE size OF
2714
    |1: movmr8(rbp, offs, reg)
2715
    |2: movmr16(rbp, offs, reg)
2716
    |4: movmr32(rbp, offs, reg)
2717
    |8: movmr(rbp, offs, reg)
2718
    END
2719
END rsave;
2720
 
2721
 
7693 akron1 2722
PROCEDURE CodeGen* (code: IL.CODES; outname: ARRAY OF CHAR; target: INTEGER; options: PROG.OPTIONS);
7597 akron1 2723
VAR
2724
    path, modname, ext: PATHS.PATH;
2725
 
2726
BEGIN
7693 akron1 2727
    tcount := CHL.Length(code.types);
2728
 
7597 akron1 2729
    Win64RegPar[0] := rcx;
2730
    Win64RegPar[1] := rdx;
2731
    Win64RegPar[2] := r8;
2732
    Win64RegPar[3] := r9;
2733
 
2734
    SystemVRegPar[0] := rdi;
2735
    SystemVRegPar[1] := rsi;
2736
    SystemVRegPar[2] := rdx;
2737
    SystemVRegPar[3] := rcx;
2738
    SystemVRegPar[4] := r8;
2739
    SystemVRegPar[5] := r9;
2740
 
2741
    PATHS.split(outname, path, modname, ext);
2742
    S.append(modname, ext);
2743
 
7693 akron1 2744
    REG.Init(R, push, pop, mov, xchg, rload, rsave, {rax, r10, r11}, {rcx, rdx, r8, r9});
7597 akron1 2745
 
7693 akron1 2746
    code.bss := MAX(code.bss, MAX(code.dmin - CHL.Length(code.data), 8));
7597 akron1 2747
 
2748
    Numbers := LISTS.create(NIL);
2749
    Numbers_Count := 0;
2750
    NewNumber(ROR(1, 1));      (* 8000000000000000H *)
2751
    NewNumber(0);
2752
    NewNumber(ROR(-2, 1));     (* 7FFFFFFFFFFFFFFFH *)
2753
    NewNumber(-1);
2754
    NewNumber(ROR(7FFH, 12));  (* +Infinity *)
2755
    NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1))));  (* {0..51, 63} *)
2756
    NewNumber(LSR(ASR(ROR(1, 1), 9), 2));  (* {52..61} *)
2757
 
2758
    prog := BIN.create(code.lcount);
7693 akron1 2759
    BIN.SetParams(prog, code.bss, 1, WCHR(1), WCHR(0));
7597 akron1 2760
 
2761
    X86.SetProgram(prog);
2762
 
7693 akron1 2763
    prolog(code, modname, target, options.stack);
2764
    translate(code.commands, tcount * 8);
7597 akron1 2765
    epilog(code, modname, target);
2766
 
2767
    BIN.fixup(prog);
2768
    IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
7693 akron1 2769
        PE32.write(prog, outname, options.base, target = mConst.Target_iConsole64, target = mConst.Target_iDLL64, TRUE)
2770
    ELSIF target IN {mConst.Target_iELF64, mConst.Target_iELFSO64} THEN
2771
        ELF.write(prog, outname, sofinit, target = mConst.Target_iELFSO64, TRUE)
7597 akron1 2772
    END
2773
END CodeGen;
2774
 
2775
 
2776
END AMD64.