/
ir-gas64.bas
7434 lines (6730 loc) · 225 KB
/
ir-gas64.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
''-------------
''ir-gas64.bas
''-------------
'' asm 64bit backend
'' By SARG
/' ================== information ===============================
Windows ABI
-----------
params : rcx,rdx,r8,r9 + xmm0 to xmm3
Space for these registers also reserved on the stack to store them at the beginning of proc.
However if the first arg is an integer number (not a float) it is put in rcx and if the second one is a float it is put in xmm0. But if the third
one is an integer, r8 (not rdx) is used. And so on. So only four registers (rNN or xmmN) are used. Other parameters are put on the stack.
ex : integer, float,integer, float -> rcx,xmm1,r8,xmm3
rbp,rbx,rdi,rsi,r12,r13,r14,r15 belong to calling proc, if used by called need to be saved by called
rcx,rdx,r8,r9,rax,r10,r11 belong to called proc, if used by calling need to be saved (before call)
Linux ABI
---------
params : rdi,rsi,rdx,rcx,r8,r9 + xmm0 to xmm7
Space for these registers also reserved on the stack to store them at the beginning of proc.
Differently from Windows ABI all the registers (rNN or xmmN) could be used for passing parameters. Other parameters are put on the stack.
rbx, r12 to r15 belong to calling proc, if used by called need to be saved by called
parameters + r10 r11 rax belong to called proc, if used by calling need to be saved (before call)
Red zone : an area (128 bytes= 16 regs * 8) reserved on the stack, seems not often used
data organisation ''todo complete that information
-----------------
IRVREGTYPE_ENUM
IR_VREGTYPE_IMM 0
IR_VREGTYPE_VAR 1 '' VAR - var access
<varname> ofs static --> [rip+ofs] / local --> ofs[rbp]
IR_VREGTYPE_IDX 2 '' IDX - local array indexing
ofs1 vidx=<var <varname>ofs2 local
<varname> ofs vidx=<reg local/static
ofs vidx=<reg
also several levels for vidx and could be VAR (local/global)
IR_VREGTYPE_PTR 3 '' PTR - derefs
ofs vidx=reg
IR_VREGTYPE_REG 4
IR_VREGTYPE_OFS 5 '' OFS - global symbol access
<varname> ofs static
WINDOWS stack organization
--------------------------
rbp+xx param x
rbp+56 param 6
rbp+48 param 5 if more than 4 parameters and up
rbp+40 param 4 also in registers (rcx or xmm)
rbp+32 param 3
rbp+24 param 2
rbp+16 param 1 calling --> rsp + x / called --> rbp + 16, 24,.. to 8+x*8
return addr (after call)
rbp old rbp
rbp-8 rbx 7 saved registers (space arbitrary reserved even not used) --> rbp -8 to -56
-16 rdi
-24 rsi
-32 r12
-40 r13
-48 r14
-56 r15
rbp-56-x --> local vars
param x space is reversed using argcountmax, even with variadic
.......
rsp+32 --> param 5 if more than 4 parameters and up
param 4 also in registers (rcx or xmm)
param 3
param 2
rsp --> param 1
0[rsp)=16[rbp]
Linux stack organization (Linux/BSD)
------------------------
rbp+32 param 3
rbp+24 param 2
rbp+16 FIRST param 1 on stack (no param in register) calling --> rsp + x / called --> rbp + 16, 24,.. to 8+x*8
return addr (after call)
rbp old rbp
rbp-8 rbx 5 saved registers (space arbitrary reserved even not used) --> rbp -8 to -40
-16 r12
-24 r13
-32 r14
-40 r15
if variadic register save area, only for parameters not defined
-152 rdi 0
-112 rsi 8
...
-104 r9 40
-176 xmm0 48
...
-48 xmm7 104
rbp-x saved param passed in register
rbp-y --> local vars
'/
#include once "fbint.bi"
#include once "flist.bi"
#include once "lex.bi"
#include once "ir-private.bi"
#include once "stabs.bi"
'' comment to not get basic data
'#define basicdata
#define KDOALL 0
#define KNOALL 1
#define KNOFREE 2
#define KNOOPTIM 3
#define asm_code(s,opt...) hWriteasm64(s,opt)
#macro cfi_asm_code(s, opt...)
if( env.clopt.unwindinfo = true ) then
hWriteasm64(s,opt)
end if
#endmacro
declare sub cfi_windows_asm_code(byval statement as string)
'' Define __GAS64_DEBUG__ if it wasn't explicitly disabled
'' by '-d DISABLE_GAS64_DEBUG' passed as compiler option when
'' compiling fbc itself (or in the makefile).
'' Defining __GAS64_DEBUG__ will enable debug information to
'' be written to the asm file. Disabling __GAS64_DEBUG__ but still
'' allowing __FB_DEBUG__ allows building a debug version of fbc but
'' not have asm files grow to very large sizes.
''
#ifndef DISABLE_GAS64_DEBUG
'' not disabled? OK turn on debugging information in asm
'' files by default if this is a debug version of fbc
#if __FB_DEBUG__ <> 0
#define __GAS64_DEBUG__
#endif
#endif
#ifdef __GAS64_DEBUG__
#define asm_info(s) hWriteasm64("# "+s)
#else
#define asm_info(s) rem
#ifndef typeDumpToStr
#define typeDumpToStr(a,b) " "+str(a)
#endif
#endif
#macro asm_error(s)
hWriteasm64("")
asm_info(String(len(s)+10,"*"))
asm_info("* ERROR "+s+" *")
asm_info(String(len(s)+10,"*"))
asm_code("FOUND AN ERROR : "+s)
hWriteasm64("")
#endmacro
#define NEWLINE2 NEWLINE+string( ctx.indent*3, 32 )
#define KUSE_MOV 0
#define KUSE_LEA 1
#define KUSE_JMP 2
#define KREGFREE -2 ''register not free
#define KREGRSVD -3 ''register reserved
#define KREGLOCK -4 ''register locked (used as parameter)
#define KREGUPPER 15 ''registers 0 to 15 / 16=rip /17=dummy reg to avoid crash
#define KNOTFOUND -1
#define KSIZEPROCTXT 4000000 ''initial size of proc_txt used for speed up text adding
'' used by ASM64_REGROOM.status (TODO: use a named enum for readability???)
#define KROOMFREE -1
#define KROOMMARKED -2
#define KROOMUSED -3
#macro MPUSH(strg)
pushnbstr+=1
pushstr(pushnbstr)=strg
asm_info("MPUSH="+str(pushnbstr)+" "+pushstr(pushnbstr))
#endmacro
enum KREG
KREG_RAX
KREG_RBX
KREG_RCX
KREG_RDX
KREG_RSI
KREG_RDI
KREG_RBP
KREG_RSP
KREG_R8
KREG_R9
KREG_R10
KREG_R11
KREG_R12
KREG_R13
KREG_R14
KREG_R15
KREG_RIP
''17 corresponding string * XXX to generate an error when assembling
KREG_XXX
end enum
''parameter type
enum
KPARAMR1
KPARAMX1
KPARAMRR
KPARAMRX
KPARAMXR
KPARAMXX
KPARAMSK0=10
KPARAMSK1
KPARAMSK2
KPARAMSK3
end enum
''offset for saving registers before a call
#define KRCX_OFST -24
#define KRDX_OFST -32
#define KRSI_OFST -40
#define KRDI_OFST -48
#define KR8_OFST -56
#define KR9_OFST -64
#define KR10_OFST -72
#define KR11_OFST -80
enum
'' every thing outside proc, global declarations
SECTION_HEAD
'' procedure bodies
SECTION_BODY
'' every thing outside proc, debugging meta data
SECTION_FOOT
'' for each procedure, will be add to the section_body
SECTION_PROLOG
'' instructions, etc between prolog and epilog .....
SECTION_PROC
SECTION_EPILOG
end enum
'' type for tracking the spilled registers
type ASM64_SAVEDREG
id as long '' unique id for debugging messages only
sdvreg as long '' the id of the real register spilled??? KREGFREE = FREE
sdoffset as long '' offset into the spilled registers for current stackframe
spilbranch1 as long '' depends ctx.labelbranch2 for tracking spilled registers in second branch???
end type
type ASM64_CONTEXT
'' current indentation used by hWriteam64()
indent as integer
'' current section to write to
section as integer
head_txt as string
body_txt as string
foot_txt as string
prolog_txt as string
proc_txt as string
epilog_txt as string
argcptmax as integer
arginteg as integer
argfloat as integer
ofs as integer
''stack necessary for each procedure,stkmax if structure passed byval
''stkspil value stack at beginning of procedures to check no overflow for spilling
''stkcopy stack pointer when copying byval parameter
stk as longint
stkmax as longint
stkspil as longint
stkcopy as longint
usedreg as long
''to save register and virtuel register to be used with jmp reg after a cmp where reg is unmarked
''happens when -exx is set check pointer not null --> cmp r11,0 / je LT_0001 / jmp [r11]
jmpreg as long
jmpvreg as long
jmppass as long
'ctors as string ''kept here if to be added
'dtors as string
ctorcount as integer
dtorcount as integer
roundfloat as boolean ''rounding float can use different ways
''preparing arguments (hdocall)
proccalling as Boolean
''for spilling registers
spillvregs as TFLIST '' ASM64_SPILLVREG
vreg_count as long '' required because TFLIST doesn't count allocated items
''to handle iif case
labelbranch2 as FBSYMBOL ptr
labeljump as FBSYMBOL ptr
''for variadic parameters
variadic as boolean
''target linux or win32
target as FB_COMPTARGET
systemv as boolean ' linux / BSD
''handling of vreg after a call
opereg as integer
opepass as integer
maxstack as integer
end type
type DBGCTX
typecnt as uinteger
lnum as integer
prevfilename as string
linefilename as string
proc as FBSYMBOL ptr
strnb as integer
strmax as integer
stabnb as integer
stabmax as integer
offst as longint
end type
union ustab
full as longint
type
offst as long
cod as short
desc as short
end type
end union
''for strings used in debugging data to avoid duplicate
type tdbgstr
offst as longint
txt as string
end type
type tdbgstab
stab as longint
value as string
end type
''=================== declares ==============================================
declare sub _emitdbg(byval op as integer,byval proc as FBSYMBOL ptr,byval lnum as Integer,ByVal filename as zstring Ptr = 0)
declare sub check_optim(byref code as string)
declare sub _emitconvert( byval v1 as IRVREG ptr, byval v2 as IRVREG ptr )
declare function hgetdatatype_asm64 (byval sym as FBSYMBOL ptr,byval arraydimensions as integer = 0) as string
declare sub hwriteasm64( byref ln as string,byval opt as integer=KDOALL)
declare sub _emitvariniend( byval sym as FBSYMBOL ptr )
declare sub _emitvarinipad( byval bytes as longint )
declare sub _emitvariniwstr(byval varlength as longint,byval literal as wstring ptr,byval litlength as longint)
declare sub _emitvariniscopebegin(byval sym as FBSYMBOL ptr,byval is_array as integer)
declare sub _emitvariniscopeend( )
declare sub _emitfbctinfbegin( )
declare sub _emitfbctinfend( )
declare sub _scopebegin( byval s as FBSYMBOL ptr )
declare sub _scopeend( byval s as FBSYMBOL ptr )
declare sub _emitspillregs( )
declare sub _emitload( byval v1 as IRVREG ptr )
declare sub _emitlabelnf(byval label as FBSYMBOL Ptr)
declare sub _emitscopebegin( byval s as FBSYMBOL ptr )
declare sub _emitscopeend( byval s as FBSYMBOL ptr )
declare sub _emitMacro( byval op as integer,byval v1 as IRVREG ptr, byval v2 as IRVREG ptr, byval vr as IRVREG ptr )
declare sub save_call(byref func as string,byval vr as IRVREG ptr,byval vrreg as integer)
declare function hGetMagicStructNumber( byval sym as FBSYMBOL ptr ) as integer
declare sub dbg_addstab(byref txt as string="",byval cod as ubyte,byval desc as short=0,byref value as string="0")
''===================== globals ===========================================
dim shared as DBGCTX ctxdbg
dim shared as long reghandle(KREGUPPER+2)
type ASM64_REGROOM
status as long '' KROOMFREE, KROOMMARKED, KROOMUSED
vreg as ASM64_SAVEDREG ptr '' pointer to the spilled vreg
end type
dim shared as ASM64_REGROOM regroom(KREGUPPER+2)
dim shared as ASM64_CONTEXT ctx
redim shared as tdbgstr dbgstr()
redim shared as tdbgstab dbgstab()
'' same order as FB_DATATYPE
'' Mapping dtype => stabs type tag (t*) as declared in the strings in the stabsTb()
dim shared remapTB(0 to FB_DATATYPES-1) as integer = _
{ _
7, _ '' void
16, _ '' boolean
2, _ '' byte
3, _ '' ubyte
4, _ '' char
5, _ '' short
6, _ '' ushort
6, _ '' wchar
9, _ '' int
10, _ '' uint
9, _ '' enum
1, _ '' long
8, _ '' ulong
9, _ '' longint
10, _ '' ulongint
11, _ '' single
12, _ '' double
13, _ '' string
14, _ '' fix-len string
17 _ '' va_list
}
dim shared stabsTb(0 to ...) as const zstring ptr = _
{ _
@"integer:t1=-1", _
@"void:t7=-11", _
@"byte:t2=-6", _
@"ubyte:t3=-5", _
@"char:t4=-2", _
@"short:t5=-3", _
@"ushort:t6=-7", _
@"uinteger:t8=-8", _
@"longint:t9=-31", _
@"ulongint:t10=-32", _
@"single:t11=-12", _
@"double:t12=-13", _
@"string:t13=s12data:*2,0,64;len:1,64,64;size:1,128,64;;", _
@"fixstr:t14=-2", _
@"pchar:t15=*4;", _ '' used for the data ptr in the string:t13 declaration only
@"boolean:t16=@s8;-16", _
@"va_list:t17=-11" _
}
dim shared as const zstring ptr regstrq(17)=>{@"rax",@"rbx",@"rcx",@"rdx",@"rsi",@"rdi",@"rbp",@"rsp",@"r8",@"r9",@"r10",@"r11",@"r12",@"r13",@"r14",@"r15",@"rip",@"* X_Q"}
dim shared as const zstring ptr regstrd(17)={@"eax",@"ebx",@"ecx",@"edx",@"esi",@"edi",@"ebp",@"esp",@"r8d",@"r9d",@"r10d",@"r11d",@"r12d",@"r13d",@"r14d",@"r15d",@"",@"* X_D"}
dim shared as const zstring ptr regstrw(17)={@"ax",@"bx",@"cx",@"dx",@"si",@"di",@"bp",@"sp",@"r8w",@"r9w",@"r10w",@"r11w",@"r12w",@"r13w",@"r14w",@"r15w",@"",@"* X_W"}
dim shared as const zstring ptr regstrb(17)={@"al",@"bl",@"cl",@"dl",@"sil",@"dil",@"bpl",@"spl",@"r8b",@"r9b",@"r10b",@"r11b",@"r12b",@"r13b",@"r14b",@"r15b",@"",@"* X_B"}
''priority order (can easily be changed)
dim shared as const byte reg_prio(0 to ...)={KREG_R11,KREG_R10,KREG_R8,KREG_R9,KREG_RDX,KREG_RCX,KREG_R12,KREG_R13,KREG_R14,KREG_R15,KREG_RBX,KREG_RDI,KREG_RSI}
''registers used for parameters + R10/R11 for saving
dim shared as long listreg(any)
'' ================== for optimization =========================================================
private sub check_optim(byref code as string)
dim as string part1,part2,instruc,newcode
static as string prevpart1,prevpart2,previnstruc
static as long prevwpos,flag
dim as long poschar1,poschar2,writepos
if len(code)=0 then
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV ''reinit statics
exit sub
end if
if flag=KUSE_JMP then
'asm_info("jmp found="+prevpart1)
if instr(code,prevpart1+":") then
mid(ctx.proc_txt,prevwpos)="#O9"
end if
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV ''reinit
exit sub
end if
select case left(code,3)
case "mov"
writepos=len(ctx.proc_txt)+1
poschar1=instr(code," ")
instruc=left(code,poschar1-1)
poschar2=instr(code,",")
if poschar2=0 then
''case movsb|w|d|q
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV
exit sub
End If
part1=trim(mid(code,poschar1+1,poschar2-poschar1-1))
poschar1=instr(code,"#")
if poschar1=0 then
poschar1=len(code) ''Add 1 as after removing 2
else
poschar1-=2
end if
part2=trim(Mid(code,poschar2+1,poschar1-poschar2))
''cancel mov regx, regx
if part1=part2 then
code="#O0"+code
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV
exit sub
end if
case "lea"
writepos=len(ctx.proc_txt)+1
poschar1=instr(code," ")
instruc=left(code,poschar1-1)
poschar2=instr(code,",")
part1=trim(mid(code,poschar1+1,poschar2-poschar1-1))
poschar1=instr(code,"#")
if poschar1=0 then
poschar1=len(code) ''Add 1 as after removing 2
else
poschar1-=2
end if
part2=trim(Mid(code,poschar2+1,poschar1-poschar2))
if instr(code," add ") then
prevpart1="":prevpart2=""
exit sub ''case where an add xxx is associated with lea see store for example
end if
flag=KUSE_LEA
prevpart1=part1
prevpart2=part2
prevwpos=writepos
exit sub
case "jmp"
writepos=len(ctx.proc_txt)+1
poschar1=instr(code," ")
instruc=left(code,poschar1-1)
poschar2=instr(code,",")
part1=trim(mid(code,poschar1+1,poschar2-poschar1-1))
poschar1=instr(code,"#")
if poschar1=0 then
poschar1=len(code) ''Add 1 as after removing 2
else
poschar1-=2
end if
part2=trim(Mid(code,poschar2+1,poschar1-poschar2))
if part1=prevpart1 then
''mov r11, rax --> #10mov r11, rax
''jmp r11 --> #10jmp r11
'' --> jmp rax
mid(ctx.proc_txt,prevwpos)="#10"
code="#10"+code+newline+string( ctx.indent*3, 32 )+"jmp "+prevpart2+" #Optim 10"
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV
exit sub
else
prevpart1=part1
flag=KUSE_JMP
prevwpos=writepos
exit sub
end if
case "cmp"
if len(prevpart1) then
if flag<>KUSE_LEA then
writepos=len(ctx.proc_txt)+1
poschar1=instr(code," ")
instruc=left(code,poschar1-1)
poschar2=instr(code,",")
part1=trim(mid(code,poschar1+1,poschar2-poschar1-1))
poschar1=instr(code,"#")
if poschar1=0 then
poschar1=len(code) ''Add 1 as after removing 2
else
poschar1-=2
end if
part2=trim(Mid(code,poschar2+1,poschar1-poschar2))
''mov r11, rax
''cmp r11,xx --> cmp rax, xx
''or
''mov r11, xx[rbp]
''cmp r10, r11 --> cmp r10, xx[rbp]
if part1[0]=asc("r") then
if part1=prevpart1 and prevpart2[0]=asc("r") then
mid(ctx.proc_txt,prevwpos)="#13"
code="#13"+code+newline+string( ctx.indent*3, 32 )+"cmp "+prevpart2+", "+part2+" #Optim 13"
elseif part2=prevpart1 and instr(prevpart2,"[") then
mid(ctx.proc_txt,prevwpos)="#14"
code="#14"+code+newline+string( ctx.indent*3, 32 )+"cmp "+part1+", "+prevpart2+" #Optim 14"
end if
end if
end if
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV ''reinit
end if
exit sub
case else
select case left(code,4)
case "adds","subs","muls","divs"
writepos=len(ctx.proc_txt)+1
poschar1=instr(code," ")
instruc=left(code,poschar1-1)
poschar2=instr(code,",")
part1=trim(mid(code,poschar1+1,poschar2-poschar1-1))
poschar1=instr(code,"#")
if poschar1=0 then
poschar1=len(code) ''Add 1 as after removing 2
else
poschar1-=2
end if
part2=trim(Mid(code,poschar2+1,poschar1-poschar2))
if prevpart1=part2 then
if instr(prevpart2,"[r") then
mid(ctx.proc_txt,prevwpos)="#15"
code="#15"+code+newline+string( ctx.indent*3, 32 )+instruc+" "+part1+", "+prevpart2+" #Optim 15"
end if
end if
end select
prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV ''reinit
exit sub
end select
''todo reactivate but exclude if dest not a register
if instruc="movsxd" then prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV :exit sub
if instruc="movsx" then prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV :exit sub
if instruc="movzx" then prevpart1="":prevpart2="":previnstruc="":flag=KUSE_MOV :exit sub
if flag=KUSE_LEA then
if instr(part1,"["+prevpart1+"]") then
''check register or immediate
if part2[0]=asc("r") Or part2[0]=asc("e") or (asc(Right(part2,1))>=48 and asc(right(part2,1))<=57) then
'asm_info("OPTIMIZATION 4 (lea)")
'asm_info("removed =lea "+prevpart1+", "+prevpart2)
mid(ctx.proc_txt,prevwpos)="#O4"
'asm_info("removed ="+mov+" "+part1+", "+part2)
newcode=instruc+" "+mid(part1,1,instr(part1,"[")-1)+prevpart2+", "+part2
'newcode="lea "+Mid(part1,1,instr(part1,"[")-1)+prevpart2+", "+part2
'asm_info("proposed="+newcode)
writepos=len(ctx.proc_txt)+len(code)+9
code="#O4"+code+newline+string( ctx.indent*3, 32 )+newcode+" #Optim 4"
end if
else
if part2=prevpart1 and part1[0]=asc("r") then
'asm_info("OPTIMIZATION 5 (lea)")
'asm_info("removed =lea "+prevpart1+", "+prevpart2)
mid(ctx.proc_txt,prevwpos)="#O5"
'asm_info("removed ="+mov+" "+part1+", "+part2)
'newcode=mov+" "+part1+", "+prevpart2
newcode="lea "+part1+", "+prevpart2
'asm_info("proposed="+newcode)
writepos=len(ctx.proc_txt)+len(code)+9
code="#O5"+code+newline+string( ctx.indent*3, 32 )+newcode+" #Optim 5"
else
if part1[0]=asc("r") andalso part2="["+prevpart1+"]" then
'asm_info("OPTIMIZATION 7 (lea)")
mid(ctx.proc_txt,prevwpos)="#O7"
newcode=instruc+" "+part1+", "+prevpart2
writepos=len(ctx.proc_txt)+len(code)+9
code="#O7"+code+newline+string( ctx.indent*3, 32 )+newcode+" #Optim 7"
else
prevpart1=part1
prevpart2=part2
previnstruc=instruc
prevwpos=writepos
flag=KUSE_MOV
exit sub
end if
end if
end if
prevpart1="":prevpart2=""
flag=KUSE_MOV
exit sub
end if
if part2=prevpart1 then
if part1=prevpart2 then
'asm_info("OPTIMIZATION 1")
code="#O1 "+code
else
if prevpart2="" then ''todo remove me after fixed
asm_error("prev/part empty "+"part1="+part1+" part2="+part2+" prevpart1="+prevpart1+" prevpart2="+prevpart2)
asm_info("code="+code)
asm_info("part1="+part1+" part2="+part2+" prevpart1="+prevpart1+" prevpart2="+prevpart2)
exit sub
end if
''direct simple register ?
if prevpart2[0]=asc("r") and part1[3]<>asc("d") and part1[0]<>asc("e") then
if instr(prevpart1,"[")<>0 then
'asm_info("OPTIMIZATION 2-1")
''skip comment
if part1[0]=asc("x") then
if instruc="movss" then
previnstruc="movd"
else
previnstruc="movq"
end if
end if
else
'asm_info("OPTIMIZATION 2-2")
mid(ctx.proc_txt,prevwpos)="#O2"
if instruc="movq" or instruc="movd" then
previnstruc=instruc
elseif instruc="movsx" then
previnstruc=instruc
end if
end if
writepos=len(ctx.proc_txt)+len(code)+9
code="#O2"+code+newline+string( ctx.indent*3, 32 )+previnstruc+" "+part1+", "+prevpart2+" #Optim 2"
part2=prevpart2
''xmm register ?
elseif prevpart2[0]=asc("x") then
if instr(prevpart1,"[")<>0 then
'asm_info("OPTIMIZATION 3-1")
''skip comment
if previnstruc="movss" then
instruc="movd"
else
instruc="movq"
end if
else
'asm_info("OPTIMIZATION 3-2")
mid(ctx.proc_txt,prevwpos)="#O3"
if previnstruc="movq" then
if instr(part2,"[") then
instruc="movsd"
else
instruc="movq"
end if
elseif previnstruc="movd" then
if part1[0]=asc("r") or part1[0]=asc("e") then
instruc="movd"
else
instruc="movss"
end if
else
asm_error("in check_optim 3-2 instruc unknown="+instruc)
end if
end if
writepos=len(ctx.proc_txt)+len(code)+9
code="#O3"+code+newline+string( ctx.indent*3, 32 )+instruc+" "+part1+", "+prevpart2+" #Optim 3"
part2=prevpart2
elseif ( part1[0]=asc("r") or part1[0]=asc("e") ) and prevpart1=part2 and instr(prevpart1,"[")=0 then
'asm_info("OPTIMIZATION 6")
mid(ctx.proc_txt,prevwpos)="#O6"
'asm_info("part1="+part1+" part2="+part2+" prevpart1="+prevpart1+" prevpart2="+prevpart2)
writepos=len(ctx.proc_txt)+len(code)+9
code="#O6"+code+newline+string( ctx.indent*3, 32 )+previnstruc+" "+part1+", "+prevpart2+" #Optim 6"
part2=prevpart2
elseif ( prevpart2[0]=asc("r") or prevpart2[0]=asc("e") ) and prevpart1=part2 then 'and instr(part1,"[")=0
'asm_info("OPTIMIZATION 16")
if instr(prevpart1,"[")=0 then
mid(ctx.proc_txt,prevwpos)="#16"
end if
'asm_info("part1="+part1+" part2="+part2+" prevpart1="+prevpart1+" prevpart2="+prevpart2)
if part1[0]=asc("x") then
if prevpart2[0]=asc("e") then '32bit -->xmmN
instruc="movd"
else
instruc="movq"
EndIf
End If
writepos=len(ctx.proc_txt)+len(code)+9
code="#16"+code+newline+string( ctx.indent*3, 32 )+instruc+" "+part1+", "+prevpart2+" #Optim 16"
part2=prevpart2
end if
end if
end if
prevpart1=part1
prevpart2=part2
previnstruc=instruc
prevwpos=writepos
end sub
private sub reg_freeable(byref lineasm as string)
dim as long regfound1,regfound2
dim as string instruc
instruc=left(Trim(lineasm),3)
if instruc="inc" orelse instruc="dec" orelse instruc="not" orelse instruc="neg" then
''inc r11 --> not freeable / inc qword ptr [r11] --> freeable
if instr(lineasm,"[")=0 then
''******** CHECK marked register for callee **********************************************************
exit sub
end if
else
if instr("mov lea cmp add sub imu idiv div shl shr sar and xor or call jmp push test cvt ",instruc)=0 then exit sub
end if
for ireg as long =1 To KREGUPPER
if reghandle(ireg)=KREGRSVD then continue for ''excluding rbp and rsp
regfound1=KNOTFOUND:regfound2=KNOTFOUND
if instr(lineasm,*regstrq(ireg)+",") then
regfound1=ireg
elseif instr(lineasm,*regstrd(ireg)+",") then
regfound1=ireg
elseif instr(lineasm,*regstrw(ireg)+",") then
regfound1=ireg
elseif instr(lineasm,*regstrb(ireg)+",") then
regfound1=ireg
end if
if regfound1<>KNOTFOUND then
if instruc="add" orelse instruc="sub" orelse instruc="imu" then
''already inuse and to be used later case 'add r11, xxx' not 'add qword ptr [r11], xxx'
continue for
elseif instruc="cmp" then
''already inuse but not to be used later except one case (at least) when null-pointer checking
ctx.jmpreg=regfound1 ''see their defines
ctx.jmpvreg=reghandle(regfound1)
ctx.jmppass=2
reghandle(regfound1)=KREGFREE
continue for
else
if instr(lineasm,*regstrq(ireg)+", "+*regstrq(ireg)) then
''case mov rzz, rzz in hdocall
reghandle(regfound1)=KREGFREE
exit sub
end if
end if
end if
if regfound1=KNOTFOUND then
if instr(lineasm,*regstrq(ireg)) then
regfound2=ireg
elseif instr(lineasm,*regstrd(ireg)) then
regfound2=ireg
elseif instr(lineasm,*regstrw(ireg)) then
regfound2=ireg
elseif instr(lineasm,*regstrb(ireg)) then
regfound2=ireg
end if
end if
if regfound2<>KNOTFOUND then
reghandle(regfound2)=KREGFREE
end if
next
end sub
''============== end of optim ====================================================
private function pw2(byval num as integer)as integer ''return the first power of 2 greater than a number ex 24 -->32
dim as double a=log(num)/log(2)
if frac(a)=0 then
return 2^a
else
return 2^(int(a)+1)
end if
end function
private sub asm_section(byref section as string)
static section_current as string
if section_current<>section then
asm_code(".section "+section)
section_current=section
end if
end sub
private sub emitop3_op4(byref op as string)
if right(op,3)="#NO" then
asm_code(op,KNOOPTIM)
else
asm_code(op)
end if
end sub
sub dbg_filename(byref filename as string)
if filename <> ctxdbg.prevfilename then
dbg_addstab(filename,STAB_TYPE_SOL )
ctxdbg.prevfilename = filename
end if
end sub
private sub hwriteasm64( byref ln2 as string,byval opt as integer=KDOALL)
dim as string ln,lname
#ifdef __GAS64_DEBUG__
if ln2[0]=asc("#") then
ln=" "+ln2
else
#endif
ln=ln2
if ctx.opereg then
if ctx.opepass=1 then
ctx.opepass=2
else
ctx.opereg=0
end if
end if
if ctx.jmppass then
ctx.jmppass-=1
if ctx.jmppass=0 then
ctx.jmpvreg=KREGFREE
end if
end if
if( env.clopt.debuginfo = true ) then
if ctxdbg.lnum<>-1 then
dbg_filename(ctxdbg.linefilename)
lname = *symbUniqueLabel( )
dbg_addstab(,STAB_TYPE_SLINE ,ctxdbg.lnum,lname+"-"+*symbGetMangledName( ctxdbg.proc ))
ctxdbg.lnum=-1
asm_code(lname+":")
end if
end if
if opt<>KNOFREE and opt<>KNOALL then reg_freeable(ln)
if opt=KNOOPTIM or opt=KNOALL then
''just reinit some variables
check_optim("")
else
check_optim(ln)
end if
ln = string( ctx.indent*3, 32 ) + ln
#ifdef __GAS64_DEBUG__
end if
#endif
''print ln ''used to display every line when compiler crashes....
ln += NEWLINE
'' Write it out to the current section
select case as const( ctx.section )
''body of procedure
case SECTION_PROC
ctx.proc_txt +=ln
case SECTION_PROLOG
ctx.prolog_txt += ln
case SECTION_EPILOG
ctx.epilog_txt += ln
case SECTION_HEAD
ctx.head_txt += ln
case SECTION_FOOT
ctx.foot_txt += ln
case else
''to avoid the lost of information if a section is not already selected
ctx.head_txt += ln
end select
end sub
private function hfloattohex_asm64(byval value as double,byval dtype as Integer,ByVal full as Byte=1) as string
'' Emit the raw bytes that make up the float / x86 little-endian assumption
dim as string rawbytes
dim as single singlevalue = value
if( typeGet( dtype ) = FB_DATATYPE_DOUBLE ) then
rawbytes="0x"+hex( *cptr( ulongint ptr, @value ), 16 )+" # DBL="+str(value)
if full then
return ".quad " + rawbytes
else
return rawbytes
end if
else
rawbytes="0x"+Hex( cuint( *cptr( ulong ptr, @singlevalue ) ), 8 )+" # SNG="+str(value)
if full then
return ".long " + rawbytes
else
return rawbytes
end if
end if
end function
''======================= for writing debug data ==========================================
private function dbg_addstr(byref strg as string,byval nosearch as integer =1) as integer
if nosearch=0 then
for istr as integer = 0 to ctxdbg.strnb
if strg=dbgstr(istr).txt then
return dbgstr(istr).offst
end if
next
end if
ctxdbg.strnb+=1
if ctxdbg.strnb>ctxdbg.strmax then
ctxdbg.strmax*=1.3
redim preserve dbgstr(ctxdbg.strmax)
end if
dbgstr(ctxdbg.strnb).txt=strg
dbgstr(ctxdbg.strnb).offst=ctxdbg.offst
function=ctxdbg.offst
ctxdbg.offst+=len(strg)+1
end function
private sub dbg_addstab(byref txt as string="",byval cod as ubyte,byval desc as short=0,byref value as string="0")
dim as longint offst
dim as ustab stab
if txt <>"" then
if cod=STAB_TYPE_SO or cod=STAB_TYPE_SOL then ''could be duplicated
offst=dbg_addstr(txt,0)
else
offst=dbg_addstr(txt)
end if
end if
ctxdbg.stabnb+=1
if ctxdbg.stabnb>ctxdbg.stabmax then
ctxdbg.stabmax*=1.5
redim preserve dbgstab(ctxdbg.stabmax)
end if
stab.offst=offst
stab.cod=cod
stab.desc=desc
dbgstab(ctxdbg.stabnb).stab=stab.full
dbgstab(ctxdbg.stabnb).value=value
end sub
private sub dbg_emitstr()
if ctx.systemv then
asm_section(".dbgstr,""a""")
else
asm_section(".dbgstr,""dr""")
end if
asm_code(".byte 0")
for istr as integer = 0 to ctxdbg.strnb
asm_code(".ascii """+hReplace( dbgstr(istr).txt, "\", $"\\" )+$"\0""")
next
end sub
private sub dbg_emitstab()
dim as ustab stab
if ctx.systemv then
asm_section(".dbgdat,""a""")
else
asm_section(".dbgdat,""dr""")
end if
for istab as integer = 0 to ctxdbg.stabnb