Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
7597 akron1 1
(*
2
    BSD 2-Clause License
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;
7667 akron1 669
    param2:     INTEGER;
7597 akron1 670
 
671
BEGIN
672
    loop := 1;
673
    variables := cmd.variables;
674
    leave := FALSE;
675
    leaf := TRUE;
676
 
677
    cur := cmd.next(COMMAND);
678
    REPEAT
679
        CASE cur.opcode OF
680
        |CODE.opLLOAD64,
681
         CODE.opLLOAD8,
682
         CODE.opLLOAD16,
683
         CODE.opLLOAD32,
684
         CODE.opLLOAD64_PARAM,
685
         CODE.opLLOAD32_PARAM,
686
         CODE.opLADR_SAVE,
687
         CODE.opLADR_INC1,
688
         CODE.opLADR_DEC1,
689
         CODE.opLADR_INC,
690
         CODE.opLADR_DEC,
691
         CODE.opLADR_INC1B,
692
         CODE.opLADR_DEC1B,
693
         CODE.opLADR_INCB,
694
         CODE.opLADR_DECB,
695
         CODE.opLADR_INCL,
696
         CODE.opLADR_EXCL,
697
         CODE.opLADR_UNPK:
698
            lvar := getVar(variables, cur.param2);
699
            IF (lvar # NIL) & (lvar.count # -1) THEN
700
                INC(lvar.count, loop)
701
            END
702
 
703
        |CODE.opLADR_SAVEC,
704
         CODE.opLADR_INCC,
705
         CODE.opLADR_DECC,
706
         CODE.opLADR_INCCB,
707
         CODE.opLADR_DECCB,
708
         CODE.opLADR_INCLC,
709
         CODE.opLADR_EXCLC:
710
            lvar := getVar(variables, cur.param1);
711
            IF (lvar # NIL) & (lvar.count # -1) THEN
712
                INC(lvar.count, loop)
713
            END
714
 
715
        |CODE.opLADR:
716
            lvar := getVar(variables, cur.param2);
717
            IF (lvar # NIL) & (lvar.count # -1) THEN
718
                lvar.count := -1
719
            END
720
 
721
        |CODE.opLOOP:
722
            INC(loop, 10)
723
 
724
        |CODE.opENDLOOP:
725
            DEC(loop, 10)
726
 
727
        |CODE.opLEAVE,
728
         CODE.opLEAVER,
729
         CODE.opLEAVEF:
730
            leave := TRUE
731
 
732
        |CODE.opCALL, CODE.opCALLP, CODE.opCALLI,
733
         CODE.opWIN64CALL, CODE.opWIN64CALLP, CODE.opWIN64CALLI,
7667 akron1 734
         CODE.opSYSVCALL, CODE.opSYSVCALLP, CODE.opSYSVCALLI,
735
 
736
         CODE.opSAVES, CODE.opRSET, CODE.opRSETR,
737
         CODE.opRSETL, CODE.opRSET1,
738
         CODE.opEQS .. CODE.opGES,
739
         CODE.opEQS2 .. CODE.opGES2,
740
         CODE.opEQSW .. CODE.opGESW,
741
         CODE.opEQSW2 .. CODE.opGESW2,
742
         CODE.opCOPY, CODE.opMOVE, CODE.opCOPYA,
743
         CODE.opCOPYS, CODE.opCOPYS2, CODE.opROT,
744
         CODE.opNEW, CODE.opDISP, CODE.opISREC,
745
         CODE.opIS, CODE.opTYPEGR, CODE.opTYPEGP,
746
         CODE.opCASET, CODE.opDIV,
747
         CODE.opDIVL, CODE.opMOD,
748
         CODE.opMODL, CODE.opLENGTH, CODE.opLENGTHW:
7597 akron1 749
            leaf := FALSE
750
 
7667 akron1 751
        |CODE.opDIVR, CODE.opMODR:
752
            param2 := cur.param2;
753
            IF param2 >= 1 THEN
754
                param2 := X86.log2(param2)
755
            ELSIF param2 <= -1 THEN
756
                param2 := X86.log2(-param2)
757
            ELSE
758
                param2 := -1
759
            END;
760
            IF param2 < 0 THEN
761
                leaf := FALSE
762
            END
763
 
7597 akron1 764
        ELSE
765
 
766
        END;
767
        cur := cur.next(COMMAND)
768
    UNTIL leave OR ~leaf;
769
 
770
    IF leaf THEN
771
        REPEAT
772
            reg := -1;
773
            max := -1;
774
            rvar := NIL;
775
            lvar := variables.first(CODE.LOCALVAR);
776
            WHILE lvar # NIL DO
777
                IF lvar.count > max THEN
778
                    max := lvar.count;
779
                    rvar := lvar
780
                END;
781
                lvar := lvar.next(CODE.LOCALVAR)
782
            END;
783
 
784
            IF rvar # NIL THEN
785
                reg := REG.GetAnyVarReg(R);
786
                IF reg # -1 THEN
787
                    REG.Lock(R, reg, rvar.offset, rvar.size);
788
                    REG.Load(R, reg);
789
                    rvar.count := -1
790
                END
791
            END
792
 
793
        UNTIL (rvar = NIL) OR (reg = -1)
794
    END
795
 
796
END allocReg;
797
 
798
 
799
PROCEDURE GetRegA;
800
BEGIN
801
    ASSERT(REG.GetReg(R, rax))
802
END GetRegA;
803
 
804
 
805
PROCEDURE Win64Passing (params: INTEGER);
806
VAR
807
    n, i: INTEGER;
808
 
809
BEGIN
810
    n := params MOD 32;
811
    params := params DIV 32;
812
    FOR i := 0 TO n - 1 DO
813
        IF i IN BITS(params) THEN
814
            movsdrm(i, rsp, i * 8)
815
        ELSE
816
            movrm(Win64RegPar[i], rsp, i * 8)
817
        END
818
    END
819
END Win64Passing;
820
 
821
 
822
PROCEDURE SysVPassing (params: INTEGER);
823
VAR
824
    n, i, s, p, ofs: INTEGER;
825
    i_count, f_count: INTEGER;
826
    reg: BOOLEAN;
827
 
828
BEGIN
829
    ASSERT(r10 IN R.regs);
830
    n := params MOD 32;
831
    params := params DIV 32;
832
    s := 0;
833
 
834
    i_count := 0;
835
    f_count := 0;
836
    FOR i := 0 TO n - 1 DO
837
        IF i IN BITS(params) THEN
838
            INC(f_count)
839
        ELSE
840
            INC(i_count)
841
        END
842
    END;
843
 
844
    s := MAX(0, f_count - 8) + MAX(0, i_count - 6);
845
    p := 0;
846
 
847
    subrc(rsp, s * 8);
848
 
849
    i_count := 0;
850
    f_count := 0;
851
    FOR i := 0 TO n - 1 DO
852
        ofs := (i + s) * 8;
853
        IF i IN BITS(params) THEN
854
            reg := f_count <= 7;
855
            IF reg THEN
856
                movsdrm(f_count, rsp, ofs);
857
                INC(f_count)
858
            END
859
        ELSE
860
            reg := i_count <= 5;
861
            IF reg THEN
862
                movrm(SystemVRegPar[i_count], rsp, ofs);
863
                INC(i_count)
864
            END
865
        END;
866
 
867
        IF ~reg THEN
868
            movrm(r10, rsp, ofs);
869
            movmr(rsp, p, r10);
870
            INC(p, 8)
871
        END
872
    END
873
END SysVPassing;
874
 
875
 
876
PROCEDURE fcmp (op: INTEGER; xmm: INTEGER);
877
VAR
878
    cc, reg: INTEGER;
879
 
880
BEGIN
881
    reg := REG.GetAnyReg(R);
882
    xor(reg, reg);
883
    CASE op OF
884
    |CODE.opEQF, CODE.opEQFI:
885
        comisd(xmm - 1, xmm);
886
        cc := sete
887
 
888
    |CODE.opNEF, CODE.opNEFI:
889
        comisd(xmm - 1, xmm);
890
        cc := setne
891
 
892
    |CODE.opLTF, CODE.opGTFI:
893
        comisd(xmm - 1, xmm);
894
        cc := setc
895
 
896
    |CODE.opGTF, CODE.opLTFI:
897
        comisd(xmm, xmm - 1);
898
        cc := setc
899
 
900
    |CODE.opLEF, CODE.opGEFI:
901
        comisd(xmm, xmm - 1);
902
        cc := setnc
903
 
904
    |CODE.opGEF, CODE.opLEFI:
905
        comisd(xmm - 1, xmm);
906
        cc := setnc
907
    END;
908
    OutByte2(7AH, 3 + reg DIV 8); // jp L
909
    setcc(cc, reg);
910
    //L:
911
END fcmp;
912
 
913
 
914
PROCEDURE translate (commands: LISTS.LIST; stroffs: INTEGER);
915
VAR
916
    cmd, next: COMMAND;
917
 
918
    param1, param2, param3, a, b, c, n, label, L, i, cc: INTEGER;
919
 
920
    reg1, reg2, xmm: INTEGER;
921
 
922
    float: REAL;
923
 
924
    regVar: BOOLEAN;
925
 
926
BEGIN
927
    xmm := -1;
928
    cmd := commands.first(COMMAND);
929
    WHILE cmd # NIL DO
930
 
931
        param1 := cmd.param1;
932
        param2 := cmd.param2;
933
 
934
        CASE cmd.opcode OF
935
 
936
        |CODE.opJMP:
937
            jmp(param1)
938
 
939
        |CODE.opCALL, CODE.opWIN64CALL, CODE.opSYSVCALL:
940
            REG.Store(R);
941
            CASE cmd.opcode OF
942
            |CODE.opCALL:
943
            |CODE.opWIN64CALL: Win64Passing(param2)
944
            |CODE.opSYSVCALL:  SysVPassing(param2)
945
            END;
946
            X86.call(param1);
947
            REG.Restore(R)
948
 
949
        |CODE.opCALLP, CODE.opWIN64CALLP, CODE.opSYSVCALLP:
950
            UnOp(reg1);
951
            IF reg1 # rax THEN
952
                GetRegA;
953
                ASSERT(REG.Exchange(R, reg1, rax));
954
                drop
955
            END;
956
            drop;
957
            REG.Store(R);
958
            CASE cmd.opcode OF
959
            |CODE.opCALLP:
960
            |CODE.opWIN64CALLP: Win64Passing(param2)
961
            |CODE.opSYSVCALLP:  SysVPassing(param2)
962
            END;
963
            OutByte2(0FFH, 0D0H); // call rax
964
            REG.Restore(R);
965
            ASSERT(R.top = -1)
966
 
967
        |CODE.opCALLI, CODE.opWIN64CALLI, CODE.opSYSVCALLI:
968
            REG.Store(R);
969
            CASE cmd.opcode OF
970
            |CODE.opCALLI:
971
            |CODE.opWIN64CALLI: Win64Passing(param2)
972
            |CODE.opSYSVCALLI:  SysVPassing(param2)
973
            END;
974
            callimp(param1);
975
            REG.Restore(R)
976
 
977
        |CODE.opLABEL:
978
            X86.SetLabel(param2)
979
 
980
        |CODE.opERR:
981
            CallRTL(CODE._error)
982
 
983
        |CODE.opERRC:
984
            pushc(param2)
985
 
986
        |CODE.opPRECALL:
987
            n := param2;
988
            IF (param1 # 0) & (n # 0) THEN
989
                subrc(rsp, 8)
990
            END;
991
            WHILE n > 0 DO
992
                subrc(rsp, 8);
993
                movsdmr(rsp, 0, xmm);
994
                DEC(xmm);
995
                DEC(n)
996
            END;
997
            ASSERT(xmm = -1);
998
            PushAll(0)
999
 
1000
        |CODE.opWIN64ALIGN16:
1001
            ASSERT(rax IN R.regs);
1002
            mov(rax, rsp);
1003
            andrc(rsp, -16);
1004
            push(rax);
1005
            subrc(rsp, (MAX(param2 - 4, 0) MOD 2 + MAX(4 - param2, 0) + 1) * 8)
1006
 
1007
        |CODE.opSYSVALIGN16:
1008
            ASSERT(rax IN R.regs);
1009
            mov(rax, rsp);
1010
            andrc(rsp, -16);
1011
            push(rax);
1012
            IF ~ODD(param2) THEN
1013
                push(rax)
1014
            END
1015
 
1016
        |CODE.opRESF:
1017
            ASSERT(xmm = -1);
1018
            INC(xmm);
1019
            n := param2;
1020
            IF n > 0 THEN
1021
                movsdmr(rsp, n * 8, xmm);
1022
                DEC(xmm);
1023
                INC(n)
1024
            END;
1025
 
1026
            WHILE n > 0 DO
1027
                INC(xmm);
1028
                movsdrm(xmm, rsp, 0);
1029
                addrc(rsp, 8);
1030
                DEC(n)
1031
            END
1032
 
1033
        |CODE.opRES:
1034
            ASSERT(R.top = -1);
1035
            GetRegA;
1036
            n := param2;
1037
            WHILE n > 0 DO
1038
                INC(xmm);
1039
                movsdrm(xmm, rsp, 0);
1040
                addrc(rsp, 8);
1041
                DEC(n)
1042
            END
1043
 
1044
        |CODE.opENTER:
1045
            ASSERT(R.top = -1);
1046
 
1047
            X86.SetLabel(param1);
1048
 
1049
            param3 := cmd.param3;
1050
 
1051
            IF param3 > 0 THEN
1052
                push(rbp);
1053
                mov(rbp, rsp);
1054
 
1055
                n := param3 MOD 32;
1056
                param3 := param3 DIV 32;
1057
 
1058
                FOR i := 0 TO n - 1 DO
1059
                    IF i IN BITS(param3) THEN
1060
                        movsdmr(rbp, i * 8 + 16, i)
1061
                    ELSE
1062
                        movmr(rbp, i * 8 + 16, Win64RegPar[i])
1063
                    END
1064
                END
1065
            ELSIF param3 < 0 THEN
1066
                param3 := -param3;
1067
                n := (param3 MOD 32) * 8;
1068
                param3 := param3 DIV 32;
1069
                pop(r10);
1070
                subrc(rsp, n);
1071
                push(r10);
1072
                push(rbp);
1073
                mov(rbp, rsp);
1074
 
1075
                a := 0;
1076
                b := 0;
1077
                c := 0;
1078
 
1079
                INC(n, 16);
1080
 
1081
                FOR i := 16 TO n - 8 BY 8 DO
1082
                    IF ODD(param3) THEN
1083
                        IF b <= 7 THEN
1084
                            movsdmr(rbp, i, b);
1085
                            INC(b)
1086
                        ELSE
1087
                            movrm(r10, rbp, n + c);
1088
                            movmr(rbp, i, r10);
1089
                            INC(c, 8)
1090
                        END
1091
                    ELSE
1092
                        IF a <= 5 THEN
1093
                            movmr(rbp, i, SystemVRegPar[a]);
1094
                            INC(a)
1095
                        ELSE
1096
                            movrm(r10, rbp, n + c);
1097
                            movmr(rbp, i, r10);
1098
                            INC(c, 8)
1099
                        END
1100
                    END;
1101
                    param3 := param3 DIV 2
1102
                END
1103
            ELSE
1104
                push(rbp);
1105
                mov(rbp, rsp)
1106
            END;
1107
 
1108
            n := param2;
1109
            IF n > 4 THEN
1110
                movrc(rcx, n);
1111
                                      // L:
1112
                pushc(0);
1113
                OutByte2(0E2H, 0FCH) // loop L
1114
            ELSE
1115
                WHILE n > 0 DO
1116
                    pushc(0);
1117
                    DEC(n)
1118
                END
1119
            END;
1120
 
1121
            IF cmd.allocReg THEN
1122
                allocReg(cmd)
1123
            END
1124
 
1125
        |CODE.opLEAVE, CODE.opLEAVER, CODE.opLEAVEF:
1126
            IF cmd.opcode = CODE.opLEAVER THEN
1127
                UnOp(reg1);
1128
                IF reg1 # rax THEN
1129
                    GetRegA;
1130
                    ASSERT(REG.Exchange(R, reg1, rax));
1131
                    drop
1132
                END;
1133
                drop
1134
            END;
1135
 
1136
            ASSERT(R.top = -1);
1137
 
1138
            IF cmd.opcode = CODE.opLEAVEF THEN
1139
                DEC(xmm)
1140
            END;
1141
 
1142
            ASSERT(xmm = -1);
1143
 
1144
            mov(rsp, rbp);
1145
            pop(rbp);
1146
            IF param2 > 0 THEN
1147
                OutByte3(0C2H, (param2 * 8) MOD 256, (param2 * 8) DIV 256)  // ret param2
1148
            ELSE
1149
                OutByte(0C3H) // ret
1150
            END;
1151
            REG.Reset(R)
1152
 
1153
        |CODE.opSAVES:
1154
            UnOp(reg1);
1155
            drop;
1156
            PushAll(0);
1157
            push(reg1);
1158
            pushDA(stroffs + param2);
1159
            pushc(param1);
1160
            CallRTL(CODE._move)
1161
 
1162
        |CODE.opSADR:
1163
            reg1 := REG.GetAnyReg(R);
1164
            lea(reg1, stroffs + param2, sDATA)
1165
 
1166
        |CODE.opLOAD8:
1167
            UnOp(reg1);
1168
            movzx(reg1, reg1, 0, FALSE)
1169
 
1170
        |CODE.opLOAD16:
1171
            UnOp(reg1);
1172
            movzx(reg1, reg1, 0, TRUE)
1173
 
1174
        |CODE.opLOAD32:
1175
            UnOp(reg1);
1176
            movrm32(reg1, reg1, 0);
1177
            shiftrc(shl, reg1, 32);
1178
            shiftrc(shr, reg1, 32)
1179
 
1180
        |CODE.opLOAD64:
1181
            UnOp(reg1);
1182
            movrm(reg1, reg1, 0)
1183
 
1184
        |CODE.opLLOAD64:
1185
            reg1 := REG.GetAnyReg(R);
1186
            reg2 := REG.GetVarReg(R, param2);
1187
            IF reg2 # -1 THEN
1188
                mov(reg1, reg2)
1189
            ELSE
1190
                movrm(reg1, rbp, param2 * 8)
1191
            END
1192
 
1193
        |CODE.opLLOAD8,
1194
         CODE.opLLOAD16:
1195
            reg1 := REG.GetAnyReg(R);
1196
            reg2 := REG.GetVarReg(R, param2);
1197
            IF reg2 # -1 THEN
1198
                mov(reg1, reg2)
1199
            ELSE
1200
                movzx(reg1, rbp, param2 * 8, cmd.opcode = CODE.opLLOAD16)
1201
            END
1202
 
1203
        |CODE.opLLOAD32:
1204
            reg1 := REG.GetAnyReg(R);
1205
            reg2 := REG.GetVarReg(R, param2);
1206
            IF reg2 # -1 THEN
1207
                mov(reg1, reg2)
1208
            ELSE
1209
                n := param2 * 8;
1210
                xor(reg1, reg1);
1211
                movrm32(reg1, rbp, n)
1212
            END
1213
 
1214
        |CODE.opGLOAD64:
1215
            reg1 := REG.GetAnyReg(R);
1216
            lea(reg1, param2, sBSS);
1217
            movrm(reg1, reg1, 0)
1218
 
1219
        |CODE.opGLOAD8:
1220
            reg1 := REG.GetAnyReg(R);
1221
            lea(reg1, param2, sBSS);
1222
            movzx(reg1, reg1, 0, FALSE)
1223
 
1224
        |CODE.opGLOAD16:
1225
            reg1 := REG.GetAnyReg(R);
1226
            lea(reg1, param2, sBSS);
1227
            movzx(reg1, reg1, 0, TRUE)
1228
 
1229
        |CODE.opGLOAD32:
1230
            reg1 := REG.GetAnyReg(R);
1231
            xor(reg1, reg1);
1232
            lea(reg1, param2, sBSS);
1233
            movrm32(reg1, reg1, 0)
1234
 
1235
        |CODE.opVLOAD64:
1236
            reg1 := REG.GetAnyReg(R);
1237
            movrm(reg1, rbp, param2 * 8);
1238
            movrm(reg1, reg1, 0)
1239
 
1240
        |CODE.opVLOAD8,
1241
         CODE.opVLOAD16:
1242
            reg1 := REG.GetAnyReg(R);
1243
            movrm(reg1, rbp, param2 * 8);
1244
            movzx(reg1, reg1, 0, cmd.opcode = CODE.opVLOAD16)
1245
 
1246
        |CODE.opVLOAD32:
1247
            reg1 := REG.GetAnyReg(R);
1248
            reg2 := REG.GetAnyReg(R);
1249
            xor(reg1, reg1);
1250
            movrm(reg2, rbp, param2 * 8);
1251
            movrm32(reg1, reg2, 0);
1252
            drop
1253
 
1254
        |CODE.opLADR:
1255
            n := param2 * 8;
1256
            next := cmd.next(COMMAND);
1257
            IF next.opcode = CODE.opSAVEF THEN
1258
                movsdmr(rbp, n, xmm);
1259
                DEC(xmm);
1260
                cmd := next
1261
            ELSIF next.opcode = CODE.opLOADF THEN
1262
                INC(xmm);
1263
                movsdrm(xmm, rbp, n);
1264
                cmd := next
1265
            ELSE
1266
                reg1 := REG.GetAnyReg(R);
1267
                Rex(0, reg1);
1268
                OutByte2(8DH, 45H + long(n) + (reg1 MOD 8) * 8);  // lea reg1, qword[rbp+n]
1269
                OutIntByte(n)
1270
            END
1271
 
1272
        |CODE.opGADR:
1273
            reg1 := REG.GetAnyReg(R);
1274
            lea(reg1, param2, sBSS)
1275
 
1276
        |CODE.opVADR:
1277
            reg1 := REG.GetAnyReg(R);
1278
            movrm(reg1, rbp, param2 * 8)
1279
 
1280
        |CODE.opSAVE8C:
1281
            UnOp(reg1);
1282
            IF reg1 >= 8 THEN
1283
                OutByte(41H)
1284
            END;
1285
            OutByte3(0C6H, reg1 MOD 8, param2); // mov byte[reg1], param2
1286
            drop
1287
 
1288
        |CODE.opSAVE16C:
1289
            UnOp(reg1);
1290
            OutByte(66H);
1291
            IF reg1 >= 8 THEN
1292
                OutByte(41H)
1293
            END;
1294
            OutByte2(0C7H, reg1 MOD 8);
1295
            OutByte2(param2 MOD 256, param2 DIV 256); // mov word[reg1], param2
1296
            drop
1297
 
1298
        |CODE.opSAVEC:
1299
            UnOp(reg1);
1300
            IF isLong(param2) THEN
1301
                reg2 := REG.GetAnyReg(R);
1302
                movrc(reg2, param2);
1303
                movmr(reg1, 0, reg2);
1304
                drop
1305
            ELSE
1306
                Rex(reg1, 0);
1307
                OutByte2(0C7H, reg1 MOD 8); // mov qword[reg1], param2
1308
                OutInt(param2)
1309
            END;
1310
            drop
1311
 
1312
        |CODE.opRSET:
1313
            PushAll(2);
1314
            CallRTL(CODE._set);
1315
            GetRegA
1316
 
1317
        |CODE.opRSETR:
1318
            PushAll(1);
1319
            pushc(param2);
1320
            CallRTL(CODE._set);
1321
            GetRegA
1322
 
1323
        |CODE.opRSETL:
1324
            PushAll(1);
1325
            pushc(param2);
1326
            CallRTL(CODE._set2);
1327
            GetRegA
1328
 
1329
        |CODE.opRSET1:
1330
            UnOp(reg1);
1331
            PushAll(1);
1332
            push(reg1);
1333
            CallRTL(CODE._set);
1334
            GetRegA
1335
 
1336
        |CODE.opINCL, CODE.opEXCL:
1337
            BinOp(reg1, reg2);
1338
            cmprc(reg1, 64);
1339
            OutByte2(73H, 04H); // jnb L
1340
            Rex(reg2, reg1);
1341
            OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opEXCL), 8 * (reg1 MOD 8) + reg2 MOD 8); // bts/btr qword[reg2], reg1
1342
            // L:
1343
            drop;
1344
            drop
1345
 
1346
        |CODE.opINCLC, CODE.opEXCLC:
1347
            UnOp(reg1);
1348
            Rex(reg1, 0);
1349
            OutByte2(0FH, 0BAH);  // bts/btr qword[reg1], param2
1350
            OutByte2(28H + 8 * ORD(cmd.opcode = CODE.opEXCLC) + reg1 MOD 8, param2);
1351
            drop
1352
 
1353
        |CODE.opEQS .. CODE.opGES:
1354
            PushAll(4);
1355
            pushc(cmd.opcode - CODE.opEQS);
1356
            CallRTL(CODE._strcmp);
1357
            GetRegA
1358
 
1359
        |CODE.opEQS2 .. CODE.opGES2:
1360
            PushAll(4);
1361
            pushc(cmd.opcode - CODE.opEQS2);
1362
            CallRTL(CODE._strcmp2);
1363
            GetRegA
1364
 
1365
        |CODE.opEQSW .. CODE.opGESW:
1366
            PushAll(4);
1367
            pushc(cmd.opcode - CODE.opEQSW);
1368
            CallRTL(CODE._strcmpw);
1369
            GetRegA
1370
 
1371
        |CODE.opEQSW2 .. CODE.opGESW2:
1372
            PushAll(4);
1373
            pushc(cmd.opcode - CODE.opEQSW2);
1374
            CallRTL(CODE._strcmpw2);
1375
            GetRegA
1376
 
1377
        |CODE.opINC1, CODE.opDEC1:
1378
            UnOp(reg1);
1379
            Rex(reg1, 0);
1380
            OutByte2(0FFH, reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opDEC1));
1381
            drop
1382
 
1383
        |CODE.opCONST:
1384
            reg1 := REG.GetAnyReg(R);
1385
            movrc(reg1, param2)
1386
 
1387
        |CODE.opGT, CODE.opGE, CODE.opLT,
1388
         CODE.opLE, CODE.opEQ, CODE.opNE:
1389
            BinOp(reg1, reg2);
1390
            cmprr(reg1, reg2);
1391
            drop;
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.opGTR, CODE.opLTL, CODE.opGER, CODE.opLEL,
1412
         CODE.opLER, CODE.opGEL, CODE.opLTR, CODE.opGTL,
1413
         CODE.opEQR, CODE.opEQL, CODE.opNER, CODE.opNEL:
1414
            UnOp(reg1);
1415
            IF param2 = 0 THEN
1416
                test(reg1)
1417
            ELSE
1418
                cmprc(reg1, param2)
1419
            END;
1420
            drop;
1421
            cc := X86.cond(cmd.opcode);
1422
 
1423
            IF cmd.next(COMMAND).opcode = CODE.opJE THEN
1424
                label := cmd.next(COMMAND).param1;
1425
                jcc(cc, label);
1426
                cmd := cmd.next(COMMAND)
1427
 
1428
            ELSIF cmd.next(COMMAND).opcode = CODE.opJNE THEN
1429
                label := cmd.next(COMMAND).param1;
1430
                jcc(X86.inv1(cc), label);
1431
                cmd := cmd.next(COMMAND)
1432
 
1433
            ELSE
1434
                reg1 := REG.GetAnyReg(R);
1435
                setcc(cc + 16, reg1);
1436
                andrc(reg1, 1)
1437
            END
1438
 
1439
        |CODE.opCODE:
1440
            OutByte(param2)
1441
 
1442
        |CODE.opPUSHIP:
1443
            reg1 := REG.GetAnyReg(R);
1444
            lea(reg1, param2, sIMP);
1445
            movrm(reg1, reg1, 0)
1446
 
1447
        |CODE.opPARAM:
1448
            n := param2;
1449
            IF n = 1 THEN
1450
                UnOp(reg1);
1451
                push(reg1);
1452
                drop
1453
            ELSE
1454
                ASSERT(R.top + 1 <= n);
1455
                PushAll(n)
7667 akron1 1456
            END
1457
 
1458
        |CODE.opACC:
1459
            IF (R.top # 0) OR (R.stk[0] # rax) THEN
1460
                PushAll(0);
1461
                GetRegA;
1462
                pop(rax);
1463
                DEC(R.pushed)
7597 akron1 1464
            END
1465
 
1466
        |CODE.opJNZ:
1467
            UnOp(reg1);
1468
            test(reg1);
1469
            jcc(jne, param1)
1470
 
1471
        |CODE.opJZ:
1472
            UnOp(reg1);
1473
            test(reg1);
1474
            jcc(je, param1)
1475
 
1476
        |CODE.opJE:
1477
            UnOp(reg1);
1478
            test(reg1);
1479
            jcc(jne, param1);
1480
            drop
1481
 
1482
        |CODE.opJNE:
1483
            UnOp(reg1);
1484
            test(reg1);
1485
            jcc(je, param1);
1486
            drop
1487
 
1488
        |CODE.opIN:
1489
            label := NewLabel();
1490
            L := NewLabel();
1491
            BinOp(reg1, reg2);
1492
            cmprc(reg1, 64);
1493
            jcc(jb, L);
1494
            xor(reg1, reg1);
1495
            jmp(label);
1496
            X86.SetLabel(L);
1497
            Rex(reg2, reg1);
1498
            OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
1499
            setcc(setc, reg1);
1500
            andrc(reg1, 1);
1501
            X86.SetLabel(label);
1502
            drop
1503
 
1504
        |CODE.opINR:
1505
            label := NewLabel();
1506
            L := NewLabel();
1507
            UnOp(reg1);
1508
            reg2 := REG.GetAnyReg(R);
1509
            cmprc(reg1, 64);
1510
            jcc(jb, L);
1511
            xor(reg1, reg1);
1512
            jmp(label);
1513
            X86.SetLabel(L);
1514
            movrc(reg2, param2);
1515
            Rex(reg2, reg1);
1516
            OutByte3(0FH, 0A3H, 0C0H + 8 * (reg1 MOD 8) + reg2 MOD 8); // bt reg2, reg1
1517
            setcc(setc, reg1);
1518
            andrc(reg1, 1);
1519
            X86.SetLabel(label);
1520
            drop
1521
 
1522
        |CODE.opINL:
1523
            UnOp(reg1);
1524
            Rex(reg1, 0);
1525
            OutByte2(0FH, 0BAH);  // bt reg1, param2
1526
            OutByte2(0E0H + reg1 MOD 8, param2);
1527
            setcc(setc, reg1);
1528
            andrc(reg1, 1)
1529
 
1530
        |CODE.opNOT:
1531
            UnOp(reg1);
1532
            test(reg1);
1533
            setcc(sete, reg1);
1534
            andrc(reg1, 1)
1535
 
1536
        |CODE.opORD:
1537
            UnOp(reg1);
1538
            test(reg1);
1539
            setcc(setne, reg1);
1540
            andrc(reg1, 1)
1541
 
1542
        |CODE.opABS:
1543
            UnOp(reg1);
1544
            test(reg1);
1545
            OutByte2(7DH, 03H); // jge L
1546
            neg(reg1)
1547
            // L:
1548
 
1549
        |CODE.opEQB, CODE.opNEB:
1550
            BinOp(reg1, reg2);
1551
            drop;
1552
            drop;
1553
 
1554
            test(reg1);
1555
            OutByte2(74H, 07H); // je L1
1556
            movrc(reg1, 1);
1557
            // L1:
1558
            test(reg2);
1559
            OutByte2(74H, 07H); // je L2
1560
            movrc(reg2, 1);
1561
            // L2:
1562
            cmprr(reg1, reg2);
1563
            reg1 := REG.GetAnyReg(R);
1564
            IF cmd.opcode = CODE.opEQB THEN
1565
                setcc(sete, reg1)
1566
            ELSE
1567
                setcc(setne, reg1)
1568
            END;
1569
            andrc(reg1, 1)
1570
 
1571
        |CODE.opMULSC:
1572
            UnOp(reg1);
1573
            andrc(reg1, param2)
1574
 
1575
        |CODE.opDIVSC, CODE.opADDSL, CODE.opADDSR:
1576
            UnOp(reg1);
1577
            Rex(reg1, 0);
1578
            OutByte2(81H + short(param2), 0C8H + 28H * ORD(cmd.opcode = CODE.opDIVSC) + reg1 MOD 8); // or/xor reg1, param2
1579
            OutIntByte(param2)
1580
 
1581
        |CODE.opSUBSL:
1582
            UnOp(reg1);
1583
            not(reg1);
1584
            andrc(reg1, param2)
1585
 
1586
        |CODE.opSUBSR:
1587
            UnOp(reg1);
1588
            andrc(reg1, ORD(-BITS(param2)))
1589
 
1590
        |CODE.opMULS:
1591
            BinOp(reg1, reg2);
1592
            and(reg1, reg2);
1593
            drop
1594
 
1595
        |CODE.opDIVS:
1596
            BinOp(reg1, reg2);
1597
            xor(reg1, reg2);
1598
            drop
1599
 
1600
        |CODE.opUMINS:
1601
            UnOp(reg1);
1602
            not(reg1)
1603
 
1604
        |CODE.opCOPY:
1605
            PushAll(2);
1606
            pushc(param2);
1607
            CallRTL(CODE._move2)
1608
 
1609
        |CODE.opMOVE:
1610
            PushAll(3);
1611
            CallRTL(CODE._move2)
1612
 
1613
        |CODE.opCOPYA:
1614
            PushAll(4);
1615
            pushc(param2);
1616
            CallRTL(CODE._arrcpy);
1617
            GetRegA
1618
 
1619
        |CODE.opCOPYS:
1620
            PushAll(4);
1621
            pushc(param2);
1622
            CallRTL(CODE._strcpy)
1623
 
1624
        |CODE.opCOPYS2:
1625
            PushAll(4);
1626
            pushc(param2);
1627
            CallRTL(CODE._strcpy2)
1628
 
1629
        |CODE.opROT:
1630
            PushAll(0);
1631
            push(rsp);
1632
            pushc(param2);
1633
            CallRTL(CODE._rot)
1634
 
1635
        |CODE.opNEW:
1636
            PushAll(1);
1637
            n := param2 + 16;
1638
            ASSERT(MACHINE.Align(n, 64));
1639
            pushc(n);
1640
            pushc(param1);
1641
            CallRTL(CODE._new)
1642
 
1643
        |CODE.opDISP:
1644
            PushAll(1);
1645
            CallRTL(CODE._dispose)
1646
 
1647
        |CODE.opPUSHT:
1648
            UnOp(reg1);
1649
            reg2 := REG.GetAnyReg(R);
1650
            movrm(reg2, reg1, -8)
1651
 
1652
        |CODE.opISREC:
1653
            PushAll(2);
1654
            pushc(param2);
1655
            CallRTL(CODE._isrec);
1656
            GetRegA
1657
 
1658
        |CODE.opIS:
1659
            PushAll(1);
1660
            pushc(param2);
1661
            CallRTL(CODE._is);
1662
            GetRegA
1663
 
1664
        |CODE.opTYPEGR:
1665
            PushAll(1);
1666
            pushc(param2);
1667
            CallRTL(CODE._guardrec);
1668
            GetRegA
1669
 
1670
        |CODE.opTYPEGP:
1671
            UnOp(reg1);
1672
            PushAll(0);
1673
            push(reg1);
1674
            pushc(param2);
1675
            CallRTL(CODE._guard);
1676
            GetRegA
1677
 
1678
        |CODE.opTYPEGD:
1679
            UnOp(reg1);
1680
            PushAll(0);
1681
            pushm(reg1, -8);
1682
            pushc(param2);
1683
            CallRTL(CODE._guardrec);
1684
            GetRegA
1685
 
1686
        |CODE.opCASET:
1687
            push(r10);
1688
            push(r10);
1689
            pushc(param2);
1690
            CallRTL(CODE._guardrec);
1691
            pop(r10);
1692
            test(rax);
1693
            jcc(jne, param1)
1694
 
1695
        |CODE.opSAVEP:
1696
            UnOp(reg1);
1697
            reg2 := REG.GetAnyReg(R);
1698
            lea(reg2, param2, sCODE);
1699
            movmr(reg1, 0, reg2);
1700
            drop;
1701
            drop
1702
 
1703
        |CODE.opPUSHP:
1704
            reg1 := REG.GetAnyReg(R);
1705
            lea(reg1, param2, sCODE)
1706
 
1707
        |CODE.opINC, CODE.opDEC:
1708
            BinOp(reg1, reg2);
1709
            // add/sub qword[reg2], reg1
1710
            Rex(reg2, reg1);
1711
            OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDEC), reg2 MOD 8 + (reg1 MOD 8) * 8);
1712
            drop;
1713
            drop
1714
 
1715
        |CODE.opINCC, CODE.opDECC:
1716
            UnOp(reg1);
1717
            IF isLong(param2) THEN
1718
                reg2 := REG.GetAnyReg(R);
1719
                movrc(reg2, param2);
1720
                // add/sub qword[reg1], reg2
1721
                Rex(reg1, reg2);
1722
                OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opDECC), reg1 MOD 8 + (reg2 MOD 8) * 8);
