From eff8c7e2e1105d9029cdc8e709f9353fb85b009f Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Thu, 16 Jan 2025 13:01:05 -0500 Subject: [PATCH 1/9] responded to feedback --- backend/cmm_helpers.ml | 60 ++++++++++++++++++++--------------------- backend/cmm_helpers.mli | 9 ++++--- utils/misc.mli | 6 +++-- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index 746445fe89..4870ac7020 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -30,6 +30,12 @@ type arity = (* Local binding of complex expressions *) +let sequence x y = + match x, y with + | (Cvar _ | Cconst_int _ | Cconst_natint _ | Ctuple []), y -> y + | x, Ctuple [] -> x + | x, y -> Csequence (x, y) + let bind name arg fn = match arg with | Cvar _ | Cconst_int _ | Cconst_natint _ | Cconst_symbol _ -> fn arg @@ -662,6 +668,8 @@ let make_safe_divmod operator ~if_divisor_is_negative_one dbg, Any ))) +let is_power_of_2 n = Nativeint.logand n (Nativeint.pred n) = 0n + let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = let if_divisor_is_negative_one ~dividend ~dbg = neg_int dividend dbg in match get_const c1, get_const c2 with @@ -673,14 +681,18 @@ let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = if n < 0n then if n = Nativeint.min_int - then Cop (Ccmpi Ceq, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg) + then + (* integer division by min_int always returns 0 unless the dividend is + also min_int, in which case it's 1. This is the same as comparing + against min_int. *) + Cop (Ccmpi Ceq, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg) else neg_int (div_int ?dividend_cannot_be_min_int c1 (Cconst_natint (Nativeint.neg n, dbg)) dbg) dbg - else if Nativeint.logand n (Nativeint.pred n) = 0n + else if is_power_of_2 n then let l = Misc.log2_nativeint n in (* Algorithm: @@ -726,9 +738,7 @@ let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = let if_divisor_is_positive_or_negative_one ~dividend ~dbg = - match dividend with - | Cvar _ -> Cconst_int (0, dbg) - | dividend -> Csequence (dividend, Cconst_int (0, dbg)) + sequence dividend (Cconst_int (0, dbg)) in match get_const c1, get_const c2 with | _, Some 0n -> Csequence (c1, raise_symbol dbg "caml_exn_Division_by_zero") @@ -747,7 +757,7 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = Cop (Cor, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg), dbg, Any )) - else if Nativeint.logand n (Nativeint.pred n) = 0n + else if is_power_of_2 n then let l = Misc.log2_nativeint n in (* Algorithm: @@ -776,16 +786,6 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = ~if_divisor_is_negative_one:if_divisor_is_positive_or_negative_one Cmodi c1 c2 ~dbg -let div_int ?dividend_cannot_be_min_int c1 c2 dbg = - bind "divisor" c2 (fun c2 -> - bind "dividend" c1 (fun c1 -> - div_int ?dividend_cannot_be_min_int c1 c2 dbg)) - -let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = - bind "divisor" c2 (fun c2 -> - bind "dividend" c1 (fun c1 -> - mod_int ?dividend_cannot_be_min_int c1 c2 dbg)) - (* Bool *) let test_bool dbg cmm = @@ -3560,20 +3560,26 @@ let mul_int_caml arg1 arg2 dbg = incr_int (mul_int (untag_int c1 dbg) (decr_int c2 dbg) dbg) dbg | c1, c2 -> incr_int (mul_int (decr_int c1 dbg) (untag_int c2 dbg) dbg) dbg -(* Since caml integers are tagged, we know that they when they're untagged, they - can't be [Nativeint.min_int] *) -let caml_integers_are_tagged = true - let div_int_caml arg1 arg2 dbg = + let dividend_cannot_be_min_int = + (* Since caml integers are tagged, we know that they when they're untagged, + they can't be [Nativeint.min_int] *) + true + in tag_int - (div_int ~dividend_cannot_be_min_int:caml_integers_are_tagged - (untag_int arg1 dbg) (untag_int arg2 dbg) dbg) + (div_int ~dividend_cannot_be_min_int (untag_int arg1 dbg) + (untag_int arg2 dbg) dbg) dbg let mod_int_caml arg1 arg2 dbg = + let dividend_cannot_be_min_int = + (* Since caml integers are tagged, we know that they when they're untagged, + they can't be [Nativeint.min_int] *) + true + in tag_int - (mod_int ~dividend_cannot_be_min_int:caml_integers_are_tagged - (untag_int arg1 dbg) (untag_int arg2 dbg) dbg) + (mod_int ~dividend_cannot_be_min_int (untag_int arg1 dbg) + (untag_int arg2 dbg) dbg) dbg let and_int_caml arg1 arg2 dbg = and_int arg1 arg2 dbg @@ -3897,12 +3903,6 @@ let letin_mut v ty e body = Clet_mut (v, ty, e, body) let assign x e = Cassign (x, e) -let sequence x y = - match x, y with - | Ctuple [], _ -> y - | _, Ctuple [] -> x - | _, _ -> Csequence (x, y) - let ite ~dbg ~then_dbg ~then_ ~else_dbg ~else_ cond = Cifthenelse (cond, then_dbg, then_, else_dbg, else_, dbg, Any) diff --git a/backend/cmm_helpers.mli b/backend/cmm_helpers.mli index 73535abe0a..8d0235cbed 100644 --- a/backend/cmm_helpers.mli +++ b/backend/cmm_helpers.mli @@ -699,7 +699,7 @@ val create_ccatch : (** Shift operations. Inputs: a tagged caml integer and an untagged machine integer. Outputs: a tagged caml integer. - ake as first argument a tagged caml integer, and as + Take as first argument a tagged caml integer, and as second argument an untagged machine intger which is the amount to shift the first argument by. *) @@ -1183,9 +1183,10 @@ val unboxed_int64_or_nativeint_array_set : The first argument is the heap block to modify a field of. The [index_in_words] should be an untagged integer. - In constrast to [setfield] and [setfield_computed], [immediate_or_pointer] is not - needed as the layout is implied from the name, and [initialization_or_assignment] is - not needed as unboxed ints can always be assigned without caml_modify (etc.). *) + In contrast to [setfield] and [setfield_computed], [immediate_or_pointer] is not + needed as the layout is known from the [memory_chunk] argument, and + [initialization_or_assignment] is not needed as unboxed ints can always be assigned + without caml_modify (etc.). *) val get_field_unboxed : dbg:Debuginfo.t -> diff --git a/utils/misc.mli b/utils/misc.mli index e3129a230a..e6600d8f8a 100644 --- a/utils/misc.mli +++ b/utils/misc.mli @@ -463,8 +463,10 @@ val log2: int -> int if [n] is a power of 2*) val log2_nativeint: nativeint -> int -(** [log2_nativeint n] returns [s] such that [n = Nativeint.shift_left 1n s] - if [n] is a power of 2*) +(** [log2_nativeint n] computes [floor (log2 n)] when [ n > 0 ]. + If [n] is also a power of 2, the result [s] satisfies + [n = Nativeint.shift_left 1n s] +*) val align: int -> int -> int (** [align n a] rounds [n] upwards to a multiple of [a] From afe40f1c7343c91f09ba911e05dcf000c228bae4 Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Thu, 16 Jan 2025 15:06:12 -0500 Subject: [PATCH 2/9] updated signed division by a negative constant to use the algorithm suggested in the referenced book --- backend/cmm_helpers.ml | 102 ++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index 4870ac7020..e2b5523803 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -440,6 +440,8 @@ let asr_int c1 c2 dbg = | c1' -> Cop (Casr, [c1'; c2], dbg)) | _ -> Cop (Casr, [c1; c2], dbg) +let asr_const c n dbg = asr_int c (Cconst_int (n, dbg)) dbg + let tag_int i dbg = match i with | Cconst_int (n, _) -> int_const dbg n @@ -570,22 +572,28 @@ let udivmod n d = let divimm_parameters d = Nativeint.( - assert (d > 0n); - let twopsm1 = min_int in + let ad = abs d in + assert (ad > 1n); (* 2^31 for 32-bit archs, 2^63 for 64-bit archs *) - let nc = sub (pred twopsm1) (snd (udivmod twopsm1 d)) in + let t = add min_int (shift_right_logical d (size - 1)) in + let anc = sub (pred t) (snd (udivmod t ad)) in let rec loop p (q1, r1) (q2, r2) = let p = p + 1 in let q1 = shift_left q1 1 and r1 = shift_left r1 1 in - let q1, r1 = if ucompare r1 nc >= 0 then succ q1, sub r1 nc else q1, r1 in + let q1, r1 = + if ucompare r1 anc >= 0 then succ q1, sub r1 anc else q1, r1 + in let q2 = shift_left q2 1 and r2 = shift_left r2 1 in - let q2, r2 = if ucompare r2 d >= 0 then succ q2, sub r2 d else q2, r2 in - let delta = sub d r2 in + let q2, r2 = if ucompare r2 ad >= 0 then succ q2, sub r2 ad else q2, r2 in + let delta = sub ad r2 in if ucompare q1 delta < 0 || (q1 = delta && r1 = 0n) then loop p (q1, r1) (q2, r2) - else succ q2, p - size + else + let m = succ q2 in + let m = if d < 0n then neg m else m in + m, p - size in - loop (size - 1) (udivmod twopsm1 nc) (udivmod twopsm1 d)) + loop (size - 1) (udivmod min_int anc) (udivmod min_int ad)) (* The result [(m, p)] of [divimm_parameters d] satisfies the following inequality: @@ -670,31 +678,23 @@ let make_safe_divmod operator ~if_divisor_is_negative_one let is_power_of_2 n = Nativeint.logand n (Nativeint.pred n) = 0n -let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = +let div_int ?dividend_cannot_be_min_int c1 c2 dbg = let if_divisor_is_negative_one ~dividend ~dbg = neg_int dividend dbg in match get_const c1, get_const c2 with - | _, Some 0n -> Csequence (c1, raise_symbol dbg "caml_exn_Division_by_zero") + | _, Some 0n -> sequence c1 (raise_symbol dbg "caml_exn_Division_by_zero") | _, Some 1n -> c1 | Some n1, Some n2 -> natint_const_untagged dbg (Nativeint.div n1 n2) | _, Some -1n -> if_divisor_is_negative_one ~dividend:c1 ~dbg - | _, Some n -> - if n < 0n + | _, Some divisor -> + if divisor = Nativeint.min_int then - if n = Nativeint.min_int - then - (* integer division by min_int always returns 0 unless the dividend is - also min_int, in which case it's 1. This is the same as comparing - against min_int. *) - Cop (Ccmpi Ceq, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg) - else - neg_int - (div_int ?dividend_cannot_be_min_int c1 - (Cconst_natint (Nativeint.neg n, dbg)) - dbg) - dbg - else if is_power_of_2 n + (* integer division by min_int always returns 0 unless the dividend is + also min_int, in which case it's 1. This is the same as comparing + against min_int. *) + Cop (Ccmpi Ceq, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg) + else if is_power_of_2 divisor then - let l = Misc.log2_nativeint n in + let l = Misc.log2_nativeint divisor in (* Algorithm: t = shift-right-signed(c1, l - 1) @@ -702,17 +702,15 @@ let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = t = shift-right(t, W - l) t = c1 + t res = shift-right-signed(c1 + t, l) *) - Cop - ( Casr, - [ bind "dividend" c1 (fun c1 -> - assert (l >= 1); - let t = asr_int c1 (Cconst_int (l - 1, dbg)) dbg in - let t = lsr_int t (Cconst_int (Nativeint.size - l, dbg)) dbg in - add_int c1 t dbg); - Cconst_int (l, dbg) ], - dbg ) + asr_const + (bind "dividend" c1 (fun c1 -> + assert (l >= 1); + let t = asr_const c1 (l - 1) dbg in + let t = lsr_const t (Nativeint.size - l) dbg in + add_int c1 t dbg)) + l dbg else - let m, p = divimm_parameters n in + let m, p = divimm_parameters divisor in (* Algorithm: t = multiply-high-signed(c1, m) if m < 0, @@ -722,16 +720,22 @@ let rec div_int ?dividend_cannot_be_min_int c1 c2 dbg = t = shift-right-signed(t, p) res = t + sign-bit(c1) *) - bind "dividend" c1 (fun c1 -> - let t = - Cop - (Cmulhi { signed = true }, [c1; natint_const_untagged dbg m], dbg) + bind "dividend" c1 (fun n -> + let q = + Cop (Cmulhi { signed = true }, [n; natint_const_untagged dbg m], dbg) + in + let q = + if m < 0n && divisor >= 0n + then add_int q n dbg + else if m >= 0n && divisor < 0n + then sub_int q n dbg + else q in - let t = if m < 0n then Cop (Caddi, [t; c1], dbg) else t in - let t = - if p > 0 then Cop (Casr, [t; Cconst_int (p, dbg)], dbg) else t + let q = asr_const q p dbg in + let q_is_negative = + lsr_const (if divisor >= 0n then n else q) (Nativeint.size - 1) dbg in - add_int t (lsr_int c1 (Cconst_int (Nativeint.size - 1, dbg)) dbg) dbg) + add_int q q_is_negative dbg) | _, _ -> make_safe_divmod ?dividend_cannot_be_min_int ~if_divisor_is_negative_one Cdivi c1 c2 ~dbg @@ -741,20 +745,24 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = sequence dividend (Cconst_int (0, dbg)) in match get_const c1, get_const c2 with - | _, Some 0n -> Csequence (c1, raise_symbol dbg "caml_exn_Division_by_zero") + | _, Some 0n -> sequence c1 (raise_symbol dbg "caml_exn_Division_by_zero") | _, Some (1n | -1n) -> if_divisor_is_positive_or_negative_one ~dividend:c1 ~dbg | Some n1, Some n2 -> natint_const_untagged dbg (Nativeint.rem n1 n2) | _, Some n -> if n = Nativeint.min_int then + (* similarly to the division by min_int almost always being 0, modulo + min_int is almost always the identity, the exception being when the + divisor is min_int *) bind "dividend" c1 (fun c1 -> + let min_int = Cconst_natint (Nativeint.min_int, dbg) in Cifthenelse - ( Cop (Ccmpi Ceq, [c1; neg_int c1 dbg], dbg), + ( Cop (Ccmpi Ceq, [c1; min_int], dbg), dbg, Cconst_int (0, dbg), dbg, - Cop (Cor, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg), + c1, dbg, Any )) else if is_power_of_2 n From d54b895d01d92bde00a320b932c26f69aa19ab85 Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Fri, 17 Jan 2025 15:40:56 -0500 Subject: [PATCH 3/9] responded to feedback --- backend/cmm_helpers.ml | 195 +++++++++------------- backend/cmm_helpers.mli | 3 +- middle_end/flambda2/to_cmm/to_cmm_expr.ml | 5 +- 3 files changed, 82 insertions(+), 121 deletions(-) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index e2b5523803..63b4a27f27 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -30,12 +30,6 @@ type arity = (* Local binding of complex expressions *) -let sequence x y = - match x, y with - | (Cvar _ | Cconst_int _ | Cconst_natint _ | Ctuple []), y -> y - | x, Ctuple [] -> x - | x, y -> Csequence (x, y) - let bind name arg fn = match arg with | Cvar _ | Cconst_int _ | Cconst_natint _ | Cconst_symbol _ -> fn arg @@ -551,99 +545,35 @@ let create_loop body dbg = [division_parameters] function is used in module Emit for those target platforms that support this optimization. *) -(* Unsigned comparison between native integers. *) - -let ucompare x y = Nativeint.(compare (add x min_int) (add y min_int)) - -(* Unsigned division and modulus at type nativeint. Algorithm: Hacker's Delight - section 9.3 *) - -let udivmod n d = - Nativeint.( - if d < 0n - then if ucompare n d < 0 then 0n, n else 1n, sub n d - else - let q = shift_left (div (shift_right_logical n 1) d) 1 in - let r = sub n (mul q d) in - if ucompare r d >= 0 then succ q, sub r d else q, r) - -(* Compute division parameters. Algorithm: Hacker's Delight chapter 10, fig - 10-1. *) - let divimm_parameters d = - Nativeint.( - let ad = abs d in - assert (ad > 1n); - (* 2^31 for 32-bit archs, 2^63 for 64-bit archs *) - let t = add min_int (shift_right_logical d (size - 1)) in - let anc = sub (pred t) (snd (udivmod t ad)) in - let rec loop p (q1, r1) (q2, r2) = - let p = p + 1 in - let q1 = shift_left q1 1 and r1 = shift_left r1 1 in - let q1, r1 = - if ucompare r1 anc >= 0 then succ q1, sub r1 anc else q1, r1 - in - let q2 = shift_left q2 1 and r2 = shift_left r2 1 in - let q2, r2 = if ucompare r2 ad >= 0 then succ q2, sub r2 ad else q2, r2 in - let delta = sub ad r2 in - if ucompare q1 delta < 0 || (q1 = delta && r1 = 0n) - then loop p (q1, r1) (q2, r2) - else - let m = succ q2 in - let m = if d < 0n then neg m else m in - m, p - size - in - loop (size - 1) (udivmod min_int anc) (udivmod min_int ad)) - -(* The result [(m, p)] of [divimm_parameters d] satisfies the following - inequality: - - 2^(wordsize + p) < m * d <= 2^(wordsize + p) + 2^(p + 1) (i) - - from which it follows that - - floor(n / d) = floor(n * m / 2^(wordsize+p)), if 0 <= n < 2^(wordsize-1) - - ceil(n / d) = floor(n * m / 2^(wordsize+p)) + 1, if -2^(wordsize-1) <= n < 0 - - The correctness condition (i) above can be checked by the code below. It was - exhaustively tested for values of d from 2 to 10^9 in the wordsize = 64 - case. - - * let add2 (xh, xl) (yh, yl) = - * let zl = add xl yl and zh = add xh yh in - * (if ucompare zl xl < 0 then succ zh else zh), zl - * - * let shl2 (xh, xl) n = - * assert (0 < n && n < size + size); - * if n < size - * then - * logor (shift_left xh n) (shift_right_logical xl (size - n)), - * shift_left xl n - * else shift_left xl (n - size), 0n - * - * let mul2 x y = - * let halfsize = size / 2 in - * let halfmask = pred (shift_left 1n halfsize) in - * let xl = logand x halfmask and xh = shift_right_logical x halfsize in - * let yl = logand y halfmask and yh = shift_right_logical y halfsize in - * add2 - * (mul xh yh, 0n) - * (add2 - * (shl2 (0n, mul xl yh) halfsize) - * (add2 (shl2 (0n, mul xh yl) halfsize) (0n, mul xl yl))) - * - * let ucompare2 (xh, xl) (yh, yl) = - * let c = ucompare xh yh in - * if c = 0 then ucompare xl yl else c - * - * let validate d m p = - * let md = mul2 m d in - * let one2 = 0n, 1n in - * let twoszp = shl2 one2 (size + p) in - * let twop1 = shl2 one2 (p + 1) in - * ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0 - *) + (* Signed division and modulus at type nativeint. Algorithm: Hacker's Delight, + 2nd ed, Figure 10-1. *) + let open Nativeint in + let udivmod n d = + let q = unsigned_div n d in + q, sub n (mul q d) + in + let ad = abs d in + assert (ad > 1n); + let t = add min_int (shift_right_logical d (size - 1)) in + let anc = sub (pred t) (unsigned_rem t ad) in + let step (q, r) x = + let q = shift_left q 1 and r = shift_left r 1 in + if unsigned_compare r x >= 0 then succ q, sub r x else q, r + in + let rec loop p qr1 qr2 = + let p = p + 1 in + let q1, r1 = step qr1 anc in + let q2, r2 = step qr2 ad in + let delta = sub ad r2 in + if unsigned_compare q1 delta < 0 || (q1 = delta && r1 = 0n) + then loop p (q1, r1) (q2, r2) + else + let m = succ q2 in + let m = if d < 0n then neg m else m in + m, p - size + in + loop (size - 1) (udivmod min_int anc) (udivmod min_int ad) let raise_symbol dbg symb = Cop @@ -676,12 +606,16 @@ let make_safe_divmod operator ~if_divisor_is_negative_one dbg, Any ))) -let is_power_of_2 n = Nativeint.logand n (Nativeint.pred n) = 0n +let is_power_of_2_or_zero n = Nativeint.logand n (Nativeint.pred n) = 0n + +let divide_by_zero dividend ~dbg = + bind "dividend" dividend (fun _ -> + raise_symbol dbg "caml_exn_Division_by_zero") let div_int ?dividend_cannot_be_min_int c1 c2 dbg = let if_divisor_is_negative_one ~dividend ~dbg = neg_int dividend dbg in match get_const c1, get_const c2 with - | _, Some 0n -> sequence c1 (raise_symbol dbg "caml_exn_Division_by_zero") + | _, Some 0n -> divide_by_zero c1 ~dbg | _, Some 1n -> c1 | Some n1, Some n2 -> natint_const_untagged dbg (Nativeint.div n1 n2) | _, Some -1n -> if_divisor_is_negative_one ~dividend:c1 ~dbg @@ -689,11 +623,19 @@ let div_int ?dividend_cannot_be_min_int c1 c2 dbg = if divisor = Nativeint.min_int then (* integer division by min_int always returns 0 unless the dividend is - also min_int, in which case it's 1. This is the same as comparing - against min_int. *) - Cop (Ccmpi Ceq, [c1; Cconst_natint (Nativeint.min_int, dbg)], dbg) - else if is_power_of_2 divisor + also min_int, in which case it's 1. *) + Cifthenelse + ( Cop (Ccmpi Ceq, [c1; Cconst_natint (divisor, dbg)], dbg), + dbg, + Cconst_int (1, dbg), + dbg, + Cconst_int (0, dbg), + dbg, + Any ) + else if is_power_of_2_or_zero divisor then + (* [divisor] must be positive be here since we already handled zero and + min_int (the only negative power of 2) *) let l = Misc.log2_nativeint divisor in (* Algorithm: @@ -701,7 +643,9 @@ let div_int ?dividend_cannot_be_min_int c1 c2 dbg = t = shift-right(t, W - l) - t = c1 + t res = shift-right-signed(c1 + t, l) *) + t = c1 + t + + res = shift-right-signed(c1 + t, l) *) asr_const (bind "dividend" c1 (fun c1 -> assert (l >= 1); @@ -710,17 +654,19 @@ let div_int ?dividend_cannot_be_min_int c1 c2 dbg = add_int c1 t dbg)) l dbg else - let m, p = divimm_parameters divisor in - (* Algorithm: + bind "dividend" c1 (fun n -> + (* Algorithm: - t = multiply-high-signed(c1, m) if m < 0, + q = smulhi n, M - t = t + c1 if p > 0, + if m < 0 && d > 0: q += n - t = shift-right-signed(t, p) + if m > 0 && d < 0: q -= n - res = t + sign-bit(c1) *) - bind "dividend" c1 (fun n -> + q >>= s + + q += sign-bit(q) *) + let m, s = divimm_parameters divisor in let q = Cop (Cmulhi { signed = true }, [n; natint_const_untagged dbg m], dbg) in @@ -731,28 +677,33 @@ let div_int ?dividend_cannot_be_min_int c1 c2 dbg = then sub_int q n dbg else q in - let q = asr_const q p dbg in - let q_is_negative = + let q = asr_const q s dbg in + let sign_bit = + (* we can use n instead of q when the divisor is non-negative. This + makes the instruction dependency graph shallower. *) lsr_const (if divisor >= 0n then n else q) (Nativeint.size - 1) dbg in - add_int q q_is_negative dbg) + add_int q sign_bit dbg) | _, _ -> make_safe_divmod ?dividend_cannot_be_min_int ~if_divisor_is_negative_one Cdivi c1 c2 ~dbg let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = let if_divisor_is_positive_or_negative_one ~dividend ~dbg = - sequence dividend (Cconst_int (0, dbg)) + bind "dividend" dividend (fun _ -> Cconst_int (0, dbg)) in match get_const c1, get_const c2 with - | _, Some 0n -> sequence c1 (raise_symbol dbg "caml_exn_Division_by_zero") + | _, Some 0n -> divide_by_zero c1 ~dbg | _, Some (1n | -1n) -> if_divisor_is_positive_or_negative_one ~dividend:c1 ~dbg | Some n1, Some n2 -> natint_const_untagged dbg (Nativeint.rem n1 n2) | _, Some n -> if n = Nativeint.min_int then - (* similarly to the division by min_int almost always being 0, modulo + (* [divisor] must be positive be here since we already handled zero and + min_int (the only negative power of 2). + + Similarly to the division by min_int almost always being 0, modulo min_int is almost always the identity, the exception being when the divisor is min_int *) bind "dividend" c1 (fun c1 -> @@ -765,7 +716,7 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = c1, dbg, Any )) - else if is_power_of_2 n + else if is_power_of_2_or_zero n then let l = Misc.log2_nativeint n in (* Algorithm: @@ -3911,6 +3862,12 @@ let letin_mut v ty e body = Clet_mut (v, ty, e, body) let assign x e = Cassign (x, e) +let sequence x y = + match x, y with + | Ctuple [], _ -> y + | _, Ctuple [] -> x + | _, _ -> Csequence (x, y) + let ite ~dbg ~then_dbg ~then_ ~else_dbg ~else_ cond = Cifthenelse (cond, then_dbg, then_, else_dbg, else_, dbg, Any) diff --git a/backend/cmm_helpers.mli b/backend/cmm_helpers.mli index 8d0235cbed..109c1c2ee0 100644 --- a/backend/cmm_helpers.mli +++ b/backend/cmm_helpers.mli @@ -94,7 +94,7 @@ val tag_int : expression -> Debuginfo.t -> expression (** Integer untagging. [untag_int x = (x asr 1)] *) val untag_int : expression -> Debuginfo.t -> expression -(** Specific division operations for boxed integers *) +(** signed division of two register-width integers *) val div_int : ?dividend_cannot_be_min_int:bool -> expression -> @@ -102,6 +102,7 @@ val div_int : Debuginfo.t -> expression +(** signed remainder of two register-width integers *) val mod_int : ?dividend_cannot_be_min_int:bool -> expression -> diff --git a/middle_end/flambda2/to_cmm/to_cmm_expr.ml b/middle_end/flambda2/to_cmm/to_cmm_expr.ml index 7adcbd023d..0cdb343ac8 100644 --- a/middle_end/flambda2/to_cmm/to_cmm_expr.ml +++ b/middle_end/flambda2/to_cmm/to_cmm_expr.ml @@ -169,7 +169,10 @@ let translate_external_call env res ~free_vars apply ~callee_simple ~args https://github.com/ARM-software/abi-aa/releases/download/2024Q3/aapcs64.pdf and figure out what happens for mixed int/float struct returns (it - looks like the floats may be returned in int regs) *) + looks like the floats may be returned in int regs) + + jvanburen: that seems to be what clang does: + https://godbolt.org/z/snzEoME9h *) (match Target_system.architecture () with | X86_64 -> () | AArch64 -> From 1a4407655b48411741210668523966104176bc4e Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Fri, 17 Jan 2025 15:44:03 -0500 Subject: [PATCH 4/9] testing division by constant optimzation --- testsuite/tests/basic/division_by_constant.ml | 366 ++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 testsuite/tests/basic/division_by_constant.ml diff --git a/testsuite/tests/basic/division_by_constant.ml b/testsuite/tests/basic/division_by_constant.ml new file mode 100644 index 0000000000..ca70d1aeb6 --- /dev/null +++ b/testsuite/tests/basic/division_by_constant.ml @@ -0,0 +1,366 @@ +(* TEST + { native; } +*) +open Nativeint + +let test_cases = + let int_size = Nativeint.size in + let rng = Random.State.make [| int_size |] in + (* sparse test cases, concentrated around 0, the limits, and powers of 2 *) + List.init (int_size - 1) (fun size -> + let bit = (shift_left one) size in + let rand () = + Random.State.nativeint_in_range rng + ~min:(shift_right_logical bit 1) + ~max:(pred bit) + in + [ bit; + rand (); + lognot (rand ()); + (sub max_int) (rand ()); + lognot ((sub max_int) (rand ())) ]) + |> List.concat + |> List.sort_uniq compare + +let[@inline never] check ~dividend ~divisor ~quotient ~remainder = + assert (divisor <> 0n); + assert (quotient = div dividend divisor); + assert (remainder = rem dividend divisor); + assert (dividend = add (mul quotient divisor) remainder); + assert + (if divisor = min_int + then remainder <> min_int + else abs remainder < abs divisor); + let[@inline] sign x = if x < 0n then -1 else if x = 0n then 0 else 1 in + assert (remainder = 0n || sign remainder = sign dividend) + +let[@inline always] [@specialise always] check ~divisor = + ListLabels.iter test_cases ~f:(fun dividend -> + (Sys.opaque_identity check) + ~dividend + ~divisor + ~quotient:(div dividend divisor) + ~remainder:(rem dividend divisor) + ) + +(* manual tests *) +let () = check ~divisor:3n +let () = check ~divisor:(-3n) +let () = check ~divisor:65537n +let () = check ~divisor:(-65537n) + +(* checks generated by test_cases. These get inlined so the division by a constant is + replaced *) + +let () = check ~divisor:0x1n +let () = check ~divisor:0x2n +let () = check ~divisor:0x4n +let () = check ~divisor:0x7n +let () = check ~divisor:0x8n +let () = check ~divisor:0xdn +let () = check ~divisor:0x10n +let () = check ~divisor:0x15n +let () = check ~divisor:0x20n +let () = check ~divisor:0x2an +let () = check ~divisor:0x40n +let () = check ~divisor:0x4fn +let () = check ~divisor:0x80n +let () = check ~divisor:0xa3n +let () = check ~divisor:0x100n +let () = check ~divisor:0x154n +let () = check ~divisor:0x200n +let () = check ~divisor:0x339n +let () = check ~divisor:0x400n +let () = check ~divisor:0x6cfn +let () = check ~divisor:0x800n +let () = check ~divisor:0x820n +let () = check ~divisor:0x1000n +let () = check ~divisor:0x107an +let () = check ~divisor:0x2000n +let () = check ~divisor:0x3334n +let () = check ~divisor:0x4000n +let () = check ~divisor:0x7b3an +let () = check ~divisor:0x8000n +let () = check ~divisor:0xb205n +let () = check ~divisor:0x10000n +let () = check ~divisor:0x18e6fn +let () = check ~divisor:0x20000n +let () = check ~divisor:0x3efc3n +let () = check ~divisor:0x40000n +let () = check ~divisor:0x429bfn +let () = check ~divisor:0x80000n +let () = check ~divisor:0x8fcaen +let () = check ~divisor:0x100000n +let () = check ~divisor:0x16d760n +let () = check ~divisor:0x200000n +let () = check ~divisor:0x3c068en +let () = check ~divisor:0x400000n +let () = check ~divisor:0x773070n +let () = check ~divisor:0x800000n +let () = check ~divisor:0xf21538n +let () = check ~divisor:0x1000000n +let () = check ~divisor:0x13f99d3n +let () = check ~divisor:0x2000000n +let () = check ~divisor:0x3846a5en +let () = check ~divisor:0x4000000n +let () = check ~divisor:0x5fab3ffn +let () = check ~divisor:0x8000000n +let () = check ~divisor:0xf4a77f8n +let () = check ~divisor:0x10000000n +let () = check ~divisor:0x10fb6962n +let () = check ~divisor:0x20000000n +let () = check ~divisor:0x3bcd549fn +let () = check ~divisor:0x40000000n +let () = check ~divisor:0x4f952039n +let () = check ~divisor:0x80000000n +let () = check ~divisor:0xeebeb75bn +let () = check ~divisor:0x100000000n +let () = check ~divisor:0x18ec33361n +let () = check ~divisor:0x200000000n +let () = check ~divisor:0x3242a7138n +let () = check ~divisor:0x400000000n +let () = check ~divisor:0x6bfbaac2fn +let () = check ~divisor:0x800000000n +let () = check ~divisor:0x8a8c7567dn +let () = check ~divisor:0x1000000000n +let () = check ~divisor:0x1027b086b6n +let () = check ~divisor:0x2000000000n +let () = check ~divisor:0x28474c2119n +let () = check ~divisor:0x4000000000n +let () = check ~divisor:0x7a93d7fe87n +let () = check ~divisor:0x8000000000n +let () = check ~divisor:0xfb4c23c489n +let () = check ~divisor:0x10000000000n +let () = check ~divisor:0x1f89f89e294n +let () = check ~divisor:0x20000000000n +let () = check ~divisor:0x355e3337296n +let () = check ~divisor:0x40000000000n +let () = check ~divisor:0x629bf8bccb0n +let () = check ~divisor:0x80000000000n +let () = check ~divisor:0xbfe906f1b92n +let () = check ~divisor:0x100000000000n +let () = check ~divisor:0x191407f71472n +let () = check ~divisor:0x200000000000n +let () = check ~divisor:0x36b5f12f9313n +let () = check ~divisor:0x400000000000n +let () = check ~divisor:0x5e3f23f0dddan +let () = check ~divisor:0x800000000000n +let () = check ~divisor:0xbef5e282e032n +let () = check ~divisor:0x1000000000000n +let () = check ~divisor:0x18a24ff8561ecn +let () = check ~divisor:0x2000000000000n +let () = check ~divisor:0x2369e32fbc992n +let () = check ~divisor:0x4000000000000n +let () = check ~divisor:0x4ef620f95b74fn +let () = check ~divisor:0x8000000000000n +let () = check ~divisor:0x90411098f476en +let () = check ~divisor:0x10000000000000n +let () = check ~divisor:0x10f1bf16dd463bn +let () = check ~divisor:0x20000000000000n +let () = check ~divisor:0x34a2bdb789e08dn +let () = check ~divisor:0x40000000000000n +let () = check ~divisor:0x5c6e3e4595806en +let () = check ~divisor:0x80000000000000n +let () = check ~divisor:0xac2cb82fecde51n +let () = check ~divisor:0x100000000000000n +let () = check ~divisor:0x120f735945bbc99n +let () = check ~divisor:0x200000000000000n +let () = check ~divisor:0x3039469e51b64a2n +let () = check ~divisor:0x400000000000000n +let () = check ~divisor:0x5a3c0b43e9a2efcn +let () = check ~divisor:0x800000000000000n +let () = check ~divisor:0xe8a22c0435b87b6n +let () = check ~divisor:0x1000000000000000n +let () = check ~divisor:0x1fbb93be9aaf0524n +let () = check ~divisor:0x2000000000000000n +let () = check ~divisor:0x2e9cce8cd5e94a7dn +let () = check ~divisor:0x4000000000000000n +let () = check ~divisor:0x5b14e7c342ea8ea7n +let () = check ~divisor:0x69c59104b185e6c4n +let () = check ~divisor:0x75ef5d214801e93cn +let () = check ~divisor:0x799689af7dbe5446n +let () = check ~divisor:0x7d95c4665cbcb9c3n +let () = check ~divisor:0x7e5e05e4253316b3n +let () = check ~divisor:0x7f3f1cf2a9259909n +let () = check ~divisor:0x7fb8a694f7cfaf74n +let () = check ~divisor:0x7fdef9649771cd3fn +let () = check ~divisor:0x7fe2434086fad31dn +let () = check ~divisor:0x7ff605bc4d7fe111n +let () = check ~divisor:0x7ffa5eac37685893n +let () = check ~divisor:0x7ffd535d13bd148bn +let () = check ~divisor:0x7ffe0695587e72cfn +let () = check ~divisor:0x7fff5a52b5d17bccn +let () = check ~divisor:0x7fff997b597c31a9n +let () = check ~divisor:0x7fffd087a97e11cbn +let () = check ~divisor:0x7fffec0450d9ef2cn +let () = check ~divisor:0x7ffff778cb53dfd0n +let () = check ~divisor:0x7ffffacb58cdaf74n +let () = check ~divisor:0x7ffffc3dcdbe97c7n +let () = check ~divisor:0x7ffffebc41ebb444n +let () = check ~divisor:0x7fffff613dc9052en +let () = check ~divisor:0x7fffff80ce85747cn +let () = check ~divisor:0x7fffffd022afc735n +let () = check ~divisor:0x7fffffe1cb8677ben +let () = check ~divisor:0x7ffffff7b4e38518n +let () = check ~divisor:0x7ffffff968923187n +let () = check ~divisor:0x7ffffffd2da09b66n +let () = check ~divisor:0x7ffffffee3a78db9n +let () = check ~divisor:0x7fffffff073a7723n +let () = check ~divisor:0x7fffffffb13e2009n +let () = check ~divisor:0x7fffffffd91672b1n +let () = check ~divisor:0x7fffffffef5ddd1en +let () = check ~divisor:0x7ffffffff0b85de5n +let () = check ~divisor:0x7ffffffffa24db09n +let () = check ~divisor:0x7ffffffffc646ef8n +let () = check ~divisor:0x7ffffffffee78250n +let () = check ~divisor:0x7fffffffff2a9595n +let () = check ~divisor:0x7fffffffff899f3an +let () = check ~divisor:0x7fffffffffd826b9n +let () = check ~divisor:0x7fffffffffe87226n +let () = check ~divisor:0x7ffffffffff75f7dn +let () = check ~divisor:0x7ffffffffff8229an +let () = check ~divisor:0x7ffffffffffc5874n +let () = check ~divisor:0x7ffffffffffe7639n +let () = check ~divisor:0x7fffffffffff1ec4n +let () = check ~divisor:0x7fffffffffff96e7n +let () = check ~divisor:0x7fffffffffffd43cn +let () = check ~divisor:0x7fffffffffffecf1n +let () = check ~divisor:0x7ffffffffffff4a2n +let () = check ~divisor:0x7ffffffffffffae8n +let () = check ~divisor:0x7ffffffffffffd12n +let () = check ~divisor:0x7ffffffffffffe26n +let () = check ~divisor:0x7fffffffffffff11n +let () = check ~divisor:0x7fffffffffffffa7n +let () = check ~divisor:0x7fffffffffffffc7n +let () = check ~divisor:0x7fffffffffffffe3n +let () = check ~divisor:0x7ffffffffffffff4n +let () = check ~divisor:0x7ffffffffffffff8n +let () = check ~divisor:0x7ffffffffffffffdn +let () = check ~divisor:0x7ffffffffffffffen +let () = check ~divisor:0x7fffffffffffffffn +let () = check ~divisor:0x8000000000000000n +let () = check ~divisor:0x8000000000000001n +let () = check ~divisor:0x8000000000000002n +let () = check ~divisor:0x8000000000000005n +let () = check ~divisor:0x800000000000000dn +let () = check ~divisor:0x8000000000000017n +let () = check ~divisor:0x8000000000000028n +let () = check ~divisor:0x800000000000005an +let () = check ~divisor:0x80000000000000e2n +let () = check ~divisor:0x80000000000001e3n +let () = check ~divisor:0x80000000000002dbn +let () = check ~divisor:0x80000000000006efn +let () = check ~divisor:0x80000000000009e2n +let () = check ~divisor:0x80000000000010dan +let () = check ~divisor:0x80000000000025c6n +let () = check ~divisor:0x8000000000006a1dn +let () = check ~divisor:0x8000000000009f0fn +let () = check ~divisor:0x80000000000192d8n +let () = check ~divisor:0x8000000000026c30n +let () = check ~divisor:0x80000000000497d7n +let () = check ~divisor:0x80000000000d9189n +let () = check ~divisor:0x8000000000114ec3n +let () = check ~divisor:0x8000000000305e32n +let () = check ~divisor:0x8000000000405a0fn +let () = check ~divisor:0x8000000000a3b89an +let () = check ~divisor:0x8000000001416aacn +let () = check ~divisor:0x800000000236f72dn +let () = check ~divisor:0x80000000041e824fn +let () = check ~divisor:0x800000000ace82edn +let () = check ~divisor:0x800000001baeef0cn +let () = check ~divisor:0x800000002f370abfn +let () = check ~divisor:0x800000006f4eea4an +let () = check ~divisor:0x80000000ee73e06cn +let () = check ~divisor:0x8000000163ff75cdn +let () = check ~divisor:0x80000002c054c81fn +let () = check ~divisor:0x800000052e7d2f21n +let () = check ~divisor:0x8000000d8a7e1bacn +let () = check ~divisor:0x800000103dd26b53n +let () = check ~divisor:0x800000223a470101n +let () = check ~divisor:0x8000007fa4045f80n +let () = check ~divisor:0x800000e45d6fd0den +let () = check ~divisor:0x800001e78d8346d6n +let () = check ~divisor:0x8000029b1675a7a8n +let () = check ~divisor:0x8000053849ced170n +let () = check ~divisor:0x80000c68934248b4n +let () = check ~divisor:0x800015b93f5ea575n +let () = check ~divisor:0x8000222ac6abfce3n +let () = check ~divisor:0x800071767fcd2050n +let () = check ~divisor:0x8000dc7d0d078691n +let () = check ~divisor:0x8001c6d218244d58n +let () = check ~divisor:0x8002c17faae76758n +let () = check ~divisor:0x80067449a16e79d1n +let () = check ~divisor:0x80095c91235e8715n +let () = check ~divisor:0x8014ad09556ad699n +let () = check ~divisor:0x8038d558ee7f2b82n +let () = check ~divisor:0x8068ba2ea24e6b16n +let () = check ~divisor:0x80d635ef2e7f90d8n +let () = check ~divisor:0x813b4c28ac280801n +let () = check ~divisor:0x820afdd334b1649en +let () = check ~divisor:0x87cfe1f0910cc176n +let () = check ~divisor:0x8ba913d5cdea6590n +let () = check ~divisor:0x9587999411c567ben +let () = check ~divisor:0xb5f5db077018f8c8n +let () = check ~divisor:0xcfe662f0c82e6584n +let () = check ~divisor:0xe98376a7e310494an +let () = check ~divisor:0xf52637e14e4cd80en +let () = check ~divisor:0xf92a69c1da392d64n +let () = check ~divisor:0xfdf40e66c7956c47n +let () = check ~divisor:0xfea5fcdd8582c81bn +let () = check ~divisor:0xff2ef1ffe1d2a282n +let () = check ~divisor:0xffa815c4429b0c98n +let () = check ~divisor:0xffc45909b9012c9en +let () = check ~divisor:0xffe8e9a5fce64df8n +let () = check ~divisor:0xfff08241e22d092en +let () = check ~divisor:0xfffad56035621e99n +let () = check ~divisor:0xfffd47754fafaf91n +let () = check ~divisor:0xfffe719238e7a731n +let () = check ~divisor:0xffff47f0f40dd886n +let () = check ~divisor:0xffff9ab441ef092en +let () = check ~divisor:0xffffdf57b79f098cn +let () = check ~divisor:0xffffead156a3e7c1n +let () = check ~divisor:0xfffff5e3c70abdc8n +let () = check ~divisor:0xfffff866180fd19cn +let () = check ~divisor:0xfffffd5287159496n +let () = check ~divisor:0xfffffecf8400bd7en +let () = check ~divisor:0xffffff6d01927255n +let () = check ~divisor:0xffffff81fbc885b5n +let () = check ~divisor:0xffffffcf41c5afd0n +let () = check ~divisor:0xffffffe17bb98621n +let () = check ~divisor:0xfffffff6cdf34b1bn +let () = check ~divisor:0xfffffffb55ba25d3n +let () = check ~divisor:0xfffffffde54a6ad8n +let () = check ~divisor:0xfffffffe3f4de45fn +let () = check ~divisor:0xffffffff11069f3bn +let () = check ~divisor:0xffffffffba8fb1dcn +let () = check ~divisor:0xffffffffd78c6873n +let () = check ~divisor:0xffffffffe8de94f9n +let () = check ~divisor:0xfffffffff66a8bdbn +let () = check ~divisor:0xfffffffff8658c5dn +let () = check ~divisor:0xfffffffffd6cf681n +let () = check ~divisor:0xfffffffffeb11b5an +let () = check ~divisor:0xffffffffff59ed0cn +let () = check ~divisor:0xffffffffff992755n +let () = check ~divisor:0xffffffffffc31c58n +let () = check ~divisor:0xffffffffffedb322n +let () = check ~divisor:0xfffffffffff484f2n +let () = check ~divisor:0xfffffffffff8208fn +let () = check ~divisor:0xfffffffffffcdaa9n +let () = check ~divisor:0xfffffffffffe7764n +let () = check ~divisor:0xffffffffffff7710n +let () = check ~divisor:0xffffffffffffa7abn +let () = check ~divisor:0xffffffffffffd4f3n +let () = check ~divisor:0xffffffffffffe767n +let () = check ~divisor:0xfffffffffffff299n +let () = check ~divisor:0xfffffffffffffb81n +let () = check ~divisor:0xfffffffffffffc92n +let () = check ~divisor:0xfffffffffffffeaan +let () = check ~divisor:0xffffffffffffff40n +let () = check ~divisor:0xffffffffffffffb6n +let () = check ~divisor:0xffffffffffffffd1n +let () = check ~divisor:0xffffffffffffffe2n +let () = check ~divisor:0xfffffffffffffff4n +let () = check ~divisor:0xfffffffffffffff8n +let () = check ~divisor:0xfffffffffffffffcn +let () = check ~divisor:0xfffffffffffffffen +let () = check ~divisor:0xffffffffffffffffn From f1a071b61c0bf4bd51fc6b2315ca7f4463652980 Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Tue, 21 Jan 2025 10:58:42 -0500 Subject: [PATCH 5/9] re-added comment with disclaimer for d>1 --- backend/cmm_helpers.ml | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index 63b4a27f27..5154913cf5 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -575,6 +575,56 @@ let divimm_parameters d = in loop (size - 1) (udivmod min_int anc) (udivmod min_int ad) +(* For d > 1, the result [(m, p)] of [divimm_parameters d] satisfies the following + inequality: + + 2^(wordsize + p) < m * d <= 2^(wordsize + p) + 2^(p + 1) (i) + + from which it follows that + + floor(n / d) = floor(n * m / 2^(wordsize+p)), if 0 <= n < 2^(wordsize-1) + + ceil(n / d) = floor(n * m / 2^(wordsize+p)) + 1, if -2^(wordsize-1) <= n < 0 + + The correctness condition (i) above can be checked by the code below. It was + exhaustively tested for values of d from 2 to 10^9 in the wordsize = 64 + case. + + * let add2 (xh, xl) (yh, yl) = + * let zl = add xl yl and zh = add xh yh in + * (if ucompare zl xl < 0 then succ zh else zh), zl + * + * let shl2 (xh, xl) n = + * assert (0 < n && n < size + size); + * if n < size + * then + * logor (shift_left xh n) (shift_right_logical xl (size - n)), + * shift_left xl n + * else shift_left xl (n - size), 0n + * + * let mul2 x y = + * let halfsize = size / 2 in + * let halfmask = pred (shift_left 1n halfsize) in + * let xl = logand x halfmask and xh = shift_right_logical x halfsize in + * let yl = logand y halfmask and yh = shift_right_logical y halfsize in + * add2 + * (mul xh yh, 0n) + * (add2 + * (shl2 (0n, mul xl yh) halfsize) + * (add2 (shl2 (0n, mul xh yl) halfsize) (0n, mul xl yl))) + * + * let ucompare2 (xh, xl) (yh, yl) = + * let c = ucompare xh yh in + * if c = 0 then ucompare xl yl else c + * + * let validate d m p = + * let md = mul2 m d in + * let one2 = 0n, 1n in + * let twoszp = shl2 one2 (size + p) in + * let twop1 = shl2 one2 (p + 1) in + * ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0 + *) + let raise_symbol dbg symb = Cop (Craise Lambda.Raise_regular, [Cconst_symbol (global_symbol symb, dbg)], dbg) From c5ab6a261595b3326dd22323434a2bff58100d83 Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Tue, 21 Jan 2025 10:59:37 -0500 Subject: [PATCH 6/9] moved comment --- backend/cmm_helpers.ml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index 5154913cf5..99ab8f0cbf 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -750,10 +750,7 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = | _, Some n -> if n = Nativeint.min_int then - (* [divisor] must be positive be here since we already handled zero and - min_int (the only negative power of 2). - - Similarly to the division by min_int almost always being 0, modulo + (* Similarly to the division by min_int almost always being 0, modulo min_int is almost always the identity, the exception being when the divisor is min_int *) bind "dividend" c1 (fun c1 -> @@ -768,6 +765,8 @@ let mod_int ?dividend_cannot_be_min_int c1 c2 dbg = Any )) else if is_power_of_2_or_zero n then + (* [divisor] must be positive be here since we already handled zero and + min_int (the only negative power of 2). *) let l = Misc.log2_nativeint n in (* Algorithm: From 7033cfd90c99eebb8b6f44857ee32a662f117ace Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Tue, 21 Jan 2025 11:40:59 -0500 Subject: [PATCH 7/9] updated division tests --- backend/cmm_helpers.ml | 10 +- testsuite/tests/basic/division_by_constant.ml | 1245 +++++++++++++---- 2 files changed, 986 insertions(+), 269 deletions(-) diff --git a/backend/cmm_helpers.ml b/backend/cmm_helpers.ml index 99ab8f0cbf..0a25dfcae1 100644 --- a/backend/cmm_helpers.ml +++ b/backend/cmm_helpers.ml @@ -592,7 +592,7 @@ let divimm_parameters d = * let add2 (xh, xl) (yh, yl) = * let zl = add xl yl and zh = add xh yh in - * (if ucompare zl xl < 0 then succ zh else zh), zl + * (if unsigned_compare zl xl < 0 then succ zh else zh), zl * * let shl2 (xh, xl) n = * assert (0 < n && n < size + size); @@ -613,16 +613,16 @@ let divimm_parameters d = * (shl2 (0n, mul xl yh) halfsize) * (add2 (shl2 (0n, mul xh yl) halfsize) (0n, mul xl yl))) * - * let ucompare2 (xh, xl) (yh, yl) = - * let c = ucompare xh yh in - * if c = 0 then ucompare xl yl else c + * let unsigned_compare2 (xh, xl) (yh, yl) = + * let c = unsigned_compare xh yh in + * if c = 0 then unsigned_compare xl yl else c * * let validate d m p = * let md = mul2 m d in * let one2 = 0n, 1n in * let twoszp = shl2 one2 (size + p) in * let twop1 = shl2 one2 (p + 1) in - * ucompare2 twoszp md < 0 && ucompare2 md (add2 twoszp twop1) <= 0 + * unsigned_compare2 twoszp md < 0 && unsigned_compare2 md (add2 twoszp twop1) <= 0 *) let raise_symbol dbg symb = diff --git a/testsuite/tests/basic/division_by_constant.ml b/testsuite/tests/basic/division_by_constant.ml index ca70d1aeb6..f9b2c654c2 100644 --- a/testsuite/tests/basic/division_by_constant.ml +++ b/testsuite/tests/basic/division_by_constant.ml @@ -4,363 +4,1080 @@ open Nativeint let test_cases = - let int_size = Nativeint.size in - let rng = Random.State.make [| int_size |] in + let rng = Random.State.make_self_init () in (* sparse test cases, concentrated around 0, the limits, and powers of 2 *) - List.init (int_size - 1) (fun size -> - let bit = (shift_left one) size in - let rand () = - Random.State.nativeint_in_range rng - ~min:(shift_right_logical bit 1) - ~max:(pred bit) - in - [ bit; - rand (); - lognot (rand ()); - (sub max_int) (rand ()); - lognot ((sub max_int) (rand ())) ]) - |> List.concat - |> List.sort_uniq compare + List.init (size - 1) (fun size -> + let bit = (shift_left one) size in + let rand () = + Random.State.nativeint_in_range rng + ~min:(shift_right_logical bit 1) + ~max:(pred bit) + in + ListLabels.concat_map + [pred bit; bit; succ bit; rand ()] + ~f:(fun x -> [x; lognot x; sub max_int x; lognot (sub max_int x)])) + |> List.concat |> List.sort_uniq compare -let[@inline never] check ~dividend ~divisor ~quotient ~remainder = +let[@inline never] check_result ~dividend ~divisor ~quotient ~remainder = assert (divisor <> 0n); assert (quotient = div dividend divisor); assert (remainder = rem dividend divisor); assert (dividend = add (mul quotient divisor) remainder); - assert - (if divisor = min_int - then remainder <> min_int - else abs remainder < abs divisor); + assert ( + if divisor = min_int + then remainder <> min_int + else abs remainder < abs divisor); let[@inline] sign x = if x < 0n then -1 else if x = 0n then 0 else 1 in assert (remainder = 0n || sign remainder = sign dividend) +(* test that the order of side effects are preserved in all cases *) + +let[@inline never] test_effects f ~expect = + let rev_effects = ref [] in + let result = + match f ~push:(fun x -> rev_effects := x :: !rev_effects) with + | x -> `result x + | exception exn -> `exn exn + in + let effects = List.rev (result :: !rev_effects) in + assert (effects = expect) + +let () = + test_effects + (fun ~push -> + let[@inline never] divide_by_3 x = + div + (push `divisor; + x) + (push `dividend; + 3n) + in + divide_by_3 42n) + ~expect:[`dividend; `divisor; `result 14n]; + test_effects + (fun ~push -> + div + (push `divisor; + 42n) + (push `dividend; + 3n)) + ~expect:[`dividend; `divisor; `result 14n]; + test_effects + (fun ~push -> + let[@inline never] divide_by_0 x = + div + (push `divisor; + x) + (push `dividend; + 0n) + in + divide_by_0 42n) + ~expect:[`dividend; `divisor; `exn Division_by_zero]; + test_effects (fun ~push -> + div + (push `divisor; + 42n) + (push `dividend; + 0n)) + ~expect:[`dividend; `divisor; `exn Division_by_zero] + + +(* Since [check] is always inlined, the division-by-constant optimization should + trigger in every case when called with a literal ~divisor +*) let[@inline always] [@specialise always] check ~divisor = + let[@inline always] quotient ~dividend = div dividend divisor in + let[@inline always] remainder ~dividend = rem dividend divisor in ListLabels.iter test_cases ~f:(fun dividend -> - (Sys.opaque_identity check) - ~dividend - ~divisor - ~quotient:(div dividend divisor) - ~remainder:(rem dividend divisor) - ) + check_result ~dividend ~divisor ~quotient:(quotient ~dividend) + ~remainder:(remainder ~dividend)) (* manual tests *) + let () = check ~divisor:3n let () = check ~divisor:(-3n) +let () = check ~divisor:5n +let () = check ~divisor:(-5n) +let () = check ~divisor:7n +let () = check ~divisor:(-7n) let () = check ~divisor:65537n let () = check ~divisor:(-65537n) -(* checks generated by test_cases. These get inlined so the division by a constant is - replaced *) +(* These tests are generated by a manual run of test_cases with seed + [[| int_size |]] to test against a hard-coded list of dividends. *) let () = check ~divisor:0x1n let () = check ~divisor:0x2n +let () = check ~divisor:0x3n let () = check ~divisor:0x4n +let () = check ~divisor:0x5n let () = check ~divisor:0x7n let () = check ~divisor:0x8n -let () = check ~divisor:0xdn +let () = check ~divisor:0x9n +let () = check ~divisor:0xen +let () = check ~divisor:0xfn let () = check ~divisor:0x10n +let () = check ~divisor:0x11n let () = check ~divisor:0x15n +let () = check ~divisor:0x1fn let () = check ~divisor:0x20n -let () = check ~divisor:0x2an +let () = check ~divisor:0x21n +let () = check ~divisor:0x39n +let () = check ~divisor:0x3fn let () = check ~divisor:0x40n -let () = check ~divisor:0x4fn +let () = check ~divisor:0x41n +let () = check ~divisor:0x54n +let () = check ~divisor:0x7fn let () = check ~divisor:0x80n -let () = check ~divisor:0xa3n +let () = check ~divisor:0x81n +let () = check ~divisor:0xa8n +let () = check ~divisor:0xffn let () = check ~divisor:0x100n -let () = check ~divisor:0x154n +let () = check ~divisor:0x101n +let () = check ~divisor:0x1b2n +let () = check ~divisor:0x1ffn let () = check ~divisor:0x200n -let () = check ~divisor:0x339n +let () = check ~divisor:0x201n +let () = check ~divisor:0x2c7n +let () = check ~divisor:0x3ffn let () = check ~divisor:0x400n -let () = check ~divisor:0x6cfn +let () = check ~divisor:0x401n +let () = check ~divisor:0x4d6n +let () = check ~divisor:0x7ffn let () = check ~divisor:0x800n -let () = check ~divisor:0x820n +let () = check ~divisor:0x801n +let () = check ~divisor:0xb15n +let () = check ~divisor:0xfffn let () = check ~divisor:0x1000n -let () = check ~divisor:0x107an +let () = check ~divisor:0x1001n +let () = check ~divisor:0x1017n +let () = check ~divisor:0x1fffn let () = check ~divisor:0x2000n -let () = check ~divisor:0x3334n +let () = check ~divisor:0x2001n +let () = check ~divisor:0x33fbn +let () = check ~divisor:0x3fffn let () = check ~divisor:0x4000n -let () = check ~divisor:0x7b3an +let () = check ~divisor:0x4001n +let () = check ~divisor:0x45bfn +let () = check ~divisor:0x7fffn let () = check ~divisor:0x8000n -let () = check ~divisor:0xb205n +let () = check ~divisor:0x8001n +let () = check ~divisor:0x846dn +let () = check ~divisor:0xffffn let () = check ~divisor:0x10000n -let () = check ~divisor:0x18e6fn +let () = check ~divisor:0x10001n +let () = check ~divisor:0x199dbn +let () = check ~divisor:0x1ffffn let () = check ~divisor:0x20000n -let () = check ~divisor:0x3efc3n +let () = check ~divisor:0x20001n +let () = check ~divisor:0x301f3n +let () = check ~divisor:0x3ffffn let () = check ~divisor:0x40000n -let () = check ~divisor:0x429bfn +let () = check ~divisor:0x40001n +let () = check ~divisor:0x5252dn +let () = check ~divisor:0x7ffffn let () = check ~divisor:0x80000n -let () = check ~divisor:0x8fcaen +let () = check ~divisor:0x80001n +let () = check ~divisor:0x853f7n +let () = check ~divisor:0xfffffn let () = check ~divisor:0x100000n -let () = check ~divisor:0x16d760n +let () = check ~divisor:0x100001n +let () = check ~divisor:0x17364cn +let () = check ~divisor:0x1fffffn let () = check ~divisor:0x200000n -let () = check ~divisor:0x3c068en +let () = check ~divisor:0x200001n +let () = check ~divisor:0x2c0b6dn +let () = check ~divisor:0x3fffffn let () = check ~divisor:0x400000n -let () = check ~divisor:0x773070n +let () = check ~divisor:0x400001n +let () = check ~divisor:0x472c65n +let () = check ~divisor:0x7fffffn let () = check ~divisor:0x800000n -let () = check ~divisor:0xf21538n +let () = check ~divisor:0x800001n +let () = check ~divisor:0xc922c8n +let () = check ~divisor:0xffffffn let () = check ~divisor:0x1000000n -let () = check ~divisor:0x13f99d3n +let () = check ~divisor:0x1000001n +let () = check ~divisor:0x13db6b8n +let () = check ~divisor:0x1ffffffn let () = check ~divisor:0x2000000n -let () = check ~divisor:0x3846a5en +let () = check ~divisor:0x2000001n +let () = check ~divisor:0x234316en +let () = check ~divisor:0x3ffffffn let () = check ~divisor:0x4000000n -let () = check ~divisor:0x5fab3ffn +let () = check ~divisor:0x4000001n +let () = check ~divisor:0x6417e4an +let () = check ~divisor:0x7ffffffn let () = check ~divisor:0x8000000n -let () = check ~divisor:0xf4a77f8n +let () = check ~divisor:0x8000001n +let () = check ~divisor:0xf42bd1an +let () = check ~divisor:0xfffffffn let () = check ~divisor:0x10000000n -let () = check ~divisor:0x10fb6962n +let () = check ~divisor:0x10000001n +let () = check ~divisor:0x157f83d8n +let () = check ~divisor:0x1fffffffn let () = check ~divisor:0x20000000n -let () = check ~divisor:0x3bcd549fn +let () = check ~divisor:0x20000001n +let () = check ~divisor:0x23fc9a89n +let () = check ~divisor:0x3fffffffn let () = check ~divisor:0x40000000n -let () = check ~divisor:0x4f952039n +let () = check ~divisor:0x40000001n +let () = check ~divisor:0x606407cfn +let () = check ~divisor:0x7fffffffn let () = check ~divisor:0x80000000n -let () = check ~divisor:0xeebeb75bn +let () = check ~divisor:0x80000001n +let () = check ~divisor:0xff459362n +let () = check ~divisor:0xffffffffn let () = check ~divisor:0x100000000n -let () = check ~divisor:0x18ec33361n +let () = check ~divisor:0x100000001n +let () = check ~divisor:0x16d2325een +let () = check ~divisor:0x1ffffffffn let () = check ~divisor:0x200000000n -let () = check ~divisor:0x3242a7138n +let () = check ~divisor:0x200000001n +let () = check ~divisor:0x215c110bfn +let () = check ~divisor:0x3ffffffffn let () = check ~divisor:0x400000000n -let () = check ~divisor:0x6bfbaac2fn +let () = check ~divisor:0x400000001n +let () = check ~divisor:0x5027c5723n +let () = check ~divisor:0x7ffffffffn let () = check ~divisor:0x800000000n -let () = check ~divisor:0x8a8c7567dn +let () = check ~divisor:0x800000001n +let () = check ~divisor:0xd4d0827e3n +let () = check ~divisor:0xfffffffffn let () = check ~divisor:0x1000000000n -let () = check ~divisor:0x1027b086b6n +let () = check ~divisor:0x1000000001n +let () = check ~divisor:0x15d1d001d9n +let () = check ~divisor:0x1fffffffffn let () = check ~divisor:0x2000000000n -let () = check ~divisor:0x28474c2119n +let () = check ~divisor:0x2000000001n +let () = check ~divisor:0x2820fa6d55n +let () = check ~divisor:0x3fffffffffn let () = check ~divisor:0x4000000000n -let () = check ~divisor:0x7a93d7fe87n +let () = check ~divisor:0x4000000001n +let () = check ~divisor:0x4bfe819254n +let () = check ~divisor:0x7fffffffffn let () = check ~divisor:0x8000000000n -let () = check ~divisor:0xfb4c23c489n +let () = check ~divisor:0x8000000001n +let () = check ~divisor:0xd963cf14dbn +let () = check ~divisor:0xffffffffffn let () = check ~divisor:0x10000000000n -let () = check ~divisor:0x1f89f89e294n +let () = check ~divisor:0x10000000001n +let () = check ~divisor:0x140e77596edn +let () = check ~divisor:0x1ffffffffffn let () = check ~divisor:0x20000000000n -let () = check ~divisor:0x355e3337296n +let () = check ~divisor:0x20000000001n +let () = check ~divisor:0x2f02862416dn +let () = check ~divisor:0x3ffffffffffn let () = check ~divisor:0x40000000000n -let () = check ~divisor:0x629bf8bccb0n +let () = check ~divisor:0x40000000001n +let () = check ~divisor:0x4d6529dd139n +let () = check ~divisor:0x7ffffffffffn let () = check ~divisor:0x80000000000n -let () = check ~divisor:0xbfe906f1b92n +let () = check ~divisor:0x80000000001n +let () = check ~divisor:0xbc7a5d6d2efn +let () = check ~divisor:0xfffffffffffn let () = check ~divisor:0x100000000000n -let () = check ~divisor:0x191407f71472n +let () = check ~divisor:0x100000000001n +let () = check ~divisor:0x13e1e859d117n +let () = check ~divisor:0x1fffffffffffn let () = check ~divisor:0x200000000000n -let () = check ~divisor:0x36b5f12f9313n +let () = check ~divisor:0x200000000001n +let () = check ~divisor:0x37449ec5407en +let () = check ~divisor:0x3fffffffffffn let () = check ~divisor:0x400000000000n -let () = check ~divisor:0x5e3f23f0dddan +let () = check ~divisor:0x400000000001n +let () = check ~divisor:0x4e37e6399ecfn +let () = check ~divisor:0x7fffffffffffn let () = check ~divisor:0x800000000000n -let () = check ~divisor:0xbef5e282e032n +let () = check ~divisor:0x800000000001n +let () = check ~divisor:0xbd55865839e2n +let () = check ~divisor:0xffffffffffffn let () = check ~divisor:0x1000000000000n -let () = check ~divisor:0x18a24ff8561ecn +let () = check ~divisor:0x1000000000001n +let () = check ~divisor:0x1c863e16a635dn +let () = check ~divisor:0x1ffffffffffffn let () = check ~divisor:0x2000000000000n -let () = check ~divisor:0x2369e32fbc992n +let () = check ~divisor:0x2000000000001n +let () = check ~divisor:0x31b40893d1566n +let () = check ~divisor:0x3ffffffffffffn let () = check ~divisor:0x4000000000000n -let () = check ~divisor:0x4ef620f95b74fn +let () = check ~divisor:0x4000000000001n +let () = check ~divisor:0x7868b5768b820n +let () = check ~divisor:0x7ffffffffffffn let () = check ~divisor:0x8000000000000n -let () = check ~divisor:0x90411098f476en +let () = check ~divisor:0x8000000000001n +let () = check ~divisor:0xc98a65538b0dan +let () = check ~divisor:0xfffffffffffffn let () = check ~divisor:0x10000000000000n -let () = check ~divisor:0x10f1bf16dd463bn +let () = check ~divisor:0x10000000000001n +let () = check ~divisor:0x19dfa30e2bc30en +let () = check ~divisor:0x1fffffffffffffn let () = check ~divisor:0x20000000000000n -let () = check ~divisor:0x34a2bdb789e08dn +let () = check ~divisor:0x20000000000001n +let () = check ~divisor:0x2141bc1b7fd898n +let () = check ~divisor:0x3fffffffffffffn let () = check ~divisor:0x40000000000000n -let () = check ~divisor:0x5c6e3e4595806en +let () = check ~divisor:0x40000000000001n +let () = check ~divisor:0x47a1f2eef0007an +let () = check ~divisor:0x7fffffffffffffn let () = check ~divisor:0x80000000000000n -let () = check ~divisor:0xac2cb82fecde51n +let () = check ~divisor:0x80000000000001n +let () = check ~divisor:0xdd74b0801605c6n +let () = check ~divisor:0xffffffffffffffn let () = check ~divisor:0x100000000000000n -let () = check ~divisor:0x120f735945bbc99n +let () = check ~divisor:0x100000000000001n +let () = check ~divisor:0x1828a556a36abc3n +let () = check ~divisor:0x1ffffffffffffffn let () = check ~divisor:0x200000000000000n -let () = check ~divisor:0x3039469e51b64a2n +let () = check ~divisor:0x200000000000001n +let () = check ~divisor:0x2a42f222c7d6b0cn +let () = check ~divisor:0x3ffffffffffffffn let () = check ~divisor:0x400000000000000n -let () = check ~divisor:0x5a3c0b43e9a2efcn +let () = check ~divisor:0x400000000000001n +let () = check ~divisor:0x44578a4bd765334n +let () = check ~divisor:0x7ffffffffffffffn let () = check ~divisor:0x800000000000000n -let () = check ~divisor:0xe8a22c0435b87b6n +let () = check ~divisor:0x800000000000001n +let () = check ~divisor:0xf3c26b221ceaa1dn +let () = check ~divisor:0xfffffffffffffffn let () = check ~divisor:0x1000000000000000n -let () = check ~divisor:0x1fbb93be9aaf0524n +let () = check ~divisor:0x1000000000000001n +let () = check ~divisor:0x10056da6bfdde918n +let () = check ~divisor:0x1fffffffffffffffn let () = check ~divisor:0x2000000000000000n -let () = check ~divisor:0x2e9cce8cd5e94a7dn +let () = check ~divisor:0x2000000000000001n +let () = check ~divisor:0x2d145e4f69d39854n +let () = check ~divisor:0x3ffffffffffffffen +let () = check ~divisor:0x3fffffffffffffffn let () = check ~divisor:0x4000000000000000n -let () = check ~divisor:0x5b14e7c342ea8ea7n -let () = check ~divisor:0x69c59104b185e6c4n -let () = check ~divisor:0x75ef5d214801e93cn -let () = check ~divisor:0x799689af7dbe5446n -let () = check ~divisor:0x7d95c4665cbcb9c3n -let () = check ~divisor:0x7e5e05e4253316b3n -let () = check ~divisor:0x7f3f1cf2a9259909n -let () = check ~divisor:0x7fb8a694f7cfaf74n -let () = check ~divisor:0x7fdef9649771cd3fn -let () = check ~divisor:0x7fe2434086fad31dn -let () = check ~divisor:0x7ff605bc4d7fe111n -let () = check ~divisor:0x7ffa5eac37685893n -let () = check ~divisor:0x7ffd535d13bd148bn -let () = check ~divisor:0x7ffe0695587e72cfn -let () = check ~divisor:0x7fff5a52b5d17bccn -let () = check ~divisor:0x7fff997b597c31a9n -let () = check ~divisor:0x7fffd087a97e11cbn -let () = check ~divisor:0x7fffec0450d9ef2cn -let () = check ~divisor:0x7ffff778cb53dfd0n -let () = check ~divisor:0x7ffffacb58cdaf74n -let () = check ~divisor:0x7ffffc3dcdbe97c7n -let () = check ~divisor:0x7ffffebc41ebb444n -let () = check ~divisor:0x7fffff613dc9052en -let () = check ~divisor:0x7fffff80ce85747cn -let () = check ~divisor:0x7fffffd022afc735n -let () = check ~divisor:0x7fffffe1cb8677ben -let () = check ~divisor:0x7ffffff7b4e38518n -let () = check ~divisor:0x7ffffff968923187n -let () = check ~divisor:0x7ffffffd2da09b66n -let () = check ~divisor:0x7ffffffee3a78db9n -let () = check ~divisor:0x7fffffff073a7723n -let () = check ~divisor:0x7fffffffb13e2009n -let () = check ~divisor:0x7fffffffd91672b1n -let () = check ~divisor:0x7fffffffef5ddd1en -let () = check ~divisor:0x7ffffffff0b85de5n -let () = check ~divisor:0x7ffffffffa24db09n -let () = check ~divisor:0x7ffffffffc646ef8n -let () = check ~divisor:0x7ffffffffee78250n -let () = check ~divisor:0x7fffffffff2a9595n -let () = check ~divisor:0x7fffffffff899f3an -let () = check ~divisor:0x7fffffffffd826b9n -let () = check ~divisor:0x7fffffffffe87226n -let () = check ~divisor:0x7ffffffffff75f7dn -let () = check ~divisor:0x7ffffffffff8229an -let () = check ~divisor:0x7ffffffffffc5874n -let () = check ~divisor:0x7ffffffffffe7639n -let () = check ~divisor:0x7fffffffffff1ec4n -let () = check ~divisor:0x7fffffffffff96e7n -let () = check ~divisor:0x7fffffffffffd43cn -let () = check ~divisor:0x7fffffffffffecf1n -let () = check ~divisor:0x7ffffffffffff4a2n -let () = check ~divisor:0x7ffffffffffffae8n -let () = check ~divisor:0x7ffffffffffffd12n -let () = check ~divisor:0x7ffffffffffffe26n -let () = check ~divisor:0x7fffffffffffff11n -let () = check ~divisor:0x7fffffffffffffa7n -let () = check ~divisor:0x7fffffffffffffc7n -let () = check ~divisor:0x7fffffffffffffe3n -let () = check ~divisor:0x7ffffffffffffff4n +let () = check ~divisor:0x4000000000000001n +let () = check ~divisor:0x52eba1b0962c67abn +let () = check ~divisor:0x5ffffffffffffffen +let () = check ~divisor:0x5fffffffffffffffn +let () = check ~divisor:0x6000000000000000n +let () = check ~divisor:0x6ffa9259402216e7n +let () = check ~divisor:0x6ffffffffffffffen +let () = check ~divisor:0x6fffffffffffffffn +let () = check ~divisor:0x7000000000000000n +let () = check ~divisor:0x70c3d94dde3155e2n +let () = check ~divisor:0x77fffffffffffffen +let () = check ~divisor:0x77ffffffffffffffn +let () = check ~divisor:0x7800000000000000n +let () = check ~divisor:0x7bba875b4289accbn +let () = check ~divisor:0x7bfffffffffffffen +let () = check ~divisor:0x7bffffffffffffffn +let () = check ~divisor:0x7c00000000000000n +let () = check ~divisor:0x7d5bd0ddd38294f3n +let () = check ~divisor:0x7dfffffffffffffen +let () = check ~divisor:0x7dffffffffffffffn +let () = check ~divisor:0x7e00000000000000n +let () = check ~divisor:0x7e7d75aa95c9543cn +let () = check ~divisor:0x7efffffffffffffen +let () = check ~divisor:0x7effffffffffffffn +let () = check ~divisor:0x7f00000000000000n +let () = check ~divisor:0x7f228b4f7fe9fa39n +let () = check ~divisor:0x7f7ffffffffffffen +let () = check ~divisor:0x7f7fffffffffffffn +let () = check ~divisor:0x7f80000000000000n +let () = check ~divisor:0x7fb85e0d110fff85n +let () = check ~divisor:0x7fbffffffffffffen +let () = check ~divisor:0x7fbfffffffffffffn +let () = check ~divisor:0x7fc0000000000000n +let () = check ~divisor:0x7fdebe43e4802767n +let () = check ~divisor:0x7fdffffffffffffen +let () = check ~divisor:0x7fdfffffffffffffn +let () = check ~divisor:0x7fe0000000000000n +let () = check ~divisor:0x7fe6205cf1d43cf1n +let () = check ~divisor:0x7feffffffffffffen +let () = check ~divisor:0x7fefffffffffffffn +let () = check ~divisor:0x7ff0000000000000n +let () = check ~divisor:0x7ff36759aac74f25n +let () = check ~divisor:0x7ff7fffffffffffen +let () = check ~divisor:0x7ff7ffffffffffffn +let () = check ~divisor:0x7ff8000000000000n +let () = check ~divisor:0x7ff87974a89747dfn +let () = check ~divisor:0x7ffbfffffffffffen +let () = check ~divisor:0x7ffbffffffffffffn +let () = check ~divisor:0x7ffc000000000000n +let () = check ~divisor:0x7ffce4bf76c2ea99n +let () = check ~divisor:0x7ffdfffffffffffen +let () = check ~divisor:0x7ffdffffffffffffn +let () = check ~divisor:0x7ffe000000000000n +let () = check ~divisor:0x7ffe379c1e959ca2n +let () = check ~divisor:0x7ffefffffffffffen +let () = check ~divisor:0x7ffeffffffffffffn +let () = check ~divisor:0x7fff000000000000n +let () = check ~divisor:0x7fff42aa79a7c61dn +let () = check ~divisor:0x7fff7ffffffffffen +let () = check ~divisor:0x7fff7fffffffffffn +let () = check ~divisor:0x7fff800000000000n +let () = check ~divisor:0x7fffb1c819c66130n +let () = check ~divisor:0x7fffbffffffffffen +let () = check ~divisor:0x7fffbfffffffffffn +let () = check ~divisor:0x7fffc00000000000n +let () = check ~divisor:0x7fffc8bb613abf81n +let () = check ~divisor:0x7fffdffffffffffen +let () = check ~divisor:0x7fffdfffffffffffn +let () = check ~divisor:0x7fffe00000000000n +let () = check ~divisor:0x7fffec1e17a62ee8n +let () = check ~divisor:0x7fffeffffffffffen +let () = check ~divisor:0x7fffefffffffffffn +let () = check ~divisor:0x7ffff00000000000n +let () = check ~divisor:0x7ffff4385a292d10n +let () = check ~divisor:0x7ffff7fffffffffen +let () = check ~divisor:0x7ffff7ffffffffffn +let () = check ~divisor:0x7ffff80000000000n +let () = check ~divisor:0x7ffffb29ad622ec6n +let () = check ~divisor:0x7ffffbfffffffffen +let () = check ~divisor:0x7ffffbffffffffffn +let () = check ~divisor:0x7ffffc0000000000n +let () = check ~divisor:0x7ffffd0fd79dbe92n +let () = check ~divisor:0x7ffffdfffffffffen +let () = check ~divisor:0x7ffffdffffffffffn +let () = check ~divisor:0x7ffffe0000000000n +let () = check ~divisor:0x7ffffebf188a6912n +let () = check ~divisor:0x7ffffefffffffffen +let () = check ~divisor:0x7ffffeffffffffffn +let () = check ~divisor:0x7fffff0000000000n +let () = check ~divisor:0x7fffff269c30eb24n +let () = check ~divisor:0x7fffff7ffffffffen +let () = check ~divisor:0x7fffff7fffffffffn +let () = check ~divisor:0x7fffff8000000000n +let () = check ~divisor:0x7fffffb4017e6dabn +let () = check ~divisor:0x7fffffbffffffffen +let () = check ~divisor:0x7fffffbfffffffffn +let () = check ~divisor:0x7fffffc000000000n +let () = check ~divisor:0x7fffffd7df0592aan +let () = check ~divisor:0x7fffffdffffffffen +let () = check ~divisor:0x7fffffdfffffffffn +let () = check ~divisor:0x7fffffe000000000n +let () = check ~divisor:0x7fffffea2e2ffe26n +let () = check ~divisor:0x7fffffeffffffffen +let () = check ~divisor:0x7fffffefffffffffn +let () = check ~divisor:0x7ffffff000000000n +let () = check ~divisor:0x7ffffff2b2f7d81cn +let () = check ~divisor:0x7ffffff7fffffffen +let () = check ~divisor:0x7ffffff7ffffffffn +let () = check ~divisor:0x7ffffff800000000n +let () = check ~divisor:0x7ffffffafd83a8dcn +let () = check ~divisor:0x7ffffffbfffffffen +let () = check ~divisor:0x7ffffffbffffffffn +let () = check ~divisor:0x7ffffffc00000000n +let () = check ~divisor:0x7ffffffdea3eef40n +let () = check ~divisor:0x7ffffffdfffffffen +let () = check ~divisor:0x7ffffffdffffffffn +let () = check ~divisor:0x7ffffffe00000000n +let () = check ~divisor:0x7ffffffe92dcda11n +let () = check ~divisor:0x7ffffffefffffffen +let () = check ~divisor:0x7ffffffeffffffffn +let () = check ~divisor:0x7fffffff00000000n +let () = check ~divisor:0x7fffffff00ba6c9dn +let () = check ~divisor:0x7fffffff7ffffffen +let () = check ~divisor:0x7fffffff7fffffffn +let () = check ~divisor:0x7fffffff80000000n +let () = check ~divisor:0x7fffffff9f9bf830n +let () = check ~divisor:0x7fffffffbffffffen +let () = check ~divisor:0x7fffffffbfffffffn +let () = check ~divisor:0x7fffffffc0000000n +let () = check ~divisor:0x7fffffffdc036576n +let () = check ~divisor:0x7fffffffdffffffen +let () = check ~divisor:0x7fffffffdfffffffn +let () = check ~divisor:0x7fffffffe0000000n +let () = check ~divisor:0x7fffffffea807c27n +let () = check ~divisor:0x7fffffffeffffffen +let () = check ~divisor:0x7fffffffefffffffn +let () = check ~divisor:0x7ffffffff0000000n +let () = check ~divisor:0x7ffffffff0bd42e5n +let () = check ~divisor:0x7ffffffff7fffffen +let () = check ~divisor:0x7ffffffff7ffffffn +let () = check ~divisor:0x7ffffffff8000000n +let () = check ~divisor:0x7ffffffff9be81b5n +let () = check ~divisor:0x7ffffffffbfffffen +let () = check ~divisor:0x7ffffffffbffffffn +let () = check ~divisor:0x7ffffffffc000000n +let () = check ~divisor:0x7ffffffffdcbce91n +let () = check ~divisor:0x7ffffffffdfffffen +let () = check ~divisor:0x7ffffffffdffffffn +let () = check ~divisor:0x7ffffffffe000000n +let () = check ~divisor:0x7ffffffffec24947n +let () = check ~divisor:0x7ffffffffefffffen +let () = check ~divisor:0x7ffffffffeffffffn +let () = check ~divisor:0x7fffffffff000000n +let () = check ~divisor:0x7fffffffff36dd37n +let () = check ~divisor:0x7fffffffff7ffffen +let () = check ~divisor:0x7fffffffff7fffffn +let () = check ~divisor:0x7fffffffff800000n +let () = check ~divisor:0x7fffffffffb8d39an +let () = check ~divisor:0x7fffffffffbffffen +let () = check ~divisor:0x7fffffffffbfffffn +let () = check ~divisor:0x7fffffffffc00000n +let () = check ~divisor:0x7fffffffffd3f492n +let () = check ~divisor:0x7fffffffffdffffen +let () = check ~divisor:0x7fffffffffdfffffn +let () = check ~divisor:0x7fffffffffe00000n +let () = check ~divisor:0x7fffffffffe8c9b3n +let () = check ~divisor:0x7fffffffffeffffen +let () = check ~divisor:0x7fffffffffefffffn +let () = check ~divisor:0x7ffffffffff00000n +let () = check ~divisor:0x7ffffffffff7ac08n +let () = check ~divisor:0x7ffffffffff7fffen +let () = check ~divisor:0x7ffffffffff7ffffn +let () = check ~divisor:0x7ffffffffff80000n +let () = check ~divisor:0x7ffffffffffadad2n +let () = check ~divisor:0x7ffffffffffbfffen +let () = check ~divisor:0x7ffffffffffbffffn +let () = check ~divisor:0x7ffffffffffc0000n +let () = check ~divisor:0x7ffffffffffcfe0cn +let () = check ~divisor:0x7ffffffffffdfffen +let () = check ~divisor:0x7ffffffffffdffffn +let () = check ~divisor:0x7ffffffffffe0000n +let () = check ~divisor:0x7ffffffffffe6624n +let () = check ~divisor:0x7ffffffffffefffen +let () = check ~divisor:0x7ffffffffffeffffn +let () = check ~divisor:0x7fffffffffff0000n +let () = check ~divisor:0x7fffffffffff7b92n +let () = check ~divisor:0x7fffffffffff7ffen +let () = check ~divisor:0x7fffffffffff7fffn +let () = check ~divisor:0x7fffffffffff8000n +let () = check ~divisor:0x7fffffffffffba40n +let () = check ~divisor:0x7fffffffffffbffen +let () = check ~divisor:0x7fffffffffffbfffn +let () = check ~divisor:0x7fffffffffffc000n +let () = check ~divisor:0x7fffffffffffcc04n +let () = check ~divisor:0x7fffffffffffdffen +let () = check ~divisor:0x7fffffffffffdfffn +let () = check ~divisor:0x7fffffffffffe000n +let () = check ~divisor:0x7fffffffffffefe8n +let () = check ~divisor:0x7fffffffffffeffen +let () = check ~divisor:0x7fffffffffffefffn +let () = check ~divisor:0x7ffffffffffff000n +let () = check ~divisor:0x7ffffffffffff4ean +let () = check ~divisor:0x7ffffffffffff7fen +let () = check ~divisor:0x7ffffffffffff7ffn +let () = check ~divisor:0x7ffffffffffff800n +let () = check ~divisor:0x7ffffffffffffb29n +let () = check ~divisor:0x7ffffffffffffbfen +let () = check ~divisor:0x7ffffffffffffbffn +let () = check ~divisor:0x7ffffffffffffc00n +let () = check ~divisor:0x7ffffffffffffd38n +let () = check ~divisor:0x7ffffffffffffdfen +let () = check ~divisor:0x7ffffffffffffdffn +let () = check ~divisor:0x7ffffffffffffe00n +let () = check ~divisor:0x7ffffffffffffe4dn +let () = check ~divisor:0x7ffffffffffffefen +let () = check ~divisor:0x7ffffffffffffeffn +let () = check ~divisor:0x7fffffffffffff00n +let () = check ~divisor:0x7fffffffffffff57n +let () = check ~divisor:0x7fffffffffffff7en +let () = check ~divisor:0x7fffffffffffff7fn +let () = check ~divisor:0x7fffffffffffff80n +let () = check ~divisor:0x7fffffffffffffabn +let () = check ~divisor:0x7fffffffffffffben +let () = check ~divisor:0x7fffffffffffffbfn +let () = check ~divisor:0x7fffffffffffffc0n +let () = check ~divisor:0x7fffffffffffffc6n +let () = check ~divisor:0x7fffffffffffffden +let () = check ~divisor:0x7fffffffffffffdfn +let () = check ~divisor:0x7fffffffffffffe0n +let () = check ~divisor:0x7fffffffffffffean +let () = check ~divisor:0x7fffffffffffffeen +let () = check ~divisor:0x7fffffffffffffefn +let () = check ~divisor:0x7ffffffffffffff0n +let () = check ~divisor:0x7ffffffffffffff1n +let () = check ~divisor:0x7ffffffffffffff6n +let () = check ~divisor:0x7ffffffffffffff7n let () = check ~divisor:0x7ffffffffffffff8n +let () = check ~divisor:0x7ffffffffffffffan +let () = check ~divisor:0x7ffffffffffffffbn +let () = check ~divisor:0x7ffffffffffffffcn let () = check ~divisor:0x7ffffffffffffffdn let () = check ~divisor:0x7ffffffffffffffen let () = check ~divisor:0x7fffffffffffffffn let () = check ~divisor:0x8000000000000000n let () = check ~divisor:0x8000000000000001n let () = check ~divisor:0x8000000000000002n +let () = check ~divisor:0x8000000000000003n +let () = check ~divisor:0x8000000000000004n let () = check ~divisor:0x8000000000000005n -let () = check ~divisor:0x800000000000000dn -let () = check ~divisor:0x8000000000000017n -let () = check ~divisor:0x8000000000000028n -let () = check ~divisor:0x800000000000005an -let () = check ~divisor:0x80000000000000e2n -let () = check ~divisor:0x80000000000001e3n -let () = check ~divisor:0x80000000000002dbn -let () = check ~divisor:0x80000000000006efn -let () = check ~divisor:0x80000000000009e2n -let () = check ~divisor:0x80000000000010dan -let () = check ~divisor:0x80000000000025c6n -let () = check ~divisor:0x8000000000006a1dn -let () = check ~divisor:0x8000000000009f0fn -let () = check ~divisor:0x80000000000192d8n -let () = check ~divisor:0x8000000000026c30n -let () = check ~divisor:0x80000000000497d7n -let () = check ~divisor:0x80000000000d9189n -let () = check ~divisor:0x8000000000114ec3n -let () = check ~divisor:0x8000000000305e32n -let () = check ~divisor:0x8000000000405a0fn -let () = check ~divisor:0x8000000000a3b89an -let () = check ~divisor:0x8000000001416aacn -let () = check ~divisor:0x800000000236f72dn -let () = check ~divisor:0x80000000041e824fn -let () = check ~divisor:0x800000000ace82edn -let () = check ~divisor:0x800000001baeef0cn -let () = check ~divisor:0x800000002f370abfn -let () = check ~divisor:0x800000006f4eea4an -let () = check ~divisor:0x80000000ee73e06cn -let () = check ~divisor:0x8000000163ff75cdn -let () = check ~divisor:0x80000002c054c81fn -let () = check ~divisor:0x800000052e7d2f21n -let () = check ~divisor:0x8000000d8a7e1bacn -let () = check ~divisor:0x800000103dd26b53n -let () = check ~divisor:0x800000223a470101n -let () = check ~divisor:0x8000007fa4045f80n -let () = check ~divisor:0x800000e45d6fd0den -let () = check ~divisor:0x800001e78d8346d6n -let () = check ~divisor:0x8000029b1675a7a8n -let () = check ~divisor:0x8000053849ced170n -let () = check ~divisor:0x80000c68934248b4n -let () = check ~divisor:0x800015b93f5ea575n -let () = check ~divisor:0x8000222ac6abfce3n -let () = check ~divisor:0x800071767fcd2050n -let () = check ~divisor:0x8000dc7d0d078691n -let () = check ~divisor:0x8001c6d218244d58n -let () = check ~divisor:0x8002c17faae76758n -let () = check ~divisor:0x80067449a16e79d1n -let () = check ~divisor:0x80095c91235e8715n -let () = check ~divisor:0x8014ad09556ad699n -let () = check ~divisor:0x8038d558ee7f2b82n -let () = check ~divisor:0x8068ba2ea24e6b16n -let () = check ~divisor:0x80d635ef2e7f90d8n -let () = check ~divisor:0x813b4c28ac280801n -let () = check ~divisor:0x820afdd334b1649en -let () = check ~divisor:0x87cfe1f0910cc176n -let () = check ~divisor:0x8ba913d5cdea6590n -let () = check ~divisor:0x9587999411c567ben -let () = check ~divisor:0xb5f5db077018f8c8n -let () = check ~divisor:0xcfe662f0c82e6584n -let () = check ~divisor:0xe98376a7e310494an -let () = check ~divisor:0xf52637e14e4cd80en -let () = check ~divisor:0xf92a69c1da392d64n -let () = check ~divisor:0xfdf40e66c7956c47n -let () = check ~divisor:0xfea5fcdd8582c81bn -let () = check ~divisor:0xff2ef1ffe1d2a282n -let () = check ~divisor:0xffa815c4429b0c98n -let () = check ~divisor:0xffc45909b9012c9en -let () = check ~divisor:0xffe8e9a5fce64df8n -let () = check ~divisor:0xfff08241e22d092en -let () = check ~divisor:0xfffad56035621e99n -let () = check ~divisor:0xfffd47754fafaf91n -let () = check ~divisor:0xfffe719238e7a731n -let () = check ~divisor:0xffff47f0f40dd886n -let () = check ~divisor:0xffff9ab441ef092en -let () = check ~divisor:0xffffdf57b79f098cn -let () = check ~divisor:0xffffead156a3e7c1n -let () = check ~divisor:0xfffff5e3c70abdc8n -let () = check ~divisor:0xfffff866180fd19cn -let () = check ~divisor:0xfffffd5287159496n -let () = check ~divisor:0xfffffecf8400bd7en -let () = check ~divisor:0xffffff6d01927255n -let () = check ~divisor:0xffffff81fbc885b5n -let () = check ~divisor:0xffffffcf41c5afd0n -let () = check ~divisor:0xffffffe17bb98621n -let () = check ~divisor:0xfffffff6cdf34b1bn -let () = check ~divisor:0xfffffffb55ba25d3n -let () = check ~divisor:0xfffffffde54a6ad8n -let () = check ~divisor:0xfffffffe3f4de45fn -let () = check ~divisor:0xffffffff11069f3bn -let () = check ~divisor:0xffffffffba8fb1dcn -let () = check ~divisor:0xffffffffd78c6873n -let () = check ~divisor:0xffffffffe8de94f9n -let () = check ~divisor:0xfffffffff66a8bdbn -let () = check ~divisor:0xfffffffff8658c5dn -let () = check ~divisor:0xfffffffffd6cf681n -let () = check ~divisor:0xfffffffffeb11b5an -let () = check ~divisor:0xffffffffff59ed0cn -let () = check ~divisor:0xffffffffff992755n -let () = check ~divisor:0xffffffffffc31c58n -let () = check ~divisor:0xffffffffffedb322n -let () = check ~divisor:0xfffffffffff484f2n -let () = check ~divisor:0xfffffffffff8208fn -let () = check ~divisor:0xfffffffffffcdaa9n -let () = check ~divisor:0xfffffffffffe7764n -let () = check ~divisor:0xffffffffffff7710n -let () = check ~divisor:0xffffffffffffa7abn -let () = check ~divisor:0xffffffffffffd4f3n -let () = check ~divisor:0xffffffffffffe767n -let () = check ~divisor:0xfffffffffffff299n -let () = check ~divisor:0xfffffffffffffb81n -let () = check ~divisor:0xfffffffffffffc92n -let () = check ~divisor:0xfffffffffffffeaan -let () = check ~divisor:0xffffffffffffff40n -let () = check ~divisor:0xffffffffffffffb6n -let () = check ~divisor:0xffffffffffffffd1n -let () = check ~divisor:0xffffffffffffffe2n -let () = check ~divisor:0xfffffffffffffff4n +let () = check ~divisor:0x8000000000000007n +let () = check ~divisor:0x8000000000000008n +let () = check ~divisor:0x8000000000000009n +let () = check ~divisor:0x800000000000000en +let () = check ~divisor:0x800000000000000fn +let () = check ~divisor:0x8000000000000010n +let () = check ~divisor:0x8000000000000011n +let () = check ~divisor:0x8000000000000015n +let () = check ~divisor:0x800000000000001fn +let () = check ~divisor:0x8000000000000020n +let () = check ~divisor:0x8000000000000021n +let () = check ~divisor:0x8000000000000039n +let () = check ~divisor:0x800000000000003fn +let () = check ~divisor:0x8000000000000040n +let () = check ~divisor:0x8000000000000041n +let () = check ~divisor:0x8000000000000054n +let () = check ~divisor:0x800000000000007fn +let () = check ~divisor:0x8000000000000080n +let () = check ~divisor:0x8000000000000081n +let () = check ~divisor:0x80000000000000a8n +let () = check ~divisor:0x80000000000000ffn +let () = check ~divisor:0x8000000000000100n +let () = check ~divisor:0x8000000000000101n +let () = check ~divisor:0x80000000000001b2n +let () = check ~divisor:0x80000000000001ffn +let () = check ~divisor:0x8000000000000200n +let () = check ~divisor:0x8000000000000201n +let () = check ~divisor:0x80000000000002c7n +let () = check ~divisor:0x80000000000003ffn +let () = check ~divisor:0x8000000000000400n +let () = check ~divisor:0x8000000000000401n +let () = check ~divisor:0x80000000000004d6n +let () = check ~divisor:0x80000000000007ffn +let () = check ~divisor:0x8000000000000800n +let () = check ~divisor:0x8000000000000801n +let () = check ~divisor:0x8000000000000b15n +let () = check ~divisor:0x8000000000000fffn +let () = check ~divisor:0x8000000000001000n +let () = check ~divisor:0x8000000000001001n +let () = check ~divisor:0x8000000000001017n +let () = check ~divisor:0x8000000000001fffn +let () = check ~divisor:0x8000000000002000n +let () = check ~divisor:0x8000000000002001n +let () = check ~divisor:0x80000000000033fbn +let () = check ~divisor:0x8000000000003fffn +let () = check ~divisor:0x8000000000004000n +let () = check ~divisor:0x8000000000004001n +let () = check ~divisor:0x80000000000045bfn +let () = check ~divisor:0x8000000000007fffn +let () = check ~divisor:0x8000000000008000n +let () = check ~divisor:0x8000000000008001n +let () = check ~divisor:0x800000000000846dn +let () = check ~divisor:0x800000000000ffffn +let () = check ~divisor:0x8000000000010000n +let () = check ~divisor:0x8000000000010001n +let () = check ~divisor:0x80000000000199dbn +let () = check ~divisor:0x800000000001ffffn +let () = check ~divisor:0x8000000000020000n +let () = check ~divisor:0x8000000000020001n +let () = check ~divisor:0x80000000000301f3n +let () = check ~divisor:0x800000000003ffffn +let () = check ~divisor:0x8000000000040000n +let () = check ~divisor:0x8000000000040001n +let () = check ~divisor:0x800000000005252dn +let () = check ~divisor:0x800000000007ffffn +let () = check ~divisor:0x8000000000080000n +let () = check ~divisor:0x8000000000080001n +let () = check ~divisor:0x80000000000853f7n +let () = check ~divisor:0x80000000000fffffn +let () = check ~divisor:0x8000000000100000n +let () = check ~divisor:0x8000000000100001n +let () = check ~divisor:0x800000000017364cn +let () = check ~divisor:0x80000000001fffffn +let () = check ~divisor:0x8000000000200000n +let () = check ~divisor:0x8000000000200001n +let () = check ~divisor:0x80000000002c0b6dn +let () = check ~divisor:0x80000000003fffffn +let () = check ~divisor:0x8000000000400000n +let () = check ~divisor:0x8000000000400001n +let () = check ~divisor:0x8000000000472c65n +let () = check ~divisor:0x80000000007fffffn +let () = check ~divisor:0x8000000000800000n +let () = check ~divisor:0x8000000000800001n +let () = check ~divisor:0x8000000000c922c8n +let () = check ~divisor:0x8000000000ffffffn +let () = check ~divisor:0x8000000001000000n +let () = check ~divisor:0x8000000001000001n +let () = check ~divisor:0x80000000013db6b8n +let () = check ~divisor:0x8000000001ffffffn +let () = check ~divisor:0x8000000002000000n +let () = check ~divisor:0x8000000002000001n +let () = check ~divisor:0x800000000234316en +let () = check ~divisor:0x8000000003ffffffn +let () = check ~divisor:0x8000000004000000n +let () = check ~divisor:0x8000000004000001n +let () = check ~divisor:0x8000000006417e4an +let () = check ~divisor:0x8000000007ffffffn +let () = check ~divisor:0x8000000008000000n +let () = check ~divisor:0x8000000008000001n +let () = check ~divisor:0x800000000f42bd1an +let () = check ~divisor:0x800000000fffffffn +let () = check ~divisor:0x8000000010000000n +let () = check ~divisor:0x8000000010000001n +let () = check ~divisor:0x80000000157f83d8n +let () = check ~divisor:0x800000001fffffffn +let () = check ~divisor:0x8000000020000000n +let () = check ~divisor:0x8000000020000001n +let () = check ~divisor:0x8000000023fc9a89n +let () = check ~divisor:0x800000003fffffffn +let () = check ~divisor:0x8000000040000000n +let () = check ~divisor:0x8000000040000001n +let () = check ~divisor:0x80000000606407cfn +let () = check ~divisor:0x800000007fffffffn +let () = check ~divisor:0x8000000080000000n +let () = check ~divisor:0x8000000080000001n +let () = check ~divisor:0x80000000ff459362n +let () = check ~divisor:0x80000000ffffffffn +let () = check ~divisor:0x8000000100000000n +let () = check ~divisor:0x8000000100000001n +let () = check ~divisor:0x800000016d2325een +let () = check ~divisor:0x80000001ffffffffn +let () = check ~divisor:0x8000000200000000n +let () = check ~divisor:0x8000000200000001n +let () = check ~divisor:0x8000000215c110bfn +let () = check ~divisor:0x80000003ffffffffn +let () = check ~divisor:0x8000000400000000n +let () = check ~divisor:0x8000000400000001n +let () = check ~divisor:0x80000005027c5723n +let () = check ~divisor:0x80000007ffffffffn +let () = check ~divisor:0x8000000800000000n +let () = check ~divisor:0x8000000800000001n +let () = check ~divisor:0x8000000d4d0827e3n +let () = check ~divisor:0x8000000fffffffffn +let () = check ~divisor:0x8000001000000000n +let () = check ~divisor:0x8000001000000001n +let () = check ~divisor:0x80000015d1d001d9n +let () = check ~divisor:0x8000001fffffffffn +let () = check ~divisor:0x8000002000000000n +let () = check ~divisor:0x8000002000000001n +let () = check ~divisor:0x8000002820fa6d55n +let () = check ~divisor:0x8000003fffffffffn +let () = check ~divisor:0x8000004000000000n +let () = check ~divisor:0x8000004000000001n +let () = check ~divisor:0x8000004bfe819254n +let () = check ~divisor:0x8000007fffffffffn +let () = check ~divisor:0x8000008000000000n +let () = check ~divisor:0x8000008000000001n +let () = check ~divisor:0x800000d963cf14dbn +let () = check ~divisor:0x800000ffffffffffn +let () = check ~divisor:0x8000010000000000n +let () = check ~divisor:0x8000010000000001n +let () = check ~divisor:0x80000140e77596edn +let () = check ~divisor:0x800001ffffffffffn +let () = check ~divisor:0x8000020000000000n +let () = check ~divisor:0x8000020000000001n +let () = check ~divisor:0x800002f02862416dn +let () = check ~divisor:0x800003ffffffffffn +let () = check ~divisor:0x8000040000000000n +let () = check ~divisor:0x8000040000000001n +let () = check ~divisor:0x800004d6529dd139n +let () = check ~divisor:0x800007ffffffffffn +let () = check ~divisor:0x8000080000000000n +let () = check ~divisor:0x8000080000000001n +let () = check ~divisor:0x80000bc7a5d6d2efn +let () = check ~divisor:0x80000fffffffffffn +let () = check ~divisor:0x8000100000000000n +let () = check ~divisor:0x8000100000000001n +let () = check ~divisor:0x800013e1e859d117n +let () = check ~divisor:0x80001fffffffffffn +let () = check ~divisor:0x8000200000000000n +let () = check ~divisor:0x8000200000000001n +let () = check ~divisor:0x800037449ec5407en +let () = check ~divisor:0x80003fffffffffffn +let () = check ~divisor:0x8000400000000000n +let () = check ~divisor:0x8000400000000001n +let () = check ~divisor:0x80004e37e6399ecfn +let () = check ~divisor:0x80007fffffffffffn +let () = check ~divisor:0x8000800000000000n +let () = check ~divisor:0x8000800000000001n +let () = check ~divisor:0x8000bd55865839e2n +let () = check ~divisor:0x8000ffffffffffffn +let () = check ~divisor:0x8001000000000000n +let () = check ~divisor:0x8001000000000001n +let () = check ~divisor:0x8001c863e16a635dn +let () = check ~divisor:0x8001ffffffffffffn +let () = check ~divisor:0x8002000000000000n +let () = check ~divisor:0x8002000000000001n +let () = check ~divisor:0x80031b40893d1566n +let () = check ~divisor:0x8003ffffffffffffn +let () = check ~divisor:0x8004000000000000n +let () = check ~divisor:0x8004000000000001n +let () = check ~divisor:0x8007868b5768b820n +let () = check ~divisor:0x8007ffffffffffffn +let () = check ~divisor:0x8008000000000000n +let () = check ~divisor:0x8008000000000001n +let () = check ~divisor:0x800c98a65538b0dan +let () = check ~divisor:0x800fffffffffffffn +let () = check ~divisor:0x8010000000000000n +let () = check ~divisor:0x8010000000000001n +let () = check ~divisor:0x8019dfa30e2bc30en +let () = check ~divisor:0x801fffffffffffffn +let () = check ~divisor:0x8020000000000000n +let () = check ~divisor:0x8020000000000001n +let () = check ~divisor:0x802141bc1b7fd898n +let () = check ~divisor:0x803fffffffffffffn +let () = check ~divisor:0x8040000000000000n +let () = check ~divisor:0x8040000000000001n +let () = check ~divisor:0x8047a1f2eef0007an +let () = check ~divisor:0x807fffffffffffffn +let () = check ~divisor:0x8080000000000000n +let () = check ~divisor:0x8080000000000001n +let () = check ~divisor:0x80dd74b0801605c6n +let () = check ~divisor:0x80ffffffffffffffn +let () = check ~divisor:0x8100000000000000n +let () = check ~divisor:0x8100000000000001n +let () = check ~divisor:0x81828a556a36abc3n +let () = check ~divisor:0x81ffffffffffffffn +let () = check ~divisor:0x8200000000000000n +let () = check ~divisor:0x8200000000000001n +let () = check ~divisor:0x82a42f222c7d6b0cn +let () = check ~divisor:0x83ffffffffffffffn +let () = check ~divisor:0x8400000000000000n +let () = check ~divisor:0x8400000000000001n +let () = check ~divisor:0x844578a4bd765334n +let () = check ~divisor:0x87ffffffffffffffn +let () = check ~divisor:0x8800000000000000n +let () = check ~divisor:0x8800000000000001n +let () = check ~divisor:0x8f3c26b221ceaa1dn +let () = check ~divisor:0x8fffffffffffffffn +let () = check ~divisor:0x9000000000000000n +let () = check ~divisor:0x9000000000000001n +let () = check ~divisor:0x90056da6bfdde918n +let () = check ~divisor:0x9fffffffffffffffn +let () = check ~divisor:0xa000000000000000n +let () = check ~divisor:0xa000000000000001n +let () = check ~divisor:0xad145e4f69d39854n +let () = check ~divisor:0xbffffffffffffffen +let () = check ~divisor:0xbfffffffffffffffn +let () = check ~divisor:0xc000000000000000n +let () = check ~divisor:0xc000000000000001n +let () = check ~divisor:0xd2eba1b0962c67abn +let () = check ~divisor:0xdffffffffffffffen +let () = check ~divisor:0xdfffffffffffffffn +let () = check ~divisor:0xe000000000000000n +let () = check ~divisor:0xeffa9259402216e7n +let () = check ~divisor:0xeffffffffffffffen +let () = check ~divisor:0xefffffffffffffffn +let () = check ~divisor:0xf000000000000000n +let () = check ~divisor:0xf0c3d94dde3155e2n +let () = check ~divisor:0xf7fffffffffffffen +let () = check ~divisor:0xf7ffffffffffffffn +let () = check ~divisor:0xf800000000000000n +let () = check ~divisor:0xfbba875b4289accbn +let () = check ~divisor:0xfbfffffffffffffen +let () = check ~divisor:0xfbffffffffffffffn +let () = check ~divisor:0xfc00000000000000n +let () = check ~divisor:0xfd5bd0ddd38294f3n +let () = check ~divisor:0xfdfffffffffffffen +let () = check ~divisor:0xfdffffffffffffffn +let () = check ~divisor:0xfe00000000000000n +let () = check ~divisor:0xfe7d75aa95c9543cn +let () = check ~divisor:0xfefffffffffffffen +let () = check ~divisor:0xfeffffffffffffffn +let () = check ~divisor:0xff00000000000000n +let () = check ~divisor:0xff228b4f7fe9fa39n +let () = check ~divisor:0xff7ffffffffffffen +let () = check ~divisor:0xff7fffffffffffffn +let () = check ~divisor:0xff80000000000000n +let () = check ~divisor:0xffb85e0d110fff85n +let () = check ~divisor:0xffbffffffffffffen +let () = check ~divisor:0xffbfffffffffffffn +let () = check ~divisor:0xffc0000000000000n +let () = check ~divisor:0xffdebe43e4802767n +let () = check ~divisor:0xffdffffffffffffen +let () = check ~divisor:0xffdfffffffffffffn +let () = check ~divisor:0xffe0000000000000n +let () = check ~divisor:0xffe6205cf1d43cf1n +let () = check ~divisor:0xffeffffffffffffen +let () = check ~divisor:0xffefffffffffffffn +let () = check ~divisor:0xfff0000000000000n +let () = check ~divisor:0xfff36759aac74f25n +let () = check ~divisor:0xfff7fffffffffffen +let () = check ~divisor:0xfff7ffffffffffffn +let () = check ~divisor:0xfff8000000000000n +let () = check ~divisor:0xfff87974a89747dfn +let () = check ~divisor:0xfffbfffffffffffen +let () = check ~divisor:0xfffbffffffffffffn +let () = check ~divisor:0xfffc000000000000n +let () = check ~divisor:0xfffce4bf76c2ea99n +let () = check ~divisor:0xfffdfffffffffffen +let () = check ~divisor:0xfffdffffffffffffn +let () = check ~divisor:0xfffe000000000000n +let () = check ~divisor:0xfffe379c1e959ca2n +let () = check ~divisor:0xfffefffffffffffen +let () = check ~divisor:0xfffeffffffffffffn +let () = check ~divisor:0xffff000000000000n +let () = check ~divisor:0xffff42aa79a7c61dn +let () = check ~divisor:0xffff7ffffffffffen +let () = check ~divisor:0xffff7fffffffffffn +let () = check ~divisor:0xffff800000000000n +let () = check ~divisor:0xffffb1c819c66130n +let () = check ~divisor:0xffffbffffffffffen +let () = check ~divisor:0xffffbfffffffffffn +let () = check ~divisor:0xffffc00000000000n +let () = check ~divisor:0xffffc8bb613abf81n +let () = check ~divisor:0xffffdffffffffffen +let () = check ~divisor:0xffffdfffffffffffn +let () = check ~divisor:0xffffe00000000000n +let () = check ~divisor:0xffffec1e17a62ee8n +let () = check ~divisor:0xffffeffffffffffen +let () = check ~divisor:0xffffefffffffffffn +let () = check ~divisor:0xfffff00000000000n +let () = check ~divisor:0xfffff4385a292d10n +let () = check ~divisor:0xfffff7fffffffffen +let () = check ~divisor:0xfffff7ffffffffffn +let () = check ~divisor:0xfffff80000000000n +let () = check ~divisor:0xfffffb29ad622ec6n +let () = check ~divisor:0xfffffbfffffffffen +let () = check ~divisor:0xfffffbffffffffffn +let () = check ~divisor:0xfffffc0000000000n +let () = check ~divisor:0xfffffd0fd79dbe92n +let () = check ~divisor:0xfffffdfffffffffen +let () = check ~divisor:0xfffffdffffffffffn +let () = check ~divisor:0xfffffe0000000000n +let () = check ~divisor:0xfffffebf188a6912n +let () = check ~divisor:0xfffffefffffffffen +let () = check ~divisor:0xfffffeffffffffffn +let () = check ~divisor:0xffffff0000000000n +let () = check ~divisor:0xffffff269c30eb24n +let () = check ~divisor:0xffffff7ffffffffen +let () = check ~divisor:0xffffff7fffffffffn +let () = check ~divisor:0xffffff8000000000n +let () = check ~divisor:0xffffffb4017e6dabn +let () = check ~divisor:0xffffffbffffffffen +let () = check ~divisor:0xffffffbfffffffffn +let () = check ~divisor:0xffffffc000000000n +let () = check ~divisor:0xffffffd7df0592aan +let () = check ~divisor:0xffffffdffffffffen +let () = check ~divisor:0xffffffdfffffffffn +let () = check ~divisor:0xffffffe000000000n +let () = check ~divisor:0xffffffea2e2ffe26n +let () = check ~divisor:0xffffffeffffffffen +let () = check ~divisor:0xffffffefffffffffn +let () = check ~divisor:0xfffffff000000000n +let () = check ~divisor:0xfffffff2b2f7d81cn +let () = check ~divisor:0xfffffff7fffffffen +let () = check ~divisor:0xfffffff7ffffffffn +let () = check ~divisor:0xfffffff800000000n +let () = check ~divisor:0xfffffffafd83a8dcn +let () = check ~divisor:0xfffffffbfffffffen +let () = check ~divisor:0xfffffffbffffffffn +let () = check ~divisor:0xfffffffc00000000n +let () = check ~divisor:0xfffffffdea3eef40n +let () = check ~divisor:0xfffffffdfffffffen +let () = check ~divisor:0xfffffffdffffffffn +let () = check ~divisor:0xfffffffe00000000n +let () = check ~divisor:0xfffffffe92dcda11n +let () = check ~divisor:0xfffffffefffffffen +let () = check ~divisor:0xfffffffeffffffffn +let () = check ~divisor:0xffffffff00000000n +let () = check ~divisor:0xffffffff00ba6c9dn +let () = check ~divisor:0xffffffff7ffffffen +let () = check ~divisor:0xffffffff7fffffffn +let () = check ~divisor:0xffffffff80000000n +let () = check ~divisor:0xffffffff9f9bf830n +let () = check ~divisor:0xffffffffbffffffen +let () = check ~divisor:0xffffffffbfffffffn +let () = check ~divisor:0xffffffffc0000000n +let () = check ~divisor:0xffffffffdc036576n +let () = check ~divisor:0xffffffffdffffffen +let () = check ~divisor:0xffffffffdfffffffn +let () = check ~divisor:0xffffffffe0000000n +let () = check ~divisor:0xffffffffea807c27n +let () = check ~divisor:0xffffffffeffffffen +let () = check ~divisor:0xffffffffefffffffn +let () = check ~divisor:0xfffffffff0000000n +let () = check ~divisor:0xfffffffff0bd42e5n +let () = check ~divisor:0xfffffffff7fffffen +let () = check ~divisor:0xfffffffff7ffffffn +let () = check ~divisor:0xfffffffff8000000n +let () = check ~divisor:0xfffffffff9be81b5n +let () = check ~divisor:0xfffffffffbfffffen +let () = check ~divisor:0xfffffffffbffffffn +let () = check ~divisor:0xfffffffffc000000n +let () = check ~divisor:0xfffffffffdcbce91n +let () = check ~divisor:0xfffffffffdfffffen +let () = check ~divisor:0xfffffffffdffffffn +let () = check ~divisor:0xfffffffffe000000n +let () = check ~divisor:0xfffffffffec24947n +let () = check ~divisor:0xfffffffffefffffen +let () = check ~divisor:0xfffffffffeffffffn +let () = check ~divisor:0xffffffffff000000n +let () = check ~divisor:0xffffffffff36dd37n +let () = check ~divisor:0xffffffffff7ffffen +let () = check ~divisor:0xffffffffff7fffffn +let () = check ~divisor:0xffffffffff800000n +let () = check ~divisor:0xffffffffffb8d39an +let () = check ~divisor:0xffffffffffbffffen +let () = check ~divisor:0xffffffffffbfffffn +let () = check ~divisor:0xffffffffffc00000n +let () = check ~divisor:0xffffffffffd3f492n +let () = check ~divisor:0xffffffffffdffffen +let () = check ~divisor:0xffffffffffdfffffn +let () = check ~divisor:0xffffffffffe00000n +let () = check ~divisor:0xffffffffffe8c9b3n +let () = check ~divisor:0xffffffffffeffffen +let () = check ~divisor:0xffffffffffefffffn +let () = check ~divisor:0xfffffffffff00000n +let () = check ~divisor:0xfffffffffff7ac08n +let () = check ~divisor:0xfffffffffff7fffen +let () = check ~divisor:0xfffffffffff7ffffn +let () = check ~divisor:0xfffffffffff80000n +let () = check ~divisor:0xfffffffffffadad2n +let () = check ~divisor:0xfffffffffffbfffen +let () = check ~divisor:0xfffffffffffbffffn +let () = check ~divisor:0xfffffffffffc0000n +let () = check ~divisor:0xfffffffffffcfe0cn +let () = check ~divisor:0xfffffffffffdfffen +let () = check ~divisor:0xfffffffffffdffffn +let () = check ~divisor:0xfffffffffffe0000n +let () = check ~divisor:0xfffffffffffe6624n +let () = check ~divisor:0xfffffffffffefffen +let () = check ~divisor:0xfffffffffffeffffn +let () = check ~divisor:0xffffffffffff0000n +let () = check ~divisor:0xffffffffffff7b92n +let () = check ~divisor:0xffffffffffff7ffen +let () = check ~divisor:0xffffffffffff7fffn +let () = check ~divisor:0xffffffffffff8000n +let () = check ~divisor:0xffffffffffffba40n +let () = check ~divisor:0xffffffffffffbffen +let () = check ~divisor:0xffffffffffffbfffn +let () = check ~divisor:0xffffffffffffc000n +let () = check ~divisor:0xffffffffffffcc04n +let () = check ~divisor:0xffffffffffffdffen +let () = check ~divisor:0xffffffffffffdfffn +let () = check ~divisor:0xffffffffffffe000n +let () = check ~divisor:0xffffffffffffefe8n +let () = check ~divisor:0xffffffffffffeffen +let () = check ~divisor:0xffffffffffffefffn +let () = check ~divisor:0xfffffffffffff000n +let () = check ~divisor:0xfffffffffffff4ean +let () = check ~divisor:0xfffffffffffff7fen +let () = check ~divisor:0xfffffffffffff7ffn +let () = check ~divisor:0xfffffffffffff800n +let () = check ~divisor:0xfffffffffffffb29n +let () = check ~divisor:0xfffffffffffffbfen +let () = check ~divisor:0xfffffffffffffbffn +let () = check ~divisor:0xfffffffffffffc00n +let () = check ~divisor:0xfffffffffffffd38n +let () = check ~divisor:0xfffffffffffffdfen +let () = check ~divisor:0xfffffffffffffdffn +let () = check ~divisor:0xfffffffffffffe00n +let () = check ~divisor:0xfffffffffffffe4dn +let () = check ~divisor:0xfffffffffffffefen +let () = check ~divisor:0xfffffffffffffeffn +let () = check ~divisor:0xffffffffffffff00n +let () = check ~divisor:0xffffffffffffff57n +let () = check ~divisor:0xffffffffffffff7en +let () = check ~divisor:0xffffffffffffff7fn +let () = check ~divisor:0xffffffffffffff80n +let () = check ~divisor:0xffffffffffffffabn +let () = check ~divisor:0xffffffffffffffben +let () = check ~divisor:0xffffffffffffffbfn +let () = check ~divisor:0xffffffffffffffc0n +let () = check ~divisor:0xffffffffffffffc6n +let () = check ~divisor:0xffffffffffffffden +let () = check ~divisor:0xffffffffffffffdfn +let () = check ~divisor:0xffffffffffffffe0n +let () = check ~divisor:0xffffffffffffffean +let () = check ~divisor:0xffffffffffffffeen +let () = check ~divisor:0xffffffffffffffefn +let () = check ~divisor:0xfffffffffffffff0n +let () = check ~divisor:0xfffffffffffffff1n +let () = check ~divisor:0xfffffffffffffff6n +let () = check ~divisor:0xfffffffffffffff7n let () = check ~divisor:0xfffffffffffffff8n +let () = check ~divisor:0xfffffffffffffffan +let () = check ~divisor:0xfffffffffffffffbn let () = check ~divisor:0xfffffffffffffffcn +let () = check ~divisor:0xfffffffffffffffdn let () = check ~divisor:0xfffffffffffffffen let () = check ~divisor:0xffffffffffffffffn From 958b4d335e647c434d16a33325946f51c034eacc Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Tue, 21 Jan 2025 12:36:32 -0500 Subject: [PATCH 8/9] no specialize --- testsuite/tests/basic/division_by_constant.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/tests/basic/division_by_constant.ml b/testsuite/tests/basic/division_by_constant.ml index f9b2c654c2..fa453da917 100644 --- a/testsuite/tests/basic/division_by_constant.ml +++ b/testsuite/tests/basic/division_by_constant.ml @@ -85,7 +85,7 @@ let () = (* Since [check] is always inlined, the division-by-constant optimization should trigger in every case when called with a literal ~divisor *) -let[@inline always] [@specialise always] check ~divisor = +let[@inline always] check ~divisor = let[@inline always] quotient ~dividend = div dividend divisor in let[@inline always] remainder ~dividend = rem dividend divisor in ListLabels.iter test_cases ~f:(fun dividend -> From dd1d945d4a123b1bda3b05888a03f70805f9d8ba Mon Sep 17 00:00:00 2001 From: Jacob Van Buren Date: Tue, 21 Jan 2025 13:10:36 -0500 Subject: [PATCH 9/9] sped up division tests --- testsuite/tests/basic/division_by_constant.ml | 34 ++++++++++++------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/testsuite/tests/basic/division_by_constant.ml b/testsuite/tests/basic/division_by_constant.ml index fa453da917..a723c810af 100644 --- a/testsuite/tests/basic/division_by_constant.ml +++ b/testsuite/tests/basic/division_by_constant.ml @@ -16,19 +16,27 @@ let test_cases = ListLabels.concat_map [pred bit; bit; succ bit; rand ()] ~f:(fun x -> [x; lognot x; sub max_int x; lognot (sub max_int x)])) - |> List.concat |> List.sort_uniq compare + |> List.concat |> List.sort_uniq compare |> Array.of_list let[@inline never] check_result ~dividend ~divisor ~quotient ~remainder = - assert (divisor <> 0n); - assert (quotient = div dividend divisor); - assert (remainder = rem dividend divisor); - assert (dividend = add (mul quotient divisor) remainder); - assert ( + let[@inline] sign x = if x < 0n then -1 else if x = 0n then 0 else 1 in + let identity = dividend = add (mul quotient divisor) remainder in + let magnitude = if divisor = min_int then remainder <> min_int - else abs remainder < abs divisor); - let[@inline] sign x = if x < 0n then -1 else if x = 0n then 0 else 1 in - assert (remainder = 0n || sign remainder = sign dividend) + else abs remainder < abs divisor + in + let sign = (remainder = 0n || sign remainder = sign dividend) in + if not (identity && magnitude && sign) then ( + Printf.fprintf + stderr + "FAILED: dividend=%nd, divisor=%nd, quotient=%nd, remainder=%nd\n%!" + dividend + divisor + quotient + remainder; + exit 1) + (* test that the order of side effects are preserved in all cases *) @@ -88,9 +96,9 @@ let () = let[@inline always] check ~divisor = let[@inline always] quotient ~dividend = div dividend divisor in let[@inline always] remainder ~dividend = rem dividend divisor in - ListLabels.iter test_cases ~f:(fun dividend -> - check_result ~dividend ~divisor ~quotient:(quotient ~dividend) - ~remainder:(remainder ~dividend)) + ArrayLabels.iter test_cases ~f:(fun dividend -> + check_result ~dividend ~divisor ~quotient:(quotient ~dividend) + ~remainder:(remainder ~dividend)) (* manual tests *) @@ -103,7 +111,7 @@ let () = check ~divisor:(-7n) let () = check ~divisor:65537n let () = check ~divisor:(-65537n) -(* These tests are generated by a manual run of test_cases with seed +(* The following tests are generated by a manual run of test_cases with seed [[| int_size |]] to test against a hard-coded list of dividends. *) let () = check ~divisor:0x1n