@@ -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 is_safe 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
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
647
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,14 +699,8 @@ let rec div_int c1 c2 is_safe 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
667
- (Cconst_int (0 , dbg))
668
- (div_int c1 (Cconst_int (- n, dbg)) is_safe dbg)
669
- dbg
670
702
else
671
- let m, p = divimm_parameters ( Nativeint. of_int n) in
703
+ let m, p = divimm_parameters n in
672
704
(* Algorithm:
673
705
674
706
t = multiply-high-signed(c1, m) if m < 0,
@@ -688,30 +720,36 @@ let rec div_int c1 c2 is_safe dbg =
688
720
if p > 0 then Cop (Casr , [t; Cconst_int (p, dbg)], dbg) else t
689
721
in
690
722
add_int t (lsr_int c1 (Cconst_int (Nativeint. size - 1 , dbg)) dbg) dbg)
691
- | c1 , c2 when ! Clflags. unsafe || is_safe = Lambda. Unsafe ->
692
- Cop (Cdivi , [c1; c2], dbg)
693
- | c1 , c2 ->
694
- bind " divisor" c2 (fun c2 ->
695
- bind " dividend" c1 (fun c1 ->
696
- Cifthenelse
697
- ( c2,
698
- dbg,
699
- Cop (Cdivi , [c1; c2], dbg),
700
- dbg,
701
- raise_symbol dbg " caml_exn_Division_by_zero" ,
702
- dbg,
703
- Any )))
704
-
705
- let mod_int c1 c2 is_safe dbg =
706
- match c1, c2 with
707
- | c1 , Cconst_int (0 , _ ) ->
708
- Csequence (c1, raise_symbol dbg " caml_exn_Division_by_zero" )
709
- | c1 , Cconst_int ((1 | - 1 ), _ ) -> Csequence (c1, Cconst_int (0 , dbg))
710
- | Cconst_int (n1 , _ ), Cconst_int (n2 , _ ) -> Cconst_int (n1 mod n2, dbg)
711
- | c1 , (Cconst_int (n , _ ) as c2 ) when n <> min_int ->
712
- let l = Misc. log2 n in
713
- if n = 1 lsl l
723
+ | _ , _ ->
724
+ make_safe_divmod ?dividend_cannot_be_min_int ~if_divisor_is_negative_one
725
+ Cdivi c1 c2 ~dbg
726
+
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
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
714
751
then
752
+ let l = Misc. log2_nativeint n in
715
753
(* Algorithm:
716
754
717
755
t = shift-right-signed(c1, l - 1)
@@ -728,69 +766,25 @@ let mod_int c1 c2 is_safe dbg =
728
766
let t = asr_int c1 (Cconst_int (l - 1 , dbg)) dbg in
729
767
let t = lsr_int t (Cconst_int (Nativeint. size - l, dbg)) dbg in
730
768
let t = add_int c1 t dbg in
731
- 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
732
770
sub_int c1 t dbg)
733
771
else
734
772
bind " dividend" c1 (fun c1 ->
735
- sub_int c1 (mul_int (div_int c1 c2 is_safe dbg) c2 dbg) dbg)
736
- | c1 , c2 when ! Clflags. unsafe || is_safe = Lambda. Unsafe ->
737
- (* Flambda already generates that test *)
738
- Cop (Cmodi , [c1; c2], dbg)
739
- | c1 , c2 ->
740
- bind " divisor" c2 (fun c2 ->
741
- bind " dividend" c1 (fun c1 ->
742
- Cifthenelse
743
- ( c2,
744
- dbg,
745
- Cop (Cmodi , [c1; c2], dbg),
746
- dbg,
747
- raise_symbol dbg " caml_exn_Division_by_zero" ,
748
- dbg,
749
- Any )))
750
-
751
- (* Division or modulo on boxed integers. The overflow case min_int / -1 can
752
- occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *)
753
-
754
- (* Division or modulo on boxed integers. The overflow case min_int / -1 can
755
- occur, in which case we force x / -1 = -x and x mod -1 = 0. (PR#5513). *)
756
-
757
- let safe_divmod_bi mkop mkm1 ?(dividend_cannot_be_min_int = false ) is_safe
758
- dividend divisor dbg =
759
- let is_different_from x = function
760
- | Cconst_int (n , _ ) -> Nativeint. of_int n <> x
761
- | Cconst_natint (n , _ ) -> n <> x
762
- | _ -> false
763
- in
764
- bind " divisor" divisor (fun divisor ->
765
- bind " dividend" dividend (fun dividend ->
766
- let c = mkop dividend divisor is_safe dbg in
767
- if not Arch. division_crashes_on_overflow
768
- then c
769
- else
770
- let dividend_cannot_be_min_int =
771
- dividend_cannot_be_min_int
772
- || is_different_from Nativeint. min_int dividend
773
- in
774
- let divisor_cannot_be_negative_one =
775
- is_different_from (- 1n ) divisor
776
- in
777
- if dividend_cannot_be_min_int || divisor_cannot_be_negative_one
778
- then c
779
- else
780
- Cifthenelse
781
- ( Cop (Ccmpi Cne , [divisor; Cconst_int (- 1 , dbg)], dbg),
782
- dbg,
783
- c,
784
- dbg,
785
- mkm1 dividend dbg,
786
- dbg,
787
- Any )))
788
-
789
- let safe_div_bi =
790
- safe_divmod_bi div_int (fun c1 dbg ->
791
- Cop (Csubi , [Cconst_int (0 , dbg); c1], dbg))
773
+ sub_int c1 (mul_int (div_int c1 c2 dbg) c2 dbg) dbg)
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
778
+
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))
792
783
793
- let safe_mod_bi = safe_divmod_bi mod_int (fun _ dbg -> Cconst_int (0 , dbg))
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))
794
788
795
789
(* Bool *)
796
790
@@ -1985,8 +1979,9 @@ let low_bits ~bits ~(dbg : Debuginfo.t) e =
1985
1979
| bits -> Misc. fatal_errorf " low_bits not implemented for %d bits" bits
1986
1980
1987
1981
let ignore_low_bits ~bits ~dbg :(_ : Debuginfo.t ) e =
1988
- assert (0 < = bits && bits < = arch_bits);
1989
- if bits = 0 then e else ignore_low_bit_int e
1982
+ if bits = 1
1983
+ then ignore_low_bit_int e
1984
+ else Misc. fatal_error " ignore_low_bits expected bits=1 for now"
1990
1985
1991
1986
let and_int e1 e2 dbg =
1992
1987
let is_mask32 = function
@@ -3465,11 +3460,21 @@ let mul_int_caml arg1 arg2 dbg =
3465
3460
incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg
3466
3461
| c1 , c2 -> incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg
3467
3462
3468
- let div_int_caml is_safe arg1 arg2 dbg =
3469
- tag_int (div_int (untag_int arg1 dbg) (untag_int arg2 dbg) is_safe dbg) dbg
3470
-
3471
- let mod_int_caml is_safe arg1 arg2 dbg =
3472
- tag_int (mod_int (untag_int arg1 dbg) (untag_int arg2 dbg) is_safe dbg) dbg
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
+ let div_int_caml arg1 arg2 dbg =
3468
+ tag_int
3469
+ (div_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3470
+ (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3471
+ dbg
3472
+
3473
+ let mod_int_caml arg1 arg2 dbg =
3474
+ tag_int
3475
+ (mod_int ~dividend_cannot_be_min_int: caml_integers_are_tagged
3476
+ (untag_int arg1 dbg) (untag_int arg2 dbg) dbg)
3477
+ dbg
3473
3478
3474
3479
let and_int_caml arg1 arg2 dbg = and_int arg1 arg2 dbg
3475
3480
0 commit comments