1723
                drop
1724
            ELSE
1725
                // add/sub qword[reg1], param2
1726
                Rex(reg1, 0);
1727
                OutByte2(81H + short(param2), 28H * ORD(cmd.opcode = CODE.opDECC) + reg1 MOD 8);
1728
                OutIntByte(param2)
1729
            END;
1730
            drop
1731
 
1732
        |CODE.opDROP:
1733
            UnOp(reg1);
1734
            drop
1735
 
1736
        |CODE.opSAVE, CODE.opSAVE64:
1737
            BinOp(reg2, reg1);
1738
            movmr(reg1, 0, reg2);
1739
            drop;
1740
            drop
1741
 
1742
        |CODE.opSAVE8:
1743
            BinOp(reg2, reg1);
1744
            movmr8(reg1, 0, reg2);
1745
            drop;
1746
            drop
1747
 
1748
        |CODE.opSAVE16:
1749
            BinOp(reg2, reg1);
1750
            movmr16(reg1, 0, reg2);
1751
            drop;
1752
            drop
1753
 
1754
        |CODE.opSAVE32:
1755
            BinOp(reg2, reg1);
1756
            movmr32(reg1, 0, reg2);
1757
            drop;
1758
            drop
1759
 
1760
        |CODE.opMIN:
1761
            BinOp(reg1, reg2);
