@@ -434,6 +434,8 @@ let asr_int c1 c2 dbg =
434
434
| c1' -> Cop (Casr , [c1'; c2], dbg))
435
435
| _ -> Cop (Casr , [c1; c2], dbg)
436
436
437
+ let asr_const c n dbg = asr_int c (Cconst_int (n, dbg)) dbg
438
+
437
439
let tag_int i dbg =
438
440
match i with
439
441
| Cconst_int (n , _ ) -> int_const dbg n
@@ -543,45 +545,37 @@ let create_loop body dbg =
543
545
[division_parameters] function is used in module Emit for those target
544
546
platforms that support this optimization. *)
545
547
546
- (* Unsigned comparison between native integers. *)
547
-
548
- let ucompare x y = Nativeint. (compare (add x min_int) (add y min_int))
549
-
550
- (* Unsigned division and modulus at type nativeint. Algorithm: Hacker's Delight
551
- section 9.3 *)
552
-
553
- let udivmod n d =
554
- Nativeint. (
555
- if d < 0n
556
- then if ucompare n d < 0 then 0n , n else 1n , sub n d
557
- else
558
- let q = shift_left (div (shift_right_logical n 1 ) d) 1 in
559
- let r = sub n (mul q d) in
560
- if ucompare r d > = 0 then succ q, sub r d else q, r)
561
-
562
- (* Compute division parameters. Algorithm: Hacker's Delight chapter 10, fig
563
- 10-1. *)
564
-
565
548
let divimm_parameters d =
566
- Nativeint. (
567
- assert (d > 0n );
568
- let twopsm1 = min_int in
569
- (* 2^31 for 32-bit archs, 2^63 for 64-bit archs *)
570
- let nc = sub (pred twopsm1) (snd (udivmod twopsm1 d)) in
571
- let rec loop p (q1 , r1 ) (q2 , r2 ) =
572
- let p = p + 1 in
573
- let q1 = shift_left q1 1 and r1 = shift_left r1 1 in
574
- let q1, r1 = if ucompare r1 nc > = 0 then succ q1, sub r1 nc else q1, r1 in
575
- let q2 = shift_left q2 1 and r2 = shift_left r2 1 in
576
- let q2, r2 = if ucompare r2 d > = 0 then succ q2, sub r2 d else q2, r2 in
577
- let delta = sub d r2 in
578
- if ucompare q1 delta < 0 || (q1 = delta && r1 = 0n )
579
- then loop p (q1, r1) (q2, r2)
580
- else succ q2, p - size
581
- in
582
- loop (size - 1 ) (udivmod twopsm1 nc) (udivmod twopsm1 d))
549
+ (* Signed division and modulus at type nativeint. Algorithm: Hacker's Delight,
550
+ 2nd ed, Figure 10-1. *)
551
+ let open Nativeint in
552
+ let udivmod n d =
553
+ let q = unsigned_div n d in
554
+ q, sub n (mul q d)
555
+ in
556
+ let ad = abs d in
557
+ assert (ad > 1n );
558
+ let t = add min_int (shift_right_logical d (size - 1 )) in
559
+ let anc = sub (pred t) (unsigned_rem t ad) in
560
+ let step (q , r ) x =
561
+ let q = shift_left q 1 and r = shift_left r 1 in
562
+ if unsigned_compare r x > = 0 then succ q, sub r x else q, r
563
+ in
564
+ let rec loop p qr1 qr2 =
565
+ let p = p + 1 in
566
+ let q1, r1 = step qr1 anc in
567
+ let q2, r2 = step qr2 ad in
568
+ let delta = sub ad r2 in
569
+ if unsigned_compare q1 delta < 0 || (q1 = delta && r1 = 0n )
570
+ then loop p (q1, r1) (q2, r2)
571
+ else
572
+ let m = succ q2 in
573
+ let m = if d < 0n then neg m else m in
574
+ m, p - size
575
+ in
576
+ loop (size - 1 ) (udivmod min_int anc) (udivmod min_int ad)
583
577
584
- (* The result [(m, p)] of [divimm_parameters d] satisfies the following
578
+ (* For d > 1, the result [(m, p)] of [divimm_parameters d] satisfies the following
585
579
inequality:
586
580
587
581
2^(wordsize + p) < m * d <= 2^(wordsize + p) + 2^(p + 1) (i)
@@ -598,7 +592,7 @@ let divimm_parameters d =
598
592
599
593
* let add2 (xh, xl) (yh, yl) =
600
594
* let zl = add xl yl and zh = add xh yh in
601
- * (if ucompare zl xl < 0 then succ zh else zh), zl
595
+ * (if unsigned_compare zl xl < 0 then succ zh else zh), zl
602
596
*
603
597
* let shl2 (xh, xl) n =
604
598
* assert (0 < n && n < size + size);
@@ -619,16 +613,16 @@ let divimm_parameters d =
619
613
* (shl2 (0n, mul xl yh) halfsize)
620
614
* (add2 (shl2 (0n, mul xh yl) halfsize) (0n, mul xl yl)))
621
615
*
622
- * let ucompare2 (xh, xl) (yh, yl) =
623
- * let c = ucompare xh yh in
624
- * if c = 0 then ucompare xl yl else c
616
+ * let unsigned_compare2 (xh, xl) (yh, yl) =
617
+ * let c = unsigned_compare xh yh in
618
+ * if c = 0 then unsigned_compare xl yl else c
625
619
*
626
620
* let validate d m p =
627
621
* let md = mul2 m d in
628
622
* let one2 = 0n, 1n in
629
623
* let twoszp = shl2 one2 (size + p) in
630
624
* let twop1 = shl2 one2 (p + 1) in
631
- * ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0
625
+ * unsigned_compare2 twoszp md < 0 && unsigned_compare2 md (add2 twoszp twop1) <= 0
632
626
*)
633
627
634
628
let raise_symbol dbg symb =
@@ -662,93 +656,117 @@ let make_safe_divmod operator ~if_divisor_is_negative_one
662
656
dbg,
663
657
Any )))
664
658
665
- let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg =
659
+ let is_power_of_2_or_zero n = Nativeint. logand n (Nativeint. pred n) = 0n
660
+
661
+ let divide_by_zero dividend ~dbg =
662
+ bind " dividend" dividend (fun _ ->
663
+ raise_symbol dbg " caml_exn_Division_by_zero" )
664
+
665
+ let div_int ?dividend_cannot_be_min_int c1 c2 dbg =
666
666
let if_divisor_is_negative_one ~dividend ~dbg = neg_int dividend dbg in
667
667
match get_const c1, get_const c2 with
668
- | _ , Some 0n -> Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero " )
668
+ | _ , Some 0n -> divide_by_zero c1 ~ dbg
669
669
| _ , Some 1n -> c1
670
670
| Some n1 , Some n2 -> natint_const_untagged dbg (Nativeint. div n1 n2)
671
671
| _ , Some - 1n -> if_divisor_is_negative_one ~dividend: c1 ~dbg
672
- | _ , Some n ->
673
- if n < 0n
672
+ | _ , Some divisor ->
673
+ if divisor = Nativeint. min_int
674
674
then
675
- if n = Nativeint. min_int
676
- then Cop (Ccmpi Ceq , [c1; Cconst_natint (Nativeint. min_int, dbg)], dbg)
677
- else
678
- neg_int
679
- (div_int ?dividend_cannot_be_min_int c1
680
- (Cconst_natint (Nativeint. neg n, dbg))
681
- dbg)
682
- dbg
683
- else if Nativeint. logand n (Nativeint. pred n) = 0n
675
+ (* integer division by min_int always returns 0 unless the dividend is
676
+ also min_int, in which case it's 1. *)
677
+ Cifthenelse
678
+ ( Cop (Ccmpi Ceq , [c1; Cconst_natint (divisor, dbg)], dbg),
679
+ dbg,
680
+ Cconst_int (1 , dbg),
681
+ dbg,
682
+ Cconst_int (0 , dbg),
683
+ dbg,
684
+ Any )
685
+ else if is_power_of_2_or_zero divisor
684
686
then
685
- let l = Misc. log2_nativeint n in
687
+ (* [divisor] must be positive be here since we already handled zero and
688
+ min_int (the only negative power of 2) *)
689
+ let l = Misc. log2_nativeint divisor in
686
690
(* Algorithm:
687
691
688
692
t = shift-right-signed(c1, l - 1)
689
693
690
694
t = shift-right(t, W - l)
691
695
692
- t = c1 + t res = shift-right-signed(c1 + t, l) *)
693
- Cop
694
- ( Casr ,
695
- [ bind " dividend " c1 ( fun c1 ->
696
- assert (l > = 1 );
697
- let t = asr_int c1 ( Cconst_int (l - 1 , dbg)) dbg in
698
- let t = lsr_int t ( Cconst_int ( Nativeint. size - l, dbg) ) dbg in
699
- add_int c1 t dbg);
700
- Cconst_int (l, dbg) ],
701
- dbg )
696
+ t = c1 + t
697
+
698
+ res = shift-right-signed(c1 + t, l) *)
699
+ asr_const
700
+ (bind " dividend " c1 ( fun c1 ->
701
+ assert (l > = 1 );
702
+ let t = asr_const c1 (l - 1 ) dbg in
703
+ let t = lsr_const t ( Nativeint. size - l) dbg in
704
+ add_int c1 t dbg))
705
+ l dbg
702
706
else
703
- let m, p = divimm_parameters n in
704
- (* Algorithm:
707
+ bind " dividend " c1 ( fun n ->
708
+ (* Algorithm:
705
709
706
- t = multiply-high-signed(c1, m) if m < 0,
710
+ q = smulhi n, M
707
711
708
- t = t + c1 if p > 0,
712
+ if m < 0 && d > 0: q += n
709
713
710
- t = shift-right-signed(t, p)
714
+ if m > 0 && d < 0: q -= n
711
715
712
- res = t + sign-bit(c1) *)
713
- bind " dividend" c1 (fun c1 ->
714
- let t =
715
- Cop
716
- (Cmulhi { signed = true }, [c1; natint_const_untagged dbg m], dbg)
716
+ q >>= s
717
+
718
+ q += sign-bit(q) *)
719
+ let m, s = divimm_parameters divisor in
720
+ let q =
721
+ Cop (Cmulhi { signed = true }, [n; natint_const_untagged dbg m], dbg)
722
+ in
723
+ let q =
724
+ if m < 0n && divisor > = 0n
725
+ then add_int q n dbg
726
+ else if m > = 0n && divisor < 0n
727
+ then sub_int q n dbg
728
+ else q
717
729
in
718
- let t = if m < 0n then Cop (Caddi , [t; c1], dbg) else t in
719
- let t =
720
- if p > 0 then Cop (Casr , [t; Cconst_int (p, dbg)], dbg) else t
730
+ let q = asr_const q s dbg in
731
+ let sign_bit =
732
+ (* we can use n instead of q when the divisor is non-negative. This
733
+ makes the instruction dependency graph shallower. *)
734
+ lsr_const (if divisor > = 0n then n else q) (Nativeint. size - 1 ) dbg
721
735
in
722
- add_int t (lsr_int c1 ( Cconst_int ( Nativeint. size - 1 , dbg)) dbg) dbg)
736
+ add_int q sign_bit dbg)
723
737
| _ , _ ->
724
738
make_safe_divmod ?dividend_cannot_be_min_int ~if_divisor_is_negative_one
725
739
Cdivi c1 c2 ~dbg
726
740
727
741
let mod_int ?dividend_cannot_be_min_int c1 c2 dbg =
728
742
let if_divisor_is_positive_or_negative_one ~dividend ~dbg =
729
- match dividend with
730
- | Cvar _ -> Cconst_int (0 , dbg)
731
- | dividend -> Csequence (dividend, Cconst_int (0 , dbg))
743
+ bind " dividend" dividend (fun _ -> Cconst_int (0 , dbg))
732
744
in
733
745
match get_const c1, get_const c2 with
734
- | _ , Some 0n -> Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero " )
746
+ | _ , Some 0n -> divide_by_zero c1 ~ dbg
735
747
| _ , Some (1n | - 1n ) ->
736
748
if_divisor_is_positive_or_negative_one ~dividend: c1 ~dbg
737
749
| Some n1 , Some n2 -> natint_const_untagged dbg (Nativeint. rem n1 n2)
738
750
| _ , Some n ->
739
751
if n = Nativeint. min_int
740
752
then
753
+ (* Similarly to the division by min_int almost always being 0, modulo
754
+ min_int is almost always the identity, the exception being when the
755
+ divisor is min_int *)
741
756
bind " dividend" c1 (fun c1 ->
757
+ let min_int = Cconst_natint (Nativeint. min_int, dbg) in
742
758
Cifthenelse
743
- ( Cop (Ccmpi Ceq , [c1; neg_int c1 dbg ], dbg),
759
+ ( Cop (Ccmpi Ceq , [c1; min_int ], dbg),
744
760
dbg,
745
761
Cconst_int (0 , dbg),
746
762
dbg,
747
- Cop ( Cor , [c1; Cconst_natint ( Nativeint. min_int, dbg)], dbg) ,
763
+ c1 ,
748
764
dbg,
749
765
Any ))
750
- else if Nativeint. logand n ( Nativeint. pred n) = 0n
766
+ else if is_power_of_2_or_zero n
751
767
then
768
+ (* [divisor] must be positive be here since we already handled zero and
769
+ min_int (the only negative power of 2). *)
752
770
let l = Misc. log2_nativeint n in
753
771
(* Algorithm:
754
772
@@ -776,16 +794,6 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg =
776
794
~if_divisor_is_negative_one: if_divisor_is_positive_or_negative_one Cmodi
777
795
c1 c2 ~dbg
778
796
779
- let div_int ?dividend_cannot_be_min_int c1 c2 dbg =
780
- bind " divisor" c2 (fun c2 ->
781
- bind " dividend" c1 (fun c1 ->
782
- div_int ?dividend_cannot_be_min_int c1 c2 dbg))
783
-
784
- let mod_int ?dividend_cannot_be_min_int c1 c2 dbg =
785
- bind " divisor" c2 (fun c2 ->
786
- bind " dividend" c1 (fun c1 ->
787
- mod_int ?dividend_cannot_be_min_int c1 c2 dbg))
788
-
789
797
(* Bool *)
790
798
791
799
let test_bool dbg cmm =
@@ -3460,20 +3468,26 @@ let mul_int_caml arg1 arg2 dbg =
3460
3468
incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg
3461
3469
| c1 , c2 -> incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg
3462
3470
3463
- (* Since caml integers are tagged, we know that they when they're untagged, they
3464
- can't be [Nativeint.min_int] *)
3465
- let caml_integers_are_tagged = true
3466
-
3467
3471
let div_int_caml arg1 arg2 dbg =
3472
+ let dividend_cannot_be_min_int =
3473
+ (* Since caml integers are tagged, we know that they when they're untagged,
3474
+ they can't be [Nativeint.min_int] *)
3475
+ true
3476
+ in
3468
3477
tag_int
3469
- (div_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3470
- (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3478
+ (div_int ~dividend_cannot_be_min_int (untag_int arg1 dbg)
3479
+ (untag_int arg2 dbg) dbg)
3471
3480
dbg
3472
3481
3473
3482
let mod_int_caml arg1 arg2 dbg =
3483
+ let dividend_cannot_be_min_int =
3484
+ (* Since caml integers are tagged, we know that they when they're untagged,
3485
+ they can't be [Nativeint.min_int] *)
3486
+ true
3487
+ in
3474
3488
tag_int
3475
- (mod_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3476
- (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3489
+ (mod_int ~dividend_cannot_be_min_int (untag_int arg1 dbg)
3490
+ (untag_int arg2 dbg) dbg)
3477
3491
dbg
3478
3492
3479
3493
let and_int_caml arg1 arg2 dbg = and_int arg1 arg2 dbg
0 commit comments