Subversion Repositories Kolibri OS

Rev

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