1762
            cmprr(reg1, reg2);
1763
            OutByte2(7EH, 3); // jle L
1764
            mov(reg1, reg2);
1765
            // L:
1766
            drop
1767
 
1768
        |CODE.opMAX:
1769
            BinOp(reg1, reg2);
1770
            cmprr(reg1, reg2);
1771
            OutByte2(7DH, 3);  // jge L
1772
            mov(reg1, reg2);
1773
            // L:
1774
            drop
1775
 
1776
        |CODE.opMINC:
1777
            UnOp(reg1);
1778
            cmprc(reg1, param2);
1779
            label := NewLabel();
1780
            jcc(jle, label);
1781
            movrc(reg1, param2);
1782
            X86.SetLabel(label)
1783
 
1784
        |CODE.opMAXC:
1785
            UnOp(reg1);
1786
            cmprc(reg1, param2);
1787
            label := NewLabel();
1788
            jcc(jge, label);
1789
            movrc(reg1, param2);
1790
            X86.SetLabel(label)
1791
 
1792
        |CODE.opSBOOL:
1793
            BinOp(reg2, reg1);
1794
            test(reg2);
1795
            setcc(setne, reg2);
1796
            movmr8(reg1, 0, reg2);
1797
            drop;
1798
            drop
1799
 
1800
        |CODE.opSBOOLC:
