-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathints.asm
More file actions
973 lines (819 loc) · 28.5 KB
/
ints.asm
File metadata and controls
973 lines (819 loc) · 28.5 KB
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
; Процедуры (C примитивы) для работы с целыми числами.
; Возвращает целое число, сконвертированное из текстового представления.
; RDI - адрес строки;
; RSI - адрес строки, отображаемой в случае ошибки;
; CL - количество значащих разрядов результата.
proc parse_intnat
;base equ rsi
sign equ r8
over equ r9
msg equ r10
mov msg, rsi
push rdi
zero sign
cmp byte[rdi], '+'
jz .sign
cmp byte[rdi], '-'
jnz .positive
inc sign
.sign: inc rdi
.positive:
; По умолчанию числа десятичные знаковые.
; Проверим наличие префикса с основанием системы счисления.
cmp byte[rdi], '0'
jnz .s10
mov al, [rdi + 1]
and al, not ('a' xor 'A')
add rdi, 2
mov esi, 16
cmp al, 'X'
jz ._1
mov esi, 8
cmp al, 'O'
jz ._1
mov esi, 2
cmp al, 'B'
jz ._1
cmp al, 'U'
jz .u10
sub rdi, 2
; Один разряд занимает знак числа. Для знаковых чисел он д.б. 0,
; поскольку проверка выполняется до смены знака.
.s10: dec cl
.u10: mov esi, 10
._1:; Маска содержит 1 в разрядах, запрещённых для результата.
or over, -1
; Обеспечим сдвиг на 64 разряда
dec cl
shl over, cl
add over, over
mov al, [rdi]
inc rdi
sub eax, '0'
jc .fail
cmp al, 9
jbe ._1d
and al, not (('a' - '0') xor ('A' - '0'))
sub al, 'A' - '0' - 10
jc .fail
cmp al, 0Fh
ja .fail
._1d: movzx edx, al
cmp edx, esi
ja .fail
.next: mov al, [rdi]
inc rdi
cmp al, '_'
jz .next
sub al, '0'
jc .done
cmp al, 9
jbe .dgt
and al, not (('a' - '0') xor ('A' - '0'))
sub al, 'A' - '0' - 10
jc .done
cmp al, 0Fh
ja .done
.dgt: movzx ecx, al
cmp ecx, esi
ja .done
mov rax, rdx
mul rsi
; Умножение на основание системы счисления может вызвать переполнение.
jo .fail
add rax, rcx
; Возможно переполнение после сложения.
jc .fail
mov rdx, rax
jmp .next
.done: mov rax, rdx
zero rdx
; Даже если число знаковое, бит знака на данном этапе доложен быть 0,
; кроме случая, когда число равно минимальному отрицательному.
test rax, over
jnz .check_min
; Меняем знак, если установлен соответствующий признак.
sub rdx, rax
test sign, sign
.min: cmovnz rax, rdx
pop rsi
caml_string_length rsi, rcx, rdx
dec rdi
sub rdi, rcx
cmp rsi, rdi
jnz .fail2
ret
.check_min:
; Минимально возможное отрицательное число равно маске переполнения.
test sign, sign
jz .fail
sub rdx, rax
cmp rdx, over
jz .min
; При вызове caml_failwith нет необходимости выравнивать стек
.fail:; pop rdi
.fail2: mov rdi, msg
jmp caml_failwith
restore msg, over, sign
end proc
; Меняет местами байты в 16-ти разрядном представлении числа.
; EDI - целое в OCaml представлении.
C_primitive caml_bswap16
mov eax, edi
shr eax, 8
shl edi, 8
and eax, Val_int 0xff
and edi, Val_int 0xff00
or eax, edi
or eax, 1
ret
end C_primitive
; Возвращает результат сравнения целых знаковых чисел:
; Val_int 1 - 1е > 2го;
; Val_int 0 - значения равны;
; Val_int -1 - 1е < 2го;
; RDI - 1-е целое;
; RSI - 2-е целое.
C_primitive caml_int_compare
cmp rdi, rsi
mov eax, Val_int 0
mov ecx, Val_int 1
mov rdx, Val_int -1
cmovg eax, ecx ; rdi > rsi
cmovl rax, rdx ; rdi < rsi
ret
end C_primitive
; Возвращает целое OCaml value, сконвертированное из текстового представления.
; RDI - адрес строки.
C_primitive caml_int_of_string
mov cl, sizeof value * 8 - 1
lea rsi, [.errmsg]
call parse_intnat
Val_int rax
ret
virtual Const
.errmsg db 'int_of_string', 0
end virtual
end C_primitive
; Преобразует число в OCaml-строку (с заголовком) согласно формата.
; RDI - формат; см. format_of_iconv в stdlib/camlinternalFormat.ml
; RSI - целое (в OCaml-представлении).
C_primitive caml_format_int
Int_val rsi
mov rdx, 1 shl 63 - 1
jmp caml_alloc_sprintf1
end C_primitive
; 32-x разрядные целые числа. Располагаются в куче. Размер ячейки вдвое больше
; такого числа. Приводим их к "родному" представлению для совместимости.
; Формирует заголовок блока int32
macro int32_header
mov Val_header[alloc_small_ptr_backup], (1 + 1) wosize or Custom_tag
lea rax, [caml_int32_ops]
mov [alloc_small_ptr_backup + 1 * sizeof value], rax
end macro
; Значение хранится в 1-м поле блока (после 0-го - с адресом методов).
int32_val equ (1 * sizeof value)
; Сохраняет результат в блоке, устанавливает адреса блока и аллокатора.
macro int32_ret result
mov qword[alloc_small_ptr_backup + 2 * sizeof value], result
lea rax, [int32_val + alloc_small_ptr_backup]
lea alloc_small_ptr_backup, [alloc_small_ptr_backup + 3 * sizeof value]
ret
end macro
; Возвращает результат вычитания из 0 (смена знака) целого.
; RDI - адрес целого;
C_primitive caml_int32_neg
int32_header
mov eax, [int32_val + rdi]
neg eax
cdqe
int32_ret rax
end C_primitive
; Возвращает сумму двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_int32_add
int32_header
mov eax, [int32_val + rdi]
add eax, [int32_val + rsi]
cdqe
int32_ret rax
end C_primitive
; Возвращает разность двух целых.
; RDI - адрес уменьшаемого;
; RSI - адрес вычитаемого.
C_primitive caml_int32_sub
int32_header
mov eax, [int32_val + rdi]
sub eax, [int32_val + rsi]
cdqe
int32_ret rax
end C_primitive
; Возвращает произведение двух целых.
; RDI - адрес 1-го множителя;
; RSI - адрес 2-го множителя.
C_primitive caml_int32_mul
int32_header
mov eax, [int32_val + rdi]
imul dword[int32_val + rsi]
cdqe
int32_ret rax
end C_primitive
; Возвращает частное от деления двух целых.
; RDI - адрес делимого;
; RSI - адрес делителя.
C_primitive caml_int32_div
int32_header
mov ecx, [int32_val + rsi]
test ecx, ecx
jz caml_raise_zero_divide
; При 32-х разрядном делении 0x80000000 на -1 генерируется SIGFPE,
; поскольку частное положительно и выходит за допустимый диапазон.
; Вернём в таком случае делимое (как в эталонной реализации).
mov eax, [int32_val + rdi]
cmp eax, 1 shl (sizeof value * 4 - 1)
jz .max_neg
.div: cdq
idiv ecx
cdqe
int32_ret rax
.max_neg:
cmp ecx, -1
jnz .div
mov rax, rdi
ret
end C_primitive
; Возвращает остаток от деления (по модулю) двух целых.
; RDI - адрес делимого;
; RSI - адрес делителя.
C_primitive caml_int32_mod
int32_header
; При 32-х разрядном делении 0x80000000 на -1 генерируется SIGFPE (см. div).
; Используем 64-х разрядное.
movsxd rcx, [int32_val + rsi]
test rcx, rcx
jz caml_raise_zero_divide
movsxd rax, [int32_val + rdi]
cqo
idiv rcx
int32_ret rdx
end C_primitive
; Возвращает результат поразрядной конъюнкции (И) двух целых.
; RDI - адрес 1-го множителя;
; RSI - адрес 2-го множителя.
C_primitive caml_int32_and
int32_header
mov eax, [int32_val + rdi]
and eax, [int32_val + rsi]
int32_ret rax ; обнуляем незначащие разряды
end C_primitive
; Возвращает результат поразрядной дизъюнкции (включающего ИЛИ) двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_int32_or
int32_header
mov rax, [int32_val + rdi]
or rax, [int32_val + rsi]
int32_ret rax
end C_primitive
; Возвращает сумму по модулю 2 (исключающее ИЛИ) двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_int32_xor
int32_header
mov rax, [int32_val + rdi]
xor rax, [int32_val + rsi]
int32_ret rax
end C_primitive
; Сдвиг влево.
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_int32_shift_left
int32_header
Int_val esi
mov ecx, esi
mov eax, [int32_val + rdi]
shl eax, cl
cdqe
int32_ret rax ; обнуляем незначащие разряды
end C_primitive
; Сдвиг вправо арифметический (с учётом знака).
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_int32_shift_right
int32_header
Int_val esi
mov ecx, esi
mov rax, [int32_val + rdi]
sar rax, cl
int32_ret rax
end C_primitive
; Сдвиг вправо без учёта знака.
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_int32_shift_right_unsigned
int32_header
Int_val esi
mov ecx, esi
mov eax, [int32_val + rdi]
shr eax, cl
int32_ret rax ; обнуляем незначащие разряды
end C_primitive
; Меняет местами байты в 32-ти разрядном представлении числа.
; RDI - адрес 32-битного целого.
C_primitive caml_int32_bswap
int32_header
mov rax, [int32_val + rdi]
bswap eax
int32_ret rax ; обнуляем незначащие разряды
end C_primitive
; Возвращает адрес целого, полученного из OCaml value.
; RDI - OCaml value
C_primitive caml_int32_of_int
int32_header
Int_val rdi
int32_ret rdi
end C_primitive
; Возвращает целое OCaml value, преобразованное из int32.
; RDI - адрес целого числа.
C_primitive caml_int32_to_int
movsxd rax, [int32_val + rdi]
Val_int rax
ret
end C_primitive
; Возвращает адрес целого, полученного округлением вещественного числа.
; RDI - адрес вещественного числа.
C_primitive caml_int32_of_float
int32_header
cvttsd2si rax, [rdi]
int32_ret rax
end C_primitive
; Возвращает вещественное число, полученное из int32.
; RDI - адрес целого.
C_primitive caml_int32_to_float
mov eax, 1 wosize or Double_tag
mov [alloc_small_ptr_backup], rax
mov eax, [int32_val + rdi]
cvtsi2sd xmm0, eax
movsd [alloc_small_ptr_backup + sizeof value], xmm0
lea rax, [alloc_small_ptr_backup + sizeof value]
lea alloc_small_ptr_backup, [alloc_small_ptr_backup + 2 * sizeof value]
ret
end C_primitive
; Сравнивает 2 целых числа.
C_primitive caml_int32_compare
mov eax, [int32_val + rdi]
cmp eax, [int32_val + rsi]
mov eax, Val_int 0
mov ecx, Val_int 1
mov rdx, Val_int -1
cmovnz eax, ecx
cmovs rax, rdx
ret
end C_primitive
; Преобразует 32-х разрядное число в OCaml-строку (с заголовком) согласно формата.
; RDI - формат; см. format_of_iconv в stdlib/camlinternalFormat.ml
; RSI - адрес блока с целым.
C_primitive caml_int32_format
; Для вывода шестнадцатеричных цифр следует удалить незначащие разряды.
or edx, -1
mov rsi, [int32_val + rsi]
jmp caml_alloc_sprintf1
end C_primitive
; Возвращает целое OCaml value, сконвертированное из текстового представления.
; RDI - адрес строки.
C_primitive caml_int32_of_string
int32_header
mov cl, sizeof value * 4
lea rsi, [.errmsg]
call parse_intnat
cdqe
int32_ret rax
virtual Const
.errmsg db 'Int32.of_string', 0
end virtual
end C_primitive
C_primitive caml_int32_bits_of_float
end C_primitive
C_primitive caml_int32_float_of_bits
end C_primitive
; 64-х разрядные числа. Располагаются в куче.
; Соответствуют "родным". В эталонной реализации различаются таблицей методов.
; Значение хранится в 1-м поле блока (после 0-го - с адресом методов).
int64_val equ (1 * sizeof value)
caml_int64_neg := caml_nativeint_neg
caml_int64_add := caml_nativeint_add
caml_int64_sub := caml_nativeint_sub
caml_int64_mul := caml_nativeint_mul
caml_int64_div := caml_nativeint_div
caml_int64_mod := caml_nativeint_mod
caml_int64_and := caml_nativeint_and
caml_int64_or := caml_nativeint_or
caml_int64_xor := caml_nativeint_xor
caml_int64_shift_left := caml_nativeint_shift_left
caml_int64_shift_right := caml_nativeint_shift_right
caml_int64_shift_right_unsigned := caml_nativeint_shift_right_unsigned
caml_int64_bswap := caml_nativeint_bswap
caml_int64_of_int := caml_nativeint_of_int
caml_int64_to_int := caml_nativeint_to_int
caml_int64_of_float := caml_nativeint_of_float
caml_int64_to_float := caml_nativeint_to_float
caml_int64_of_int32 := caml_nativeint_of_int32
caml_int64_to_int32 := caml_nativeint_to_int32
caml_int64_to_nativeint := caml_int64_of_nativeint
caml_int64_compare := caml_nativeint_compare
caml_int64_format := caml_nativeint_format
; Возвращает целое OCaml value, сконвертированное из текстового представления.
; RDI - адрес строки.
C_primitive caml_int64_of_string
lea rsi, [.errmsg]
jmp caml_nativeint_of_string.rsi
virtual Const
.errmsg db 'Int64.of_string', 0
end virtual
end C_primitive
; Создаём копию, поскольку формат идентичен. (безопасно ли просто вернуть RDI?)
C_primitive caml_int64_of_nativeint
nativeint_header
mov rax, [nativeint_val + rdi]
nativeint_ret rax
end C_primitive
C_primitive caml_int64_bits_of_float
end C_primitive
; RDI - адрес источника для копирования в кучу числа с плавающей точкой.
C_primitive caml_int64_float_of_bits
mov eax, 1 wosize or Double_tag
mov [alloc_small_ptr_backup], rax
mov rax, [int64_val + rdi]
mov [alloc_small_ptr_backup + sizeof value], rax
lea rax, [alloc_small_ptr_backup + sizeof value]
lea alloc_small_ptr_backup, [alloc_small_ptr_backup + 2 * sizeof value]
ret
end C_primitive
; "Родные" для архитектуры целые числа. Располагаются в куче.
; Формирует заголовок блока nativeint
macro nativeint_header
mov Val_header[alloc_small_ptr_backup], (1 + 1) wosize or Custom_tag
lea rax, [caml_nativeint_ops]
mov [alloc_small_ptr_backup + 1 * sizeof value], rax
end macro
; Значение хранится в 1-м поле блока (после 0-го - с адресом методов).
nativeint_val equ (1 * sizeof value)
; Сохраняет результат в блоке, устанавливает адреса блока и аллокатора.
macro nativeint_ret result
mov [alloc_small_ptr_backup + 2 * sizeof value], result
lea rax, [nativeint_val + alloc_small_ptr_backup]
lea alloc_small_ptr_backup, [alloc_small_ptr_backup + 3 * sizeof value]
ret
end macro
; Возвращает результат вычитания из 0 (смена знака) целого.
; RDI - адрес целого;
C_primitive caml_nativeint_neg
nativeint_header
mov rax, [nativeint_val + rdi]
neg rax
nativeint_ret rax
end C_primitive
; Возвращает сумму двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_nativeint_add
nativeint_header
mov rax, [nativeint_val + rdi]
add rax, [nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Возвращает разность двух целых.
; RDI - адрес 1-го уменьшаемое;
; RSI - адрес 2-го вычитаемое.
C_primitive caml_nativeint_sub
nativeint_header
mov rax, [nativeint_val + rdi]
sub rax, [nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Возвращает произведение двух целых.
; RDI - адрес 1-го множителя;
; RSI - адрес 2-го множителя.
C_primitive caml_nativeint_mul
nativeint_header
mov rax, [nativeint_val + rdi]
imul qword[nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Возвращает частное от деления двух целых.
; RDI - адрес делимого;
; RSI - адрес делителя.
C_primitive caml_nativeint_div
nativeint_header
mov rcx, [nativeint_val + rsi]
test rcx, rcx
jz caml_raise_zero_divide
; При делении 0x8000000000000000 на -1 генерируется SIGFPE, поскольку
; частное положительно и выходит за допустимый диапазон.
; Вернём в таком случае делимое (как в эталонной реализации).
mov rax, 1 shl (sizeof value * 8 - 1)
cmp rax, [nativeint_val + rdi]
jz .max_neg
mov rax, [nativeint_val + rdi]
.div: cqo
idiv rcx
.retm: nativeint_ret rax
.max_neg:
cmp rcx, -1
jnz .div
mov rax, rdi
ret
end C_primitive
; Возвращает остаток от деления (по модулю) двух целых.
; RDI - адрес делимого;
; RSI - адрес делителя.
C_primitive caml_nativeint_mod
nativeint_header
mov rcx, [nativeint_val + rsi]
test rcx, rcx
jz caml_raise_zero_divide
; При делении 0x8000000000000000 на -1 генерируется SIGFPE (см. div).
; В случае деления на -1 остаток всегда 0, вернём его непосредственно.
zero edx
cmp rcx, -1
jz .ret0
mov rax, [nativeint_val + rdi]
cqo
idiv rcx
.ret0: nativeint_ret rdx
end C_primitive
; Возвращает результат поразрядной конъюнкции (И) двух целых.
; RDI - адрес 1-го множителя;
; RSI - адрес 2-го множителя.
C_primitive caml_nativeint_and
nativeint_header
mov rax, [nativeint_val + rdi]
and rax, [nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Возвращает результат поразрядной дизъюнкции (включающего ИЛИ) двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_nativeint_or
nativeint_header
mov rax, [nativeint_val + rdi]
or rax, [nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Возвращает сумму по модулю 2 (исключающее ИЛИ) двух целых.
; RDI - адрес 1-го слагаемого;
; RSI - адрес 2-го слагаемого.
C_primitive caml_nativeint_xor
nativeint_header
mov rax, [nativeint_val + rdi]
xor rax, [nativeint_val + rsi]
nativeint_ret rax
end C_primitive
; Сдвиг влево целого.
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_nativeint_shift_left
nativeint_header
Int_val esi
mov ecx, esi
mov rax, [nativeint_val + rdi]
shl rax, cl
nativeint_ret rax
end C_primitive
; Сдвиг вправо арифметический (с учётом знака).
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_nativeint_shift_right
nativeint_header
Int_val esi
mov ecx, esi
mov rax, [nativeint_val + rdi]
sar rax, cl
nativeint_ret rax
end C_primitive
; Сдвиг вправо без учёта знака.
; Возвращает адрес результата.
; RDI - адрес сдвигаемого аргумента;
; RSI - количество бит, на которое следует сдвинуть аргумент (OCaml value)
C_primitive caml_nativeint_shift_right_unsigned
nativeint_header
Int_val esi
mov ecx, esi
mov rax, [nativeint_val + rdi]
shr rax, cl
nativeint_ret rax
end C_primitive
; Меняет местами байты в представлении числа.
; RDI - адрес целого.
C_primitive caml_nativeint_bswap
nativeint_header
mov rax, [nativeint_val + rdi]
bswap rax
nativeint_ret rax
end C_primitive
; Возвращает адрес целого, полученного из OCaml value.
; RDI - OCaml value
C_primitive caml_nativeint_of_int
nativeint_header
Int_val rdi
nativeint_ret rdi
end C_primitive
; Возвращает OCaml value, полученное из 64-х разрядного целого.
C_primitive caml_nativeint_to_int
mov rax, [nativeint_val + rdi]
Val_int rax
ret
end C_primitive
C_primitive caml_nativeint_of_float
end C_primitive
C_primitive caml_nativeint_to_float
end C_primitive
; Возвращает целое, сконвертированное из 32-х разрядного.
; RDI - адрес 32-х разрядного.
C_primitive caml_nativeint_of_int32
nativeint_header
movsxd rax, [int32_val + rdi]
nativeint_ret rax
end C_primitive
; Возвращает 32-х разрядное целое, полученное из 64-х разрядного.
C_primitive caml_nativeint_to_int32
int32_header
mov eax, [nativeint_val + rdi]
cdqe
int32_ret rax
end C_primitive
; Сравнивает 2 целых числа.
C_primitive caml_nativeint_compare
mov rax, [int32_val + rdi]
cmp rax, [int32_val + rsi]
mov eax, Val_int 0
mov ecx, Val_int 1
mov rdx, Val_int -1
cmovnz eax, ecx
cmovs rax, rdx
ret
end C_primitive
; Преобразует число в текстовую форму, располагая строку в текущие адреса кучи.
; Может приводить к инкременту указателя кучи.
; Возвращает в RAX длину строки-результата, выходящую за пределы указателя кучи.
; RSI - знаковое целое (в OCaml-представлении).
; RDI, RSI, RDX, RCX - не определены;
; R8, R9, R10 и R11 не используются.
proc format_int_dec
Int_val rsi
; RSI - знаковое целое.
format_nativeint_signed:
test rsi, rsi
jns format_nativeint
neg rsi
mov byte[alloc_small_ptr_backup], '-'
inc alloc_small_ptr_backup
; Преобразует число в текстовую форму, располагая строку в текущие адреса кучи.
; Возвращает в RAX длину строки-результата.
; RSI - беззнаковое целое
; RDI, RDX, RCX - не определены;
; R8 и R9 не используются по требованию caml_alloc_sprintf1.
; R10 и R11 не используются по требованию format_floating_point_number.
format_nativeint:
zero edx
; Возвращает в RSI частное от деления на 10 в степени RDX (число, значение
; которого представляет оставшиеся невыведенными старшие разряды).
; RDX - минимальное количество выводимых разрядов.
format_nativeint_pos:
zero ecx
zero edi
; Определяем количество цифр, вычисляя десятичный логарифм простым циклом.
; (вариант корректировки log2(n)*19/64 по таблице иногда быстрее, но объёмнее).
mov eax, 10
.log10: inc ecx
cmp rsi, rax
jb .@
lea rax, [rax * 5]
add rax, rax
jnc .log10
inc ecx
.@: cmp edx, ecx
cmovc edx, ecx
; EDI - количество младших цифр, после которого следует вывести разделитель.
; Разделитель находится в разрядах 32..39 RDI
; EDX - количество цифр (младших разрядов), подлежащих выводу.
format_nativeint_n:
mov ecx, edx
push rcx
; Делим на 10, умножая на магическое число.
.@: dec rdi
test edi, edi
jz .delimiter
mov rax, rsi
mov rdx, 0xCCCCCCCCCCCCCCCD
mul rdx
shr rdx, 3 ; частное
mov rax, rsi
mov rsi, rdx
lea rdx, [rdx * 4 + rdx]
sub rax, rdx
sub rax, rdx ; остаток
; Сохраняем остаток в виде символа.
add al ,'0'
.@1: dec ecx
mov [alloc_small_ptr_backup + rcx], al
jnz .@
pop rax ; размер строки
ret
.delimiter:
shr rdi, 32
mov al, dil
zero edi
jmp .@1
end proc
; Преобразует число в шестнадцатеричный текст, располагая строку в текущие адреса кучи.
; Возвращает в RAX длину строки-результата.
; RSI - беззнаковое целое.
; DL - символ соответствующий 10, т.е. 'A' или 'a'.
; R8 и R9 не используются.
proc format_nativeint_hex
; Подсчитываем количество значащих полубайт и сдвигаем незначащие.
bsr rcx, rsi
or ecx, 3
neg ecx
add ecx, 63
shl rsi, cl
shr ecx, 2
neg ecx
add ecx, 16
; ECX - количество разрядов (старших полубайт) для вывода.
; Возвращает в RSI невыведенные разряды (сдвинутыми в старшие позиции).
format_nativeint_hex_n:
zero edi
sub dl, '9' + 1
.hex_digit:
mov rax, rsi
shr rax, (sizeof value - 1) * 8 + 4
add al, '0'
cmp al, '9'
jbe .dig
add al, dl
.dig: mov [alloc_small_ptr_backup + rdi], al
inc edi
shl rsi, 4
loop .hex_digit
mov eax, edi
ret
end proc
; Преобразует число в восьмеричный текст, располагая строку в текущие адреса кучи.
; Возвращает в RAX длину строки-результата.
; RSI - беззнаковое целое.
proc format_nativeint_oct
zero rdi
mov ecx, sizeof value * 8 / 3
; 1 + 21 * 3 бит. Обрабатываем старший разряд восьмеричного числа отдельно.
shl rsi, 1
jc .high1
.skip_leading_zeroes:
mov rax, rsi
shr rax, sizeof value * 8 - 3
jnz .od
shl rsi, 3
loop .skip_leading_zeroes
inc ecx
.oct_digit:
mov rax, rsi
shr rax, sizeof value * 8 - 3
.od: add al, '0'
mov [alloc_small_ptr_backup + rdi], al
inc rdi
shl rsi, 3
loop .oct_digit
mov rax, rdi
ret
.high1: mov byte[alloc_small_ptr_backup], '1'
inc rdi
jmp .oct_digit
end proc
; Преобразует число в OCaml-строку (с заголовком) согласно формата.
; RDI - формат; см. format_of_iconv в stdlib/camlinternalFormat.ml
; RSI - адрес блока с целым.
C_primitive caml_nativeint_format
or rdx, -1
mov rsi, [nativeint_val + rsi]
jmp caml_alloc_sprintf1
end C_primitive
; Возвращает целое OCaml value, сконвертированное из текстового представления.
; RDI - адрес строки.
C_primitive caml_nativeint_of_string
lea rsi, [.errmsg]
.rsi:
nativeint_header
mov cl, sizeof value * 8
call parse_intnat
nativeint_ret rax
virtual Const
.errmsg db 'Nativeint.of_string', 0
end virtual
end C_primitive