Subversion Repositories Kolibri OS

Rev

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

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