1801
            UnOp(reg1);
1802
            IF reg1 >= 8 THEN
1803
                OutByte(41H)
1804
            END;
1805
            OutByte3(0C6H, reg1 MOD 8, ORD(param2 # 0));
1806
            drop
1807
 
1808
        |CODE.opODD:
1809
            UnOp(reg1);
1810
            andrc(reg1, 1)
1811
 
1812
        |CODE.opUMINUS:
1813
            UnOp(reg1);
1814
            neg(reg1)
1815
 
1816
        |CODE.opADD:
1817
            BinOp(reg1, reg2);
1818
            add(reg1, reg2);
1819
            drop
1820
 
1821
        |CODE.opSUB:
1822
            BinOp(reg1, reg2);
1823
            sub(reg1, reg2);
1824
            drop
1825
 
1826
        |CODE.opSUBR, CODE.opSUBL:
1827
            UnOp(reg1);
1828
            n := param2;
1829
            IF n = 1 THEN
1830
                decr(reg1)
1831
            ELSIF n = -1 THEN
1832
                incr(reg1)
1833
            ELSIF n # 0 THEN
1834
                subrc(reg1, n)
1835
            END;
1836
            IF cmd.opcode = CODE.opSUBL THEN
1837
                neg(reg1)
1838
            END
1839
 
1840
        |CODE.opADDL, CODE.opADDR:
1841
            IF param2 # 0 THEN
1842
                UnOp(reg1);
1843
                IF param2 = 1 THEN
1844
                    incr(reg1)
1845
                ELSIF param2 = -1 THEN
1846
                    decr(reg1)
1847
                ELSE
1848
                    addrc(reg1, param2)
1849
                END
1850
            END
1851
 
1852
        |CODE.opDIV:
1853
            PushAll(2);
1854
            CallRTL(CODE._div);
1855
            GetRegA
1856
 
1857
        |CODE.opDIVR:
1858
            a := param2;
1859
            IF a > 1 THEN
1860
                n := X86.log2(a)
1861
            ELSIF a < -1 THEN
1862
                n := X86.log2(-a)
1863
            ELSE
1864
                n := -1
1865
            END;
1866
 
1867
            IF a = 1 THEN
1868
 
1869
            ELSIF a = -1 THEN
1870
                UnOp(reg1);
1871
                neg(reg1)
1872
            ELSE
1873
                IF n > 0 THEN
1874
                    UnOp(reg1);
1875
 
1876
                    IF a < 0 THEN
1877
                        reg2 := REG.GetAnyReg(R);
1878
                        mov(reg2, reg1);
1879
                        shiftrc(sar, reg1, n);
1880
                        sub(reg1, reg2);
1881
                        drop
1882
                    ELSE
1883
                        shiftrc(sar, reg1, n)
1884
                    END
1885
 
1886
                ELSE
1887
                    PushAll(1);
1888
                    pushc(param2);
1889
                    CallRTL(CODE._div);
1890
                    GetRegA
1891
                END
1892
            END
1893
 
1894
        |CODE.opDIVL:
1895
            PushAll(1);
1896
            pushc(param2);
1897
            CallRTL(CODE._div2);
1898
            GetRegA
1899
 
1900
        |CODE.opMOD:
1901
            PushAll(2);
1902
            CallRTL(CODE._mod);
1903
            GetRegA
1904
 
1905
        |CODE.opMODR:
1906
            a := param2;
1907
            IF a > 1 THEN
1908
                n := X86.log2(a)
1909
            ELSIF a < -1 THEN
1910
                n := X86.log2(-a)
1911
            ELSE
1912
                n := -1
1913
            END;
1914
 
1915
            IF ABS(a) = 1 THEN
1916
                UnOp(reg1);
1917
                xor(reg1, reg1)
1918
            ELSE
1919
                IF n > 0 THEN
1920
                    UnOp(reg1);
1921
                    andrc(reg1, ABS(a) - 1);
1922
 
1923
                    IF a < 0 THEN
1924
                        test(reg1);
1925
                        label := NewLabel();
1926
                        jcc(je, label);
1927
                        addrc(reg1, a);
1928
                        X86.SetLabel(label)
1929
                    END
1930
 
1931
                ELSE
1932
                    PushAll(1);
1933
                    pushc(param2);
1934
                    CallRTL(CODE._mod);
1935
                    GetRegA
1936
                END
1937
            END
1938
 
1939
        |CODE.opMODL:
1940
            PushAll(1);
1941
            pushc(param2);
1942
            CallRTL(CODE._mod2);
1943
            GetRegA
1944
 
1945
        |CODE.opMUL:
1946
            BinOp(reg1, reg2);
1947
            oprr2(0FH, 0AFH, reg2, reg1); // imul reg1, reg2
1948
            drop
1949
 
1950
        |CODE.opMULC:
1951
            UnOp(reg1);
1952
 
1953
            a := param2;
1954
            IF a > 1 THEN
1955
                n := X86.log2(a)
1956
            ELSIF a < -1 THEN
1957
                n := X86.log2(-a)
1958
            ELSE
1959
                n := -1
1960
            END;
1961
 
1962
            IF a = 1 THEN
1963
 
1964
            ELSIF a = -1 THEN
1965
                neg(reg1)
1966
            ELSIF a = 0 THEN
1967
                xor(reg1, reg1)
1968
            ELSE
1969
                IF n > 0 THEN
1970
                    IF a < 0 THEN
1971
                        neg(reg1)
1972
                    END;
1973
                    shiftrc(shl, reg1, n)
1974
                ELSE
1975
                    // imul reg1, a
1976
                    Rex(reg1, reg1);
1977
                    OutByte2(69H + short(a), 0C0H + (reg1 MOD 8) * 9);
1978
                    OutIntByte(a)
1979
                END
1980
            END
1981
 
1982
        |CODE.opADDS:
1983
            BinOp(reg1, reg2);
1984
            or(reg1, reg2);
1985
            drop
1986
 
1987
        |CODE.opSUBS:
1988
            BinOp(reg1, reg2);
1989
            not(reg2);
1990
            and(reg1, reg2);
1991
            drop
1992
 
1993
        |CODE.opNOP:
1994
 
1995
        |CODE.opSWITCH:
1996
            UnOp(reg1);
1997
            IF param2 = 0 THEN
1998
                reg2 := rax
1999
            ELSE
2000
                reg2 := r10
2001
            END;
2002
            IF reg1 # reg2 THEN
2003
                ASSERT(REG.GetReg(R, reg2));
2004
                ASSERT(REG.Exchange(R, reg1, reg2));
2005
                drop
2006
            END;
2007
            drop
2008
 
2009
        |CODE.opENDSW:
2010
 
2011
        |CODE.opCASEL:
2012
            cmprc(rax, param1);
2013
            jcc(jl, param2)
2014
 
2015
        |CODE.opCASER:
2016
            cmprc(rax, param1);
2017
            jcc(jg, param2)
2018
 
2019
        |CODE.opCASELR:
2020
            cmprc(rax, param1);
2021
            jcc(jl, param2);
2022
            jcc(jg, cmd.param3)
2023
 
2024
        |CODE.opASR, CODE.opROR, CODE.opLSL, CODE.opLSR:
2025
            BinOp(reg1, reg2);
2026
            xchg(reg2, rcx);
2027
            Rex(reg1, 0);
2028
            OutByte(0D3H);
2029
            X86.shift(cmd.opcode, reg1 MOD 8); // shift reg1, cl
2030
            xchg(reg2, rcx);
2031
            drop
2032
 
2033
        |CODE.opASR1, CODE.opROR1, CODE.opLSL1, CODE.opLSR1:
2034
            reg1 := REG.GetAnyReg(R);
2035
            movrc(reg1, param2);
2036
            BinOp(reg1, reg2);
2037
            xchg(reg1, rcx);
2038
            Rex(reg2, 0);
2039
            OutByte(0D3H);
2040
            X86.shift(cmd.opcode, reg2 MOD 8); // shift reg2, cl
2041
            xchg(reg1, rcx);
2042
            drop;
2043
            drop;
2044
            ASSERT(REG.GetReg(R, reg2))
2045
 
2046
        |CODE.opASR2, CODE.opROR2, CODE.opLSL2, CODE.opLSR2:
2047
            UnOp(reg1);
2048
            shiftrc(cmd.opcode, reg1, ORD(BITS(param2) * {0..5}))
2049
 
2050
        |CODE.opGET:
2051
            BinOp(reg1, reg2);
2052
            drop;
2053
            drop;
2054
            _movrm(reg1, reg1, 0, param2 * 8, FALSE);
2055
            _movrm(reg1, reg2, 0, param2 * 8, TRUE)
2056
 
2057
        |CODE.opCHKBYTE:
2058
            BinOp(reg1, reg2);
2059
            cmprc(reg1, 256);
2060
            jcc(jb, param1)
2061
 
2062
        |CODE.opCHKIDX:
2063
            UnOp(reg1);
2064
            cmprc(reg1, param2);
2065
            jcc(jb, param1)
2066
 
2067
        |CODE.opCHKIDX2:
2068
            BinOp(reg1, reg2);
2069
            IF param2 # -1 THEN
2070
                cmprr(reg2, reg1);
2071
                mov(reg1, reg2);
2072
                drop;
2073
                jcc(jb, param1)
2074
            ELSE
2075
                INCL(R.regs, reg1);
2076
                DEC(R.top);
2077
                R.stk[R.top] := reg2
2078
            END
2079
 
2080
        |CODE.opLENGTH:
2081
            PushAll(2);
2082
            CallRTL(CODE._length);
2083
            GetRegA
2084
 
2085
        |CODE.opLENGTHW:
2086
            PushAll(2);
2087
            CallRTL(CODE._lengthw);
2088
            GetRegA
2089
 
2090
        |CODE.opLEN:
2091
            n := param2;
2092
            UnOp(reg1);
2093
            drop;
2094
            EXCL(R.regs, reg1);
2095
 
2096
            WHILE n > 0 DO
2097
                UnOp(reg2);
2098
                drop;
2099
                DEC(n)
2100
            END;
2101
 
2102
            INCL(R.regs, reg1);
2103
            ASSERT(REG.GetReg(R, reg1))
2104
 
2105
        |CODE.opCHR:
2106
            UnOp(reg1);
2107
            andrc(reg1, 255)
2108
 
2109
        |CODE.opWCHR:
2110
            UnOp(reg1);
2111
            andrc(reg1, 65535)
2112
 
2113
        |CODE.opEQP, CODE.opNEP, CODE.opEQIP, CODE.opNEIP:
2114
            UnOp(reg1);
2115
            reg2 := REG.GetAnyReg(R);
2116
 
2117
            CASE cmd.opcode OF
2118
            |CODE.opEQP, CODE.opNEP:
2119
                lea(reg2, param1, sCODE)
2120
 
2121
            |CODE.opEQIP, CODE.opNEIP:
2122
                lea(reg2, param1, sIMP);
2123
                movrm(reg2, reg2, 0)
2124
            END;
2125
 
2126
            cmprr(reg1, reg2);
2127
            drop;
2128
            drop;
2129
            reg1 := REG.GetAnyReg(R);
2130
 
2131
            CASE cmd.opcode OF
2132
            |CODE.opEQP, CODE.opEQIP: setcc(sete,  reg1)
2133
            |CODE.opNEP, CODE.opNEIP: setcc(setne, reg1)
2134
            END;
2135
 
2136
            andrc(reg1, 1)
2137
 
2138
        |CODE.opINC1B, CODE.opDEC1B:
2139
            UnOp(reg1);
2140
            IF reg1 >= 8 THEN
2141
                OutByte(41H)
2142
            END;
2143
            OutByte2(0FEH, 8 * ORD(cmd.opcode = CODE.opDEC1B) + reg1 MOD 8); // inc/dec byte[reg1]
2144
            drop
2145
 
2146
        |CODE.opINCCB, CODE.opDECCB:
2147
            UnOp(reg1);
2148
            IF reg1 >= 8 THEN
2149
                OutByte(41H)
2150
            END;
2151
            OutByte3(80H, 28H * ORD(cmd.opcode = CODE.opDECCB) + reg1 MOD 8, param2 MOD 256); // add/sub byte[reg1], param2 MOD 256
2152
            drop
2153
 
2154
        |CODE.opINCB, CODE.opDECB:
2155
            BinOp(reg1, reg2);
2156
            IF (reg1 >= 8) OR (reg2 >= 8) THEN
2157
                OutByte(40H + reg2 DIV 8 + 4 * (reg1 DIV 8))
2158
            END;
2159
            OutByte2(28H * ORD(cmd.opcode = CODE.opDECB), reg2 MOD 8 + 8 * (reg1 MOD 8)); // add/sub byte[reg2], reg1_8
2160
            drop;
2161
            drop
2162
 
2163
        |CODE.opSAVEIP:
2164
            UnOp(reg1);
2165
            reg2 := REG.GetAnyReg(R);
2166
            lea(reg2, param2, sIMP);
2167
            movrm(reg2, reg2, 0);
2168
            push(reg2);
2169
            drop;
2170
            IF reg1 >= 8 THEN
2171
                OutByte(41H)
2172
            END;
2173
            OutByte2(8FH, reg1 MOD 8); // pop qword[reg1]
2174
            drop
2175
 
2176
        |CODE.opCLEANUP:
2177
            n := param2 * 8;
2178
            IF n # 0 THEN
2179
                addrc(rsp, n)
2180
            END
2181
 
2182
        |CODE.opPOPSP:
2183
            pop(rsp)
2184
 
2185
        |CODE.opLOADF:
2186
            UnOp(reg1);
2187
            INC(xmm);
2188
            movsdrm(xmm, reg1, 0);
2189
            drop
2190
 
2191
        |CODE.opPUSHF:
2192
            subrc(rsp, 8);
2193
            movsdmr(rsp, 0, xmm);
2194
            DEC(xmm)
2195
 
2196
        |CODE.opCONSTF:
2197
            float := cmd.float;
2198
            INC(xmm);
2199
            reg1 := REG.GetAnyReg(R);
2200
            lea(reg1, Numbers_Offs + Numbers_Count * 8, sDATA);
2201
            movsdrm(xmm, reg1, 0);
2202
            drop;
2203
            NewNumber(UTILS.splitf(float, a, b))
2204
 
2205
        |CODE.opSAVEF:
2206
            UnOp(reg1);
2207
            movsdmr(reg1, 0, xmm);
2208
            DEC(xmm);
2209
            drop
2210
 
2211
        |CODE.opADDF, CODE.opADDFI:
2212
            opxx(58H, xmm - 1, xmm);
2213
            DEC(xmm)
2214
 
2215
        |CODE.opSUBF:
2216
            opxx(5CH, xmm - 1, xmm);
2217
            DEC(xmm)
2218
 
2219
        |CODE.opSUBFI:
2220
            opxx(5CH, xmm, xmm - 1);
2221
            opxx(10H, xmm - 1, xmm);
2222
            DEC(xmm)
2223
 
2224
        |CODE.opMULF:
2225
            opxx(59H, xmm - 1, xmm);
2226
            DEC(xmm)
2227
 
2228
        |CODE.opDIVF:
2229
            opxx(5EH, xmm - 1, xmm);
2230
            DEC(xmm)
2231
 
2232
        |CODE.opDIVFI:
2233
            opxx(5EH, xmm, xmm - 1);
2234
            opxx(10H, xmm - 1, xmm);
2235
            DEC(xmm)
2236
 
2237
        |CODE.opUMINF:
2238
            reg1 := REG.GetAnyReg(R);
2239
            lea(reg1, Numbers_Offs, sDATA);
2240
            OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // xorpd xmm, xmmword[reg1]
2241
            OutByte2(57H, reg1 MOD 8 + (xmm MOD 8) * 8);
2242
            drop
2243
 
2244
        |CODE.opFABS:
2245
            reg1 := REG.GetAnyReg(R);
2246
            lea(reg1, Numbers_Offs + 16, sDATA);
2247
            OutByte3(66H, 40H + reg1 DIV 8 + (xmm DIV 8) * 4, 0FH); // andpd xmm, xmmword[reg1]
2248
            OutByte2(54H, reg1 MOD 8 + (xmm MOD 8) * 8);
2249
            drop
2250
 
2251
        |CODE.opFLT:
2252
            UnOp(reg1);
2253
            INC(xmm);
2254
            OutByte(0F2H); Rex(reg1, xmm); OutByte(0FH); // cvtsi2sd xmm, reg1
2255
            OutByte2(2AH, 0C0H + (xmm MOD 8) * 8 + reg1 MOD 8);
2256
            drop
2257
 
2258
        |CODE.opFLOOR:
2259
            reg1 := REG.GetAnyReg(R);
2260
            subrc(rsp, 8);
2261
            OutByte3(00FH, 0AEH, 05CH); OutByte2(024H, 004H); // stmxcsr dword[rsp+4];
2262
            OutByte2(00FH, 0AEH); OutByte2(01CH, 024H);       // stmxcsr dword[rsp];
2263
            OutByte3(081H, 024H, 024H); OutByte2(0FFH, 09FH); OutByte2(0FFH, 0FFH); // and dword[rsp],11111111111111111001111111111111b;
2264
            OutByte3(081H, 00CH, 024H); OutByte2(000H, 020H); OutByte2(000H, 000H); // or dword[rsp],00000000000000000010000000000000b;
2265
            OutByte2(00FH, 0AEH); OutByte2(014H, 024H); // ldmxcsr dword[rsp];
2266
            OutByte(0F2H); Rex(xmm, reg1); OutByte(0FH); // cvtsd2si reg1, xmm
2267
            OutByte2(2DH, 0C0H + xmm MOD 8 + (reg1 MOD 8) * 8);
2268
            OutByte3(00FH, 0AEH, 054H); OutByte2(024H, 004H); // ldmxcsr dword[rsp+4];
2269
            addrc(rsp, 8);
2270
            DEC(xmm)
2271
 
2272
        |CODE.opEQF .. CODE.opGEFI:
2273
            fcmp(cmd.opcode, xmm);
2274
            DEC(xmm, 2)
2275
 
2276
        |CODE.opINF:
2277
            INC(xmm);
2278
            reg1 := REG.GetAnyReg(R);
2279
            lea(reg1, Numbers_Offs + 32, sDATA);
2280
            movsdrm(xmm, reg1, 0);
2281
            drop
2282
 
2283
        |CODE.opPACK, CODE.opPACKC:
2284
            IF cmd.opcode = CODE.opPACK THEN
2285
                BinOp(reg1, reg2)
2286
            ELSE
2287
                UnOp(reg1);
2288
                reg2 := REG.GetAnyReg(R);
2289
                movrc(reg2, param2)
2290
            END;
2291
            push(reg1);
2292
            movrm(reg1, reg1, 0);
2293
            shiftrc(shl, reg1, 1);
2294
            shiftrc(shr, reg1, 53);
2295
            add(reg1, reg2);
2296
            andrc(reg1, ORD({0..10}));
2297
            shiftrc(shl, reg1, 52);
2298
            movrm(reg2, rsp, 0);
2299
            movrm(reg2, reg2, 0);
2300
 
2301
            push(reg1);
2302
            lea(reg1, Numbers_Offs + 40, sDATA); // {0..51, 63}
2303
            movrm(reg1, reg1, 0);
2304
            and(reg2, reg1);
2305
            pop(reg1);
2306
 
2307
            or(reg2, reg1);
2308
            pop(reg1);
2309
            movmr(reg1, 0, reg2);
2310
            drop;
2311
            drop
2312
 
2313
        |CODE.opUNPK, CODE.opLADR_UNPK:
2314
 
2315
            IF cmd.opcode = CODE.opLADR_UNPK THEN
2316
                n := param2 * 8;
2317
                UnOp(reg1);
2318
                reg2 := REG.GetVarReg(R, param2);
2319
                regVar := reg2 # -1;
2320
                IF ~regVar THEN
2321
                    reg2 := REG.GetAnyReg(R);
2322
                    Rex(0, reg2);
2323
                    OutByte2(8DH, 45H + long(n) + (reg2 MOD 8) * 8);  // lea reg2, qword[rbp+n]
2324
                    OutIntByte(n)
2325
                END
2326
            ELSE
2327
                BinOp(reg1, reg2);
2328
                regVar := FALSE
2329
            END;
2330
 
2331
            push(reg1);
2332
            movrm(reg1, reg1, 0);
2333
            shiftrc(shl, reg1, 1);
2334
            shiftrc(shr, reg1, 53);
2335
            subrc(reg1, 1023);
2336
 
2337
            IF regVar THEN
2338
                mov(reg2, reg1);
2339
                reg2 := REG.GetAnyReg(R)
2340
            ELSE
2341
                movmr(reg2, 0, reg1)
2342
            END;
2343
 
2344
            pop(reg2);
2345
            movrm(reg1, reg2, 0);
2346
 
2347
            push(reg2);
2348
            lea(reg2, Numbers_Offs + 48, sDATA); // {52..61}
2349
            movrm(reg2, reg2, 0);
2350
            or(reg1, reg2);
2351
            pop(reg2);
2352
 
2353
            Rex(reg1, 0);
2354
            OutByte2(0FH, 0BAH);
2355
            OutByte2(0F0H + reg1 MOD 8, 3EH); // btr reg1, 62
2356
            movmr(reg2, 0, reg1);
2357
            drop;
2358
            drop
2359
 
2360
        |CODE.opSADR_PARAM:
2361
            pushDA(stroffs + param2)
2362
 
2363
        |CODE.opVADR_PARAM:
2364
            pushm(rbp, param2 * 8)
2365
 
2366
        |CODE.opLOAD64_PARAM:
2367
            UnOp(reg1);
2368
            pushm(reg1, 0);
2369
            drop
2370
 
2371
        |CODE.opLLOAD64_PARAM:
2372
            reg1 := REG.GetVarReg(R, param2);
2373
            IF reg1 # -1 THEN
2374
                push(reg1)
2375
            ELSE
2376
                pushm(rbp, param2 * 8)
2377
            END
2378
 
2379
        |CODE.opGLOAD64_PARAM:
2380
            reg2 := REG.GetAnyReg(R);
2381
            lea(reg2, param2, sBSS);
2382
            movrm(reg2, reg2, 0);
2383
            push(reg2);
2384
            drop
2385
 
2386
        |CODE.opCONST_PARAM:
2387
            pushc(param2)
2388
 
2389
        |CODE.opGLOAD32_PARAM:
2390
            reg1 := REG.GetAnyReg(R);
2391
            xor(reg1, reg1);
2392
            lea(reg1, param2, sBSS);
2393
            movrm32(reg1, reg1, 0);
2394
            push(reg1);
2395
            drop
2396
 
2397
        |CODE.opLOAD32_PARAM:
2398
            UnOp(reg1);
2399
            movrm32(reg1, reg1, 0);
2400
            shiftrc(shl, reg1, 32);
2401
            shiftrc(shr, reg1, 32);
2402
            push(reg1);
2403
            drop
2404
 
2405
        |CODE.opLLOAD32_PARAM:
2406
            reg1 := REG.GetAnyReg(R);
2407
            xor(reg1, reg1);
2408
            reg2 := REG.GetVarReg(R, param2);
2409
            IF reg2 # -1 THEN
2410
                mov(reg1, reg2)
2411
            ELSE
2412
                movrm32(reg1, rbp, param2 * 8)
2413
            END;
2414
            push(reg1);
2415
            drop
2416
 
2417
        |CODE.opLADR_SAVEC:
2418
            n := param1 * 8;
2419
            reg1 := REG.GetVarReg(R, param1);
2420
            IF reg1 # -1 THEN
2421
                movrc(reg1, param2)
2422
            ELSE
2423
                IF isLong(param2) THEN
2424
                    reg2 := REG.GetAnyReg(R);
2425
                    movrc(reg2, param2);
2426
                    movmr(rbp, n, reg2);
2427
                    drop
2428
                ELSE
2429
                    OutByte3(48H, 0C7H, 45H + long(n)); // mov qword[rbp+n],param2
2430
                    OutIntByte(n);
2431
                    OutInt(param2)
2432
                END
2433
            END
2434
 
2435
        |CODE.opGADR_SAVEC:
2436
            IF isLong(param2) THEN
2437
                reg1 := REG.GetAnyReg(R);
2438
                movrc(reg1, param2);
2439
                reg2 := REG.GetAnyReg(R);
2440
                lea(reg2, param1, sBSS);
2441
                movmr(reg2, 0, reg1);
2442
                drop;
2443
                drop
2444
            ELSE
2445
                reg2 := REG.GetAnyReg(R);
2446
                lea(reg2, param1, sBSS);
2447
                Rex(reg2, 0);
2448
                OutByte2(0C7H, reg2 MOD 8); // mov qword[reg2], param2
2449
                OutInt(param2);
2450
                drop
2451
            END
2452
 
2453
        |CODE.opLADR_SAVE:
2454
            UnOp(reg1);
2455
            reg2 := REG.GetVarReg(R, param2);
2456
            IF reg2 # -1 THEN
2457
                mov(reg2, reg1)
2458
            ELSE
2459
                movmr(rbp, param2 * 8, reg1)
2460
            END;
2461
            drop
2462
 
2463
        |CODE.opLADR_INC1:
2464
            reg1 := REG.GetVarReg(R, param2);
2465
            IF reg1 # -1 THEN
2466
                incr(reg1)
2467
            ELSE
2468
                n := param2 * 8;
2469
                OutByte3(48H, 0FFH, 45H + long(n)); // inc qword[rbp+n]
2470
                OutIntByte(n)
2471
            END
2472
 
2473
        |CODE.opLADR_DEC1:
2474
            reg1 := REG.GetVarReg(R, param2);
2475
            IF reg1 # -1 THEN
2476
                decr(reg1)
2477
            ELSE
2478
                n := param2 * 8;
2479
                OutByte3(48H, 0FFH, 4DH + long(n)); // dec qword[rbp+n]
2480
                OutIntByte(n)
2481
            END
2482
 
2483
        |CODE.opLADR_INCC, CODE.opLADR_DECC:
2484
            reg1 := REG.GetVarReg(R, param1);
2485
            IF isLong(param2) THEN
2486
                reg2 := REG.GetAnyReg(R);
2487
                movrc(reg2, param2);
2488
                IF reg1 # -1 THEN
2489
                    IF cmd.opcode = CODE.opLADR_DECC THEN
2490
                        sub(reg1, reg2)
2491
                    ELSE
2492
                        add(reg1, reg2)
2493
                    END
2494
                ELSE
2495
                    n := param1 * 8;
2496
                    Rex(0, reg2);
2497
                    OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DECC), 45H + long(n) + (reg2 MOD 8) * 8);
