@@ -635,16 +635,54 @@ let raise_symbol dbg symb =
635
635
Cop
636
636
(Craise Lambda. Raise_regular , [Cconst_symbol (global_symbol symb, dbg)], dbg)
637
637
638
- let rec div_int c1 c2 dbg =
639
- match c1, c2 with
640
- | c1 , Cconst_int (0 , _ ) ->
641
- Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero" )
642
- | c1 , Cconst_int (1 , _ ) -> c1
643
- | Cconst_int (n1 , _ ), Cconst_int (n2 , _ ) -> Cconst_int (n1 / n2, dbg)
644
- | c1 , Cconst_int (n , _ ) when n <> min_int ->
645
- let l = Misc. log2 n in
646
- if n = 1 lsl l
638
+ let [@ inline] get_const = function
639
+ | Cconst_int (i , _ ) -> Some (Nativeint. of_int i)
640
+ | Cconst_natint (i , _ ) -> Some i
641
+ | _ -> None
642
+
643
+ (* * Division or modulo on registers. The overflow case min_int / -1 can
644
+ occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513).
645
+ In typical cases, [operator] is used to compute the result.
646
+
647
+ However, if division crashes on overflow, we will insert a runtime check for a divisor
648
+ of -1, and fall back to [if_divisor_is_minus_one]. *)
649
+ let make_safe_divmod operator ~if_divisor_is_negative_one
650
+ ?(dividend_cannot_be_min_int = false ) c1 c2 ~dbg =
651
+ if dividend_cannot_be_min_int || not Arch. division_crashes_on_overflow
652
+ then Cop (operator, [c1; c2], dbg)
653
+ else
654
+ bind " divisor" c2 (fun c2 ->
655
+ bind " dividend" c1 (fun c1 ->
656
+ Cifthenelse
657
+ ( Cop (Ccmpi Cne , [c2; Cconst_int (- 1 , dbg)], dbg),
658
+ dbg,
659
+ Cop (operator, [c1; c2], dbg),
660
+ dbg,
661
+ if_divisor_is_negative_one ~dividend: c1 ~dbg ,
662
+ dbg,
663
+ Any )))
664
+
665
+ let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg =
666
+ let if_divisor_is_negative_one ~dividend ~dbg = neg_int dividend dbg in
667
+ match get_const c1, get_const c2 with
668
+ | _ , Some 0n -> Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero" )
669
+ | _ , Some 1n -> c1
670
+ | Some n1 , Some n2 -> natint_const_untagged dbg (Nativeint. div n1 n2)
671
+ | _ , Some - 1n -> if_divisor_is_negative_one ~dividend: c1 ~dbg
672
+ | _ , Some n ->
673
+ if n < 0n
647
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
684
+ then
685
+ let l = Misc. log2_nativeint n in
648
686
(* Algorithm:
649
687
650
688
t = shift-right-signed(c1, l - 1)
@@ -661,11 +699,8 @@ let rec div_int c1 c2 dbg =
661
699
add_int c1 t dbg);
662
700
Cconst_int (l, dbg) ],
663
701
dbg )
664
- else if n < 0
665
- then
666
- sub_int (Cconst_int (0 , dbg)) (div_int c1 (Cconst_int (- n, dbg)) dbg) dbg
667
702
else
668
- let m, p = divimm_parameters ( Nativeint. of_int n) in
703
+ let m, p = divimm_parameters n in
669
704
(* Algorithm:
670
705
671
706
t = multiply-high-signed(c1, m) if m < 0,
@@ -685,18 +720,36 @@ let rec div_int c1 c2 dbg =
685
720
if p > 0 then Cop (Casr , [t; Cconst_int (p, dbg)], dbg) else t
686
721
in
687
722
add_int t (lsr_int c1 (Cconst_int (Nativeint. size - 1 , dbg)) dbg) dbg)
688
- | c1 , c2 -> Cop (Cdivi , [c1; c2], dbg)
723
+ | _ , _ ->
724
+ make_safe_divmod ?dividend_cannot_be_min_int ~if_divisor_is_negative_one
725
+ Cdivi c1 c2 ~dbg
689
726
690
- let mod_int c1 c2 dbg =
691
- match c1, c2 with
692
- | c1 , Cconst_int (0 , _ ) ->
693
- Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero" )
694
- | c1 , Cconst_int ((1 | - 1 ), _ ) -> Csequence (c1, Cconst_int (0 , dbg))
695
- | Cconst_int (n1 , _ ), Cconst_int (n2 , _ ) -> Cconst_int (n1 mod n2, dbg)
696
- | c1 , (Cconst_int (n , _ ) as c2 ) when n <> min_int ->
697
- let l = Misc. log2 n in
698
- if n = 1 lsl l
727
+ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg =
728
+ 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))
732
+ in
733
+ match get_const c1, get_const c2 with
734
+ | _ , Some 0n -> Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero" )
735
+ | _ , Some (1n | - 1n ) ->
736
+ if_divisor_is_positive_or_negative_one ~dividend: c1 ~dbg
737
+ | Some n1 , Some n2 -> natint_const_untagged dbg (Nativeint. rem n1 n2)
738
+ | _ , Some n ->
739
+ if n = Nativeint. min_int
699
740
then
741
+ bind " dividend" c1 (fun c1 ->
742
+ Cifthenelse
743
+ ( Cop (Ccmpi Ceq , [c1; neg_int c1 dbg], dbg),
744
+ dbg,
745
+ Cconst_int (0 , dbg),
746
+ dbg,
747
+ Cop (Cor , [c1; Cconst_natint (Nativeint. min_int, dbg)], dbg),
748
+ dbg,
749
+ Any ))
750
+ else if Nativeint. logand n (Nativeint. pred n) = 0n
751
+ then
752
+ let l = Misc. log2_nativeint n in
700
753
(* Algorithm:
701
754
702
755
t = shift-right-signed(c1, l - 1)
@@ -713,62 +766,25 @@ let mod_int c1 c2 dbg =
713
766
let t = asr_int c1 (Cconst_int (l - 1 , dbg)) dbg in
714
767
let t = lsr_int t (Cconst_int (Nativeint. size - l, dbg)) dbg in
715
768
let t = add_int c1 t dbg in
716
- let t = Cop (Cand , [t; Cconst_int ( - n, dbg)], dbg) in
769
+ let t = Cop (Cand , [t; Cconst_natint ( Nativeint. neg n, dbg)], dbg) in
717
770
sub_int c1 t dbg)
718
771
else
719
772
bind " dividend" c1 (fun c1 ->
720
773
sub_int c1 (mul_int (div_int c1 c2 dbg) c2 dbg) dbg)
721
- | c1 , c2 ->
722
- (* Flambda already generates the tests for zero*)
723
- Cop (Cmodi , [c1; c2], dbg)
724
-
725
- (* Division or modulo on boxed integers. The overflow case min_int / -1 can
726
- occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *)
727
-
728
- (* Division or modulo on boxed integers. The overflow case min_int / -1 can
729
- occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *)
730
-
731
- let safe_divmod_bi mkop mkm1 ?(dividend_cannot_be_min_int = false ) dividend
732
- divisor dbg =
733
- let is_different_from x = function
734
- | Cconst_int (n , _ ) -> Nativeint. of_int n <> x
735
- | Cconst_natint (n , _ ) -> n <> x
736
- | _ -> false
737
- in
738
- bind " divisor" divisor (fun divisor ->
739
- bind " dividend" dividend (fun dividend ->
740
- let c = mkop dividend divisor dbg in
741
- if not Arch. division_crashes_on_overflow
742
- then c
743
- else
744
- let dividend_cannot_be_min_int =
745
- dividend_cannot_be_min_int
746
- || is_different_from Nativeint. min_int dividend
747
- in
748
- let divisor_cannot_be_negative_one =
749
- is_different_from (- 1n ) divisor
750
- in
751
- if dividend_cannot_be_min_int || divisor_cannot_be_negative_one
752
- then c
753
- else
754
- Cifthenelse
755
- ( Cop (Ccmpi Cne , [divisor; Cconst_int (- 1 , dbg)], dbg),
756
- dbg,
757
- c,
758
- dbg,
759
- mkm1 dividend dbg,
760
- dbg,
761
- Any )))
774
+ | _ , _ ->
775
+ make_safe_divmod ?dividend_cannot_be_min_int
776
+ ~if_divisor_is_negative_one: if_divisor_is_positive_or_negative_one Cmodi
777
+ c1 c2 ~dbg
762
778
763
779
let div_int ?dividend_cannot_be_min_int c1 c2 dbg =
764
- safe_divmod_bi ?dividend_cannot_be_min_int div_int
765
- ( fun c1 dbg -> Cop ( Csubi , [ Cconst_int ( 0 , dbg); c1], dbg))
766
- 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))
767
783
768
784
let mod_int ?dividend_cannot_be_min_int c1 c2 dbg =
769
- safe_divmod_bi ?dividend_cannot_be_min_int mod_int
770
- ( fun _ dbg -> Cconst_int ( 0 , dbg))
771
- 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))
772
788
773
789
(* Bool *)
774
790
@@ -3544,11 +3560,21 @@ let mul_int_caml arg1 arg2 dbg =
3544
3560
incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg
3545
3561
| c1 , c2 -> incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg
3546
3562
3563
+ (* Since caml integers are tagged, we know that they when they're untagged, they
3564
+ can't be [Nativeint.min_int] *)
3565
+ let caml_integers_are_tagged = true
3566
+
3547
3567
let div_int_caml arg1 arg2 dbg =
3548
- tag_int (div_int (untag_int arg1 dbg) (untag_int arg2 dbg) dbg) dbg
3568
+ tag_int
3569
+ (div_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3570
+ (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3571
+ dbg
3549
3572
3550
3573
let mod_int_caml arg1 arg2 dbg =
3551
- tag_int (mod_int (untag_int arg1 dbg) (untag_int arg2 dbg) dbg) dbg
3574
+ tag_int
3575
+ (mod_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3576
+ (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3577
+ dbg
3552
3578
3553
3579
let and_int_caml arg1 arg2 dbg = and_int arg1 arg2 dbg
3554
3580
0 commit comments