2498
                    OutIntByte(n) // add/sub qword[rbp+n],reg2
2499
                END;
2500
                drop
2501
            ELSE
2502
                IF reg1 # -1 THEN
2503
                    IF cmd.opcode = CODE.opLADR_DECC THEN
2504
                        subrc(reg1, param2)
2505
                    ELSE
2506
                        addrc(reg1, param2)
2507
                    END
2508
                ELSE
2509
                    n := param1 * 8;
2510
                    OutByte3(48H, 81H + short(param2), 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECC));
2511
                    OutIntByte(n);
2512
                    OutIntByte(param2) // add/sub qword[rbp+n],param2
2513
                END
2514
            END
2515
 
2516
        |CODE.opLADR_INC1B, CODE.opLADR_DEC1B:
2517
            reg1 := REG.GetVarReg(R, param2);
2518
            IF reg1 # -1 THEN
2519
                IF cmd.opcode = CODE.opLADR_DEC1B THEN
2520
                    decr(reg1)
2521
                ELSE
2522
                    incr(reg1)
2523
                END;
2524
                andrc(reg1, 255)
2525
            ELSE
2526
                n := param2 * 8;
2527
                OutByte2(0FEH, 45H + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_DEC1B));
2528
                OutIntByte(n)  // inc/dec byte[rbp+n]
2529
            END
2530
 
2531
        |CODE.opLADR_INCCB, CODE.opLADR_DECCB:
2532
            reg1 := REG.GetVarReg(R, param1);
2533
            param2 := param2 MOD 256;
2534
            IF reg1 # -1 THEN
2535
                IF cmd.opcode = CODE.opLADR_DECCB THEN
2536
                    subrc(reg1, param2)
2537
                ELSE
2538
                    addrc(reg1, param2)
2539
                END;
2540
                andrc(reg1, 255)
2541
            ELSE
2542
                n := param1 * 8;
2543
                OutByte2(80H, 45H + long(n) + 28H * ORD(cmd.opcode = CODE.opLADR_DECCB));
2544
                OutIntByte(n);
2545
                OutByte(param2) // add/sub byte[rbp+n],param2
2546
            END
2547
 
2548
        |CODE.opLADR_INC, CODE.opLADR_DEC:
2549
            UnOp(reg1);
2550
            reg2 := REG.GetVarReg(R, param2);
2551
            IF reg2 # -1 THEN
2552
                IF cmd.opcode = CODE.opLADR_DEC THEN
2553
                    sub(reg2, reg1)
2554
                ELSE
2555
                    add(reg2, reg1)
2556
                END
2557
            ELSE
2558
                n := param2 * 8;
2559
                Rex(0, reg1);
2560
                OutByte2(01H + 28H * ORD(cmd.opcode = CODE.opLADR_DEC), 45H + long(n) + (reg1 MOD 8) * 8);
2561
                OutIntByte(n) // add/sub qword[rbp+n],reg1
2562
            END;
2563
            drop
2564
 
2565
        |CODE.opLADR_INCB, CODE.opLADR_DECB:
2566
            UnOp(reg1);
2567
            reg2 := REG.GetVarReg(R, param2);
2568
            IF reg2 # -1 THEN
2569
                IF cmd.opcode = CODE.opLADR_DECB THEN
2570
                    sub(reg2, reg1)
2571
                ELSE
2572
                    add(reg2, reg1)
2573
                END;
2574
                andrc(reg2, 255)
2575
            ELSE
2576
                n := param2 * 8;
2577
                IF reg1 >= 8 THEN
2578
                    OutByte(44H)
2579
                END;
2580
                OutByte2(28H * ORD(cmd.opcode = CODE.opLADR_DECB), 45H + long(n) + 8 * (reg1 MOD 8));
2581
                OutIntByte(n) // add/sub byte[rbp+n], reg1_8
2582
            END;
2583
            drop
2584
 
2585
        |CODE.opLADR_INCL, CODE.opLADR_EXCL:
2586
            UnOp(reg1);
2587
            cmprc(reg1, 64);
2588
            reg2 := REG.GetVarReg(R, param2);
2589
            IF reg2 # -1 THEN
2590
                OutByte2(73H, 4); // jnb L
2591
                oprr2(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), reg2, reg1) // bts/btr reg2, reg1
2592
            ELSE
2593
                n := param2 * 8;
2594
                OutByte2(73H, 5 + 3 * ORD(~isByte(n))); // jnb L
2595
                Rex(0, reg1);
2596
                OutByte3(0FH, 0ABH + 8 * ORD(cmd.opcode = CODE.opLADR_EXCL), 45H + long(n) + 8 * (reg1 MOD 8));
2597
                OutIntByte(n) // bts/btr qword[rbp+n], reg1
2598
            END;
2599
            // L:
2600
            drop
2601
 
2602
        |CODE.opLADR_INCLC, CODE.opLADR_EXCLC:
2603
            reg1 := REG.GetVarReg(R, param1);
2604
            IF reg1 # -1 THEN
2605
                Rex(reg1, 0);
2606
                OutByte3(0FH, 0BAH, 0E8H);  // bts/btr reg1, param2
2607
                OutByte2(reg1 MOD 8 + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC), param2)
2608
            ELSE
2609
                n := param1 * 8;
2610
                OutByte3(48H, 0FH, 0BAH);  // bts/btr qword[rbp+n], param2
2611
                OutByte(6DH + long(n) + 8 * ORD(cmd.opcode = CODE.opLADR_EXCLC));
2612
                OutIntByte(n);
2613
                OutByte(param2)
2614
            END
2615
 
2616
        |CODE.opLOOP, CODE.opENDLOOP:
2617
 
2618
        END;
2619
 
2620
        cmd := cmd.next(COMMAND)
2621
    END;
2622
 
2623
    ASSERT(R.pushed = 0);
2624
    ASSERT(R.top = -1);
2625
    ASSERT(xmm = -1)
2626
END translate;
2627
 
2628
 
2629
PROCEDURE prolog (code: CODE.CODES; modname: ARRAY OF CHAR; target, stack_size: INTEGER);
2630
VAR
2631
    ModName_Offs, entry: INTEGER;
2632
 
2633
BEGIN
2634
    ModName_Offs := CHL.Length(code.types) * 8 + CHL.Length(code.data);
2635
    Numbers_Offs := ModName_Offs + LENGTH(modname) + 1;
2636
    ASSERT(MACHINE.Align(Numbers_Offs, 16));
2637
 
2638
    entry := NewLabel();
2639
    X86.SetLabel(entry);
2640
 
2641
    IF target = mConst.Target_iDLL64 THEN
2642
        dllret := NewLabel();
2643
        push(r8);
2644
        push(rdx);
2645
        push(rcx);
2646
        CallRTL(CODE._dllentry);
2647
        test(rax);
2648
        jcc(je, dllret)
2649
    END;
2650
 
2651
    push(rsp);
2652
    lea(rax, entry, sCODE);
2653
    push(rax);
2654
    pushDA(0); //TYPES
2655
    pushc(CHL.Length(code.types));
2656
    pushDA(ModName_Offs); //MODNAME
2657
    CallRTL(CODE._init)
2658
END prolog;
2659
 
2660
 
2661
PROCEDURE epilog (code: CODE.CODES; modname: ARRAY OF CHAR; target: INTEGER);
2662
VAR
2663
    i, n: INTEGER;
2664
    number: Number;
2665
    exp: CODE.EXPORT_PROC;
2666
 
2667
 
2668
    PROCEDURE import (imp: LISTS.LIST);
2669
    VAR
2670
        lib:  CODE.IMPORT_LIB;
2671
        proc: CODE.IMPORT_PROC;
2672
 
2673
    BEGIN
2674
 
2675
        lib := imp.first(CODE.IMPORT_LIB);
2676
        WHILE lib # NIL DO
2677
            BIN.Import(prog, lib.name, 0);
2678
            proc := lib.procs.first(CODE.IMPORT_PROC);
2679
            WHILE proc # NIL DO
2680
                BIN.Import(prog, proc.name, proc.label);
2681
                proc := proc.next(CODE.IMPORT_PROC)
2682
            END;
2683
            lib := lib.next(CODE.IMPORT_LIB)
2684
        END
2685
 
2686
    END import;
2687
 
2688
 
2689
BEGIN
2690
    IF target = mConst.Target_iDLL64 THEN
2691
        X86.SetLabel(dllret);
2692
        OutByte(0C3H) // ret
2693
    ELSE
2694
        pushc(0);
2695
        CallRTL(CODE._exit)
2696
    END;
2697
 
2698
    X86.fixup;
2699
 
2700
    i := 0;
2701
    WHILE i < CHL.Length(code.types) DO
2702
        BIN.PutData64LE(prog, CHL.GetInt(code.types, i));
2703
        INC(i)
2704
    END;
2705
 
2706
    i := 0;
2707
    WHILE i < CHL.Length(code.data) DO
2708
        BIN.PutData(prog, CHL.GetByte(code.data, i));
2709
        INC(i)
2710
    END;
2711
 
2712
    BIN.PutDataStr(prog, modname);
2713
    BIN.PutData(prog, 0);
2714
    n := CHL.Length(prog.data);
2715
    ASSERT(MACHINE.Align(n, 16));
2716
    i := n - CHL.Length(prog.data);
2717
    WHILE i > 0 DO
2718
        BIN.PutData(prog, 0);
2719
        DEC(i)
2720
    END;
2721
    number := Numbers.first(Number);
2722
    FOR i := 0 TO Numbers_Count - 1 DO
2723
        BIN.PutData64LE(prog, number.value);
2724
        number := number.next(Number)
2725
    END;
2726
 
2727
    exp := code.export.first(CODE.EXPORT_PROC);
2728
    WHILE exp # NIL DO
2729
        BIN.Export(prog, exp.name, exp.label);
2730
        exp := exp.next(CODE.EXPORT_PROC)
2731
    END;
2732
 
2733
    import(code.import)
2734
END epilog;
2735
 
2736
 
2737
PROCEDURE rload (reg, offs, size: INTEGER);
2738
BEGIN
2739
    offs := offs * 8;
2740
    CASE size OF
2741
    |1: movzx(reg, rbp, offs, FALSE)
2742
    |2: movzx(reg, rbp, offs, TRUE)
2743
    |4: xor(reg, reg); movrm32(reg, rbp, offs)
2744
    |8: movrm(reg, rbp, offs)
2745
    END
2746
END rload;
2747
 
2748
 
2749
PROCEDURE rsave (reg, offs, size: INTEGER);
2750
BEGIN
2751
    offs := offs * 8;
2752
    CASE size OF
2753
    |1: movmr8(rbp, offs, reg)
2754
    |2: movmr16(rbp, offs, reg)
2755
    |4: movmr32(rbp, offs, reg)
2756
    |8: movmr(rbp, offs, reg)
2757
    END
2758
END rsave;
2759
 
2760
 
2761
PROCEDURE CodeGen* (code: CODE.CODES; outname: ARRAY OF CHAR; target, stack, base: INTEGER);
2762
VAR
2763
    path, modname, ext: PATHS.PATH;
2764
    n: INTEGER;
2765
 
2766
BEGIN
2767
    Win64RegPar[0] := rcx;
2768
    Win64RegPar[1] := rdx;
2769
    Win64RegPar[2] := r8;
2770
    Win64RegPar[3] := r9;
2771
 
2772
    SystemVRegPar[0] := rdi;
2773
    SystemVRegPar[1] := rsi;
2774
    SystemVRegPar[2] := rdx;
2775
    SystemVRegPar[3] := rcx;
2776
    SystemVRegPar[4] := r8;
2777
    SystemVRegPar[5] := r9;
2778
 
2779
    PATHS.split(outname, path, modname, ext);
2780
    S.append(modname, ext);
2781
 
2782
    R := REG.Create(push, pop, mov, xchg, rload, rsave, {rax, r10, r11}, {rcx, rdx, r8, r9});
2783
 
2784
    n := code.dmin - CHL.Length(code.data);
2785
    IF n > 0 THEN
2786
        INC(code.bss, n)
2787
    END;
2788
    code.bss := MAX(code.bss, 8);
2789
 
2790
    Numbers := LISTS.create(NIL);
2791
    Numbers_Count := 0;
2792
    NewNumber(ROR(1, 1));      (* 8000000000000000H *)
2793
    NewNumber(0);
2794
    NewNumber(ROR(-2, 1));     (* 7FFFFFFFFFFFFFFFH *)
2795
    NewNumber(-1);
2796
    NewNumber(ROR(7FFH, 12));  (* +Infinity *)
2797
    NewNumber(ORD(-BITS(LSR(ASR(ROR(1, 1), 10), 1))));  (* {0..51, 63} *)
2798
    NewNumber(LSR(ASR(ROR(1, 1), 9), 2));  (* {52..61} *)
2799
 
2800
    prog := BIN.create(code.lcount);
2801
    BIN.SetParams(prog, code.bss, stack, WCHR(1), WCHR(0));
2802
 
2803
    X86.SetProgram(prog);
2804
 
2805
    prolog(code, modname, target, stack);
2806
    translate(code.commands, CHL.Length(code.types) * 8);
2807
    epilog(code, modname, target);
2808
 
2809
    BIN.fixup(prog);
2810
    IF target IN {mConst.Target_iConsole64, mConst.Target_iGUI64, mConst.Target_iDLL64} THEN
2811
        PE32.write(prog, outname, base, target = mConst.Target_iConsole64, target = mConst.Target_iDLL64, TRUE)
2812
    ELSIF target = mConst.Target_iELF64 THEN
2813
        ELF.write(prog, outname, TRUE)
2814
    END
2815
END CodeGen;
2816
 
2817
 
2818
END AMD64.