···11+This repository contains open source software that is developed and
22+maintained by [Jane Street][js].
33+44+Contributions to this project are welcome and should be submitted via
55+GitHub pull requests.
66+77+Signing contributions
88+---------------------
99+1010+We require that you sign your contributions. Your signature certifies
1111+that you wrote the patch or otherwise have the right to pass it on as
1212+an open-source patch. The rules are pretty simple: if you can certify
1313+the below (from [developercertificate.org][dco]):
1414+1515+```
1616+Developer Certificate of Origin
1717+Version 1.1
1818+1919+Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
2020+1 Letterman Drive
2121+Suite D4700
2222+San Francisco, CA, 94129
2323+2424+Everyone is permitted to copy and distribute verbatim copies of this
2525+license document, but changing it is not allowed.
2626+2727+2828+Developer's Certificate of Origin 1.1
2929+3030+By making a contribution to this project, I certify that:
3131+3232+(a) The contribution was created in whole or in part by me and I
3333+ have the right to submit it under the open source license
3434+ indicated in the file; or
3535+3636+(b) The contribution is based upon previous work that, to the best
3737+ of my knowledge, is covered under an appropriate open source
3838+ license and I have the right under that license to submit that
3939+ work with modifications, whether created in whole or in part
4040+ by me, under the same open source license (unless I am
4141+ permitted to submit under a different license), as indicated
4242+ in the file; or
4343+4444+(c) The contribution was provided directly to me by some other
4545+ person who certified (a), (b) or (c) and I have not modified
4646+ it.
4747+4848+(d) I understand and agree that this project and the contribution
4949+ are public and that a record of the contribution (including all
5050+ personal information I submit with it, including my sign-off) is
5151+ maintained indefinitely and may be redistributed consistent with
5252+ this project or the open source license(s) involved.
5353+```
5454+5555+Then you just add a line to every git commit message:
5656+5757+```
5858+Signed-off-by: Joe Smith <joe.smith@email.com>
5959+```
6060+6161+Use your real name (sorry, no pseudonyms or anonymous contributions.)
6262+6363+If you set your `user.name` and `user.email` git configs, you can sign
6464+your commit automatically with git commit -s.
6565+6666+[dco]: http://developercertificate.org/
6767+[js]: https://opensource.janestreet.com/
+21
vendor/opam/ocaml_intrinsics_kernel/LICENSE.md
···11+The MIT License
22+33+Copyright (c) 2020--2025 Jane Street Group, LLC <opensource-contacts@janestreet.com>
44+55+Permission is hereby granted, free of charge, to any person obtaining a copy
66+of this software and associated documentation files (the "Software"), to deal
77+in the Software without restriction, including without limitation the rights
88+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
99+copies of the Software, and to permit persons to whom the Software is
1010+furnished to do so, subject to the following conditions:
1111+1212+The above copyright notice and this permission notice shall be included in all
1313+copies or substantial portions of the Software.
1414+1515+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1616+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1717+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
1818+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1919+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2020+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121+SOFTWARE.
···11+ocaml_intrinsics_kernel - a library of intrinsics for OCaml
22+===========================================================
33+44+55+The ocaml_intrinsics_kernel library provides an OCaml interface to operations
66+that have dedicated hardware instructions on some micro-architectures.
77+Currently, it provides the following operations:
88+99+* conditional select
1010+1111+See ocaml_intrinsics for details. Unlike ocaml_intrinsics, ocaml_intrinsics_kernel
1212+can be used by programs compiled to javascript.
···11+open! Base
22+module I = Ocaml_intrinsics_kernel
33+44+module%bench Overheads = struct
55+ (* Using [%bench_fun] to bind the input outside the benchmarked code actually has less
66+ overhead then using [%bench] naively. *)
77+ let%bench_fun "int overhead" =
88+ let n = Sys.opaque_identity (Random.int Int.max_value) in
99+ fun () -> Fn.id n
1010+ ;;
1111+1212+ let%bench_fun "int64 overhead" =
1313+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
1414+ fun () -> Fn.id n
1515+ ;;
1616+1717+ let%bench_fun "int32 overhead" =
1818+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
1919+ fun () -> Fn.id n
2020+ ;;
2121+2222+ let%bench_fun "nativeint overhead" =
2323+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
2424+ fun () -> Fn.id n
2525+ ;;
2626+end
2727+2828+module%bench Clz = struct
2929+ (* ocaml_intrinsics library *)
3030+ let%bench_fun "int_clz" =
3131+ let n = Sys.opaque_identity (Random.int Int.max_value) in
3232+ fun () -> I.Int.count_leading_zeros n
3333+ ;;
3434+3535+ let%bench_fun "int_clz2" =
3636+ let n = Sys.opaque_identity (Random.int Int.max_value) in
3737+ fun () -> I.Int.count_leading_zeros2 n
3838+ ;;
3939+4040+ let%bench_fun "int64_clz" =
4141+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
4242+ fun () -> I.Int64.count_leading_zeros n
4343+ ;;
4444+4545+ let%bench_fun "nativeint_clz" =
4646+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
4747+ fun () -> I.Nativeint.count_leading_zeros n
4848+ ;;
4949+5050+ let%bench_fun "int32_clz" =
5151+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
5252+ fun () -> I.Int32.count_leading_zeros n
5353+ ;;
5454+5555+ (* Base *)
5656+ let%bench_fun "base int_clz" =
5757+ let n = Sys.opaque_identity (Random.int Int.max_value) in
5858+ fun () -> Base.Int.clz n
5959+ ;;
6060+6161+ let%bench_fun "base int64_clz" =
6262+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
6363+ fun () -> Base.Int64.clz n
6464+ ;;
6565+6666+ let%bench_fun "base nativeint_clz" =
6767+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
6868+ fun () -> Base.Nativeint.clz n
6969+ ;;
7070+7171+ let%bench_fun "base int32_clz" =
7272+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
7373+ fun () -> Base.Int32.clz n
7474+ ;;
7575+end
7676+7777+module%bench Ctz = struct
7878+ (* ocaml_intrinsics library *)
7979+ let%bench_fun "int_ctz" =
8080+ let n = Sys.opaque_identity (Random.int Int.max_value) in
8181+ fun () -> I.Int.count_trailing_zeros n
8282+ ;;
8383+8484+ let%bench_fun "int64_ctz" =
8585+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
8686+ fun () -> I.Int64.count_trailing_zeros n
8787+ ;;
8888+8989+ let%bench_fun "nativeint_ctz" =
9090+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
9191+ fun () -> I.Nativeint.count_trailing_zeros n
9292+ ;;
9393+9494+ let%bench_fun "int32_ctz" =
9595+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
9696+ fun () -> I.Int32.count_trailing_zeros n
9797+ ;;
9898+9999+ (* Base *)
100100+ let%bench_fun "base int_ctz" =
101101+ let n = Sys.opaque_identity (Random.int Int.max_value) in
102102+ fun () -> Base.Int.ctz n
103103+ ;;
104104+105105+ let%bench_fun "base int64_ctz" =
106106+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
107107+ fun () -> Base.Int64.ctz n
108108+ ;;
109109+110110+ let%bench_fun "base nativeint_ctz" =
111111+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
112112+ fun () -> Base.Nativeint.ctz n
113113+ ;;
114114+115115+ let%bench_fun "base int32_ctz" =
116116+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
117117+ fun () -> Base.Int32.ctz n
118118+ ;;
119119+end
120120+121121+module%bench Popcnt = struct
122122+ (* ocaml_intrinsics library *)
123123+ let%bench_fun "int_popcount" =
124124+ let n = Sys.opaque_identity (Random.int Int.max_value) in
125125+ fun () -> I.Int.count_set_bits n
126126+ ;;
127127+128128+ let%bench_fun "int_popcount2" =
129129+ let n = Sys.opaque_identity (Random.int Int.max_value) in
130130+ fun () -> I.Int.count_set_bits2 n
131131+ ;;
132132+133133+ let%bench_fun "int64_popcount" =
134134+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
135135+ fun () -> I.Int64.count_set_bits n
136136+ ;;
137137+138138+ let%bench_fun "nativeint_popcount" =
139139+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
140140+ fun () -> I.Nativeint.count_set_bits n
141141+ ;;
142142+143143+ let%bench_fun "int32_popcount" =
144144+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
145145+ fun () -> I.Int32.count_set_bits n
146146+ ;;
147147+148148+ (* Base *)
149149+ let%bench_fun "base int_popcount" =
150150+ let n = Sys.opaque_identity (Random.int Int.max_value) in
151151+ fun () -> Base.Int.popcount n
152152+ ;;
153153+154154+ let%bench_fun "base int64_popcount" =
155155+ let n = Sys.opaque_identity (Random.int64 Int64.max_value) in
156156+ fun () -> Base.Int64.popcount n
157157+ ;;
158158+159159+ let%bench_fun "base nativeint_popcount" =
160160+ let n = Sys.opaque_identity (Random.nativeint Nativeint.max_value) in
161161+ fun () -> Base.Nativeint.popcount n
162162+ ;;
163163+164164+ let%bench_fun "base int32_popcount" =
165165+ let n = Sys.opaque_identity (Random.int32 Int32.max_value) in
166166+ fun () -> Base.Int32.popcount n
167167+ ;;
168168+end
···11+(** Are optimized C stubs available? If not, naive implementation will be used. The value
22+ is statically known and depends on the current compiler's configuration (system,
33+ target, architecture). *)
44+val available : bool
···11+(** X86 docs say:
22+33+ If only one value is a NaN (SNaN or QNaN) for this instruction, the second source
44+ operand, either a NaN or a valid floating-point value is written to the result.
55+66+ So we have to be VERY careful how we use these! *)
77+88+(** Equivalent to [if x < y then x else y].
99+1010+ On an x86-64 machine, this compiles to [minsd xmm0, xmm1]. On ARM, this calls a C
1111+ implementation. *)
1212+external min
1313+ : (float[@unboxed])
1414+ -> (float[@unboxed])
1515+ -> (float[@unboxed])
1616+ = "caml_sse2_float64_min_bytecode" "caml_sse2_float64_min"
1717+[@@noalloc]
1818+1919+(** Equivalent to [if x > y then x else y].
2020+2121+ On an x86-64 machine, this compiles to [maxsd xmm0, xmm1]. On ARM, this calls a C
2222+ implementation. *)
2323+external max
2424+ : (float[@unboxed])
2525+ -> (float[@unboxed])
2626+ -> (float[@unboxed])
2727+ = "caml_sse2_float64_max_bytecode" "caml_sse2_float64_max"
2828+[@@noalloc]
2929+3030+(** Rounds a [float] to an [int64] using the current rounding mode. In native code, the
3131+ default rounding mode is "round half to even," and we expect that no program will
3232+ change the rounding mode.
3333+3434+ If the argument is NaN or infinite or if the rounded value cannot be represented, the
3535+ result is unspecified.
3636+3737+ On an x86-64 machine, this compiles to [cvtsd2si rax, xmm0]. On ARM, this calls a C
3838+ implementation. *)
3939+external iround_current
4040+ : (float[@unboxed])
4141+ -> (int64[@unboxed])
4242+ = "caml_sse2_cast_float64_int64_bytecode" "caml_sse2_cast_float64_int64"
4343+[@@noalloc]
4444+4545+module Unboxed : sig
4646+ external min
4747+ : (float[@unboxed])
4848+ -> (float[@unboxed])
4949+ -> (float[@unboxed])
5050+ = "caml_sse2_float64_min_bytecode" "caml_sse2_float64_min"
5151+ [@@noalloc]
5252+5353+ external max
5454+ : (float[@unboxed])
5555+ -> (float[@unboxed])
5656+ -> (float[@unboxed])
5757+ = "caml_sse2_float64_max_bytecode" "caml_sse2_float64_max"
5858+ [@@noalloc]
5959+6060+ external iround_current
6161+ : (float[@unboxed])
6262+ -> (int64[@unboxed])
6363+ = "caml_sse2_cast_float64_int64_bytecode" "caml_sse2_cast_float64_int64"
6464+ [@@noalloc]
6565+end
···11+(** The are two version of [count_leading_zeros], [count_set_bits] each, which differ in
22+ their native code implementation. The first version takes as input a tagged integer
33+ and the second version takes as input an untagged integer. Generally, the first
44+ version (that operates on a tagged integer) is faster, but if the integer is already
55+ untagged, it may be faster to use the second version. *)
66+77+module Stubs = struct
88+ let available = Common.available
99+1010+ (** [count_leading_zeros n] returns the number of most-significant zero bits before the
1111+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in
1212+ [n], that is 31 or 63, depending on the target. *)
1313+ external count_leading_zeros
1414+ : int
1515+ -> (int[@untagged])
1616+ = "caml_int_clz" "caml_int_clz_tagged_to_untagged"
1717+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
1818+1919+ external count_leading_zeros2
2020+ : int
2121+ -> int
2222+ = "caml_int_clz" "caml_int_clz_untagged_to_untagged"
2323+ [@@untagged] [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2424+2525+ (** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
2626+ external count_set_bits
2727+ : int
2828+ -> (int[@untagged])
2929+ = "caml_int_popcnt" "caml_int_popcnt_tagged_to_untagged"
3030+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
3131+3232+ external count_set_bits2
3333+ : int
3434+ -> int
3535+ = "caml_int_popcnt" "caml_int_popcnt_untagged_to_untagged"
3636+ [@@untagged] [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
3737+3838+ (** [count_trailing_zeros n] returns the number of least-significant zero bits before
3939+ the least significant set bit in [n]. If [n] is 0, the result is the number of bits
4040+ in [n], that is 31 or 63, depending on the target. *)
4141+ external count_trailing_zeros
4242+ : int
4343+ -> int
4444+ = "caml_int_ctz" "caml_int_ctz_untagged_to_untagged"
4545+ [@@untagged] [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
4646+end
4747+4848+module Naive = Naive_ints.Make (struct
4949+ include Stdlib.Int
5050+5151+ external compare : t -> t -> int = "%compare"
5252+ external equal : t -> t -> bool = "%equal"
5353+5454+ let bitwidth = Sys.int_size
5555+ let to_int = Fun.id
5656+ let of_int t = t
5757+ end)
5858+5959+let[@inline always] count_leading_zeros n =
6060+ match Stubs.available with
6161+ | true -> Stubs.count_leading_zeros n
6262+ | false -> Naive.count_leading_zeros n
6363+;;
6464+6565+let[@inline always] count_leading_zeros2 n =
6666+ match Stubs.available with
6767+ | true -> Stubs.count_leading_zeros2 n
6868+ | false -> Naive.count_leading_zeros n
6969+;;
7070+7171+let[@inline always] count_set_bits2 n =
7272+ match Stubs.available with
7373+ | true -> Stubs.count_set_bits2 n
7474+ | false -> Naive.count_set_bits n
7575+;;
7676+7777+let[@inline always] count_trailing_zeros n =
7878+ match Stubs.available with
7979+ | true -> Stubs.count_trailing_zeros n
8080+ | false -> Naive.count_trailing_zeros n
8181+;;
8282+8383+let[@inline always] count_set_bits n =
8484+ match Stubs.available with
8585+ | true -> Stubs.count_set_bits n
8686+ | false -> Naive.count_set_bits n
8787+;;
+34
vendor/opam/ocaml_intrinsics_kernel/src/int.mli
···11+(** The are two versions of [count_leading_zeros] and [count_set_bits]. They have the same
22+ types, but their native code implementations differ.
33+44+ The first version inputs a tagged integer and the second version inputs an untagged
55+ integer. Generally, the first version (operating on a tagged integer) is faster, but
66+ if the untagged integer is already available in the surrounding context, the second
77+ version may be faster. *)
88+99+(** [count_leading_zeros n] returns the number of most-significant zero bits before the
1010+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in [n],
1111+ that is 31 or 63, depending on the target. *)
1212+val count_leading_zeros : int -> int
1313+1414+(** [count_leading_zeros2 n] computes the same result as [count_leading_zeros n].
1515+1616+ The functions only differ in optimizations that the compiler may be able to perform
1717+ around the call. In particular, the implementation of [count_leading_zeros n] may
1818+ operate directly on tagged n. *)
1919+val count_leading_zeros2 : int -> int
2020+2121+(** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
2222+val count_set_bits : int -> int
2323+2424+(** [count_set_bits2 n] computes the same result as [count_set_bits n].
2525+2626+ The functions only differs in optimizations that the compiler may be able to perform
2727+ around the call. In particular, the implementation of [count_set_bits n] may operate
2828+ directly on tagged n. *)
2929+val count_set_bits2 : int -> int
3030+3131+(** [count_trailing_zeros n] returns the number of least-significant zero bits before the
3232+ least significant set bit in [n]. If [n] is 0, the result is the number of bits in
3333+ [n], that is 31 or 63, depending on the target. *)
3434+val count_trailing_zeros : int -> int
+123
vendor/opam/ocaml_intrinsics_kernel/src/int32.ml
···11+module Stubs = struct
22+ let available = Common.available
33+44+ (** [count_leading_zeros n] returns the number of most-significant zero bits before the
55+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in
66+ [n], that is 32. *)
77+ external count_leading_zeros
88+ : (int32[@unboxed] [@local_opt])
99+ -> (int32[@unboxed])
1010+ = "caml_int32_clz" "caml_int32_clz_unboxed_to_untagged"
1111+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
1212+1313+ (** Same as [count_leading_zeros] except if the argument is zero, then the result is
1414+ undefined. Emits more efficient code. *)
1515+ external count_leading_zeros_nonzero_arg
1616+ : (int32[@unboxed] [@local_opt])
1717+ -> (int32[@unboxed])
1818+ = "caml_int32_clz" "caml_int32_clz_nonzero_unboxed_to_untagged"
1919+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2020+2121+ (** [count_trailing_zeros n] returns the number of least-significant zero bits before
2222+ the least significant set bit in [n]. If [n] is 0, the result is the number of bits
2323+ in [n], that is 32. *)
2424+ external count_trailing_zeros
2525+ : (int32[@unboxed] [@local_opt])
2626+ -> (int32[@unboxed])
2727+ = "caml_int32_ctz" "caml_int32_ctz_unboxed_to_untagged"
2828+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2929+3030+ (** Same as [count_trailing_zeros] except if the argument is zero, then the result is
3131+ undefined. Emits more efficient code. *)
3232+ external count_trailing_zeros_nonzero_arg
3333+ : (int32[@unboxed] [@local_opt])
3434+ -> (int32[@unboxed])
3535+ = "caml_int32_ctz" "caml_int32_ctz_nonzero_unboxed_to_untagged"
3636+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
3737+3838+ (** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
3939+ external count_set_bits
4040+ : (int32[@unboxed] [@local_opt])
4141+ -> (int32[@unboxed])
4242+ = "caml_int32_popcnt" "caml_int32_popcnt_unboxed_to_untagged"
4343+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
4444+4545+ external shift_left
4646+ : (int32[@local_opt])
4747+ -> (int32[@local_opt])
4848+ -> (int32[@local_opt])
4949+ = "caml_int32_shift_left_by_int32" "caml_int32_shift_left_by_int32_unboxed"
5050+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
5151+5252+ external shift_right
5353+ : (int32[@local_opt])
5454+ -> (int32[@local_opt])
5555+ -> (int32[@local_opt])
5656+ = "caml_int32_shift_right_by_int32" "caml_int32_shift_right_by_int32_unboxed"
5757+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
5858+5959+ external shift_right_logical
6060+ : (int32[@local_opt])
6161+ -> (int32[@local_opt])
6262+ -> (int32[@local_opt])
6363+ = "caml_int32_shift_right_logical_by_int32"
6464+ "caml_int32_shift_right_logical_by_int32_unboxed"
6565+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
6666+end
6767+6868+module Naive = Naive_ints.Make (struct
6969+ include Stdlib.Int32
7070+7171+ external compare : t -> t -> int = "%compare"
7272+ external equal : t -> t -> bool = "%equal"
7373+7474+ let bitwidth = 32l
7575+ end)
7676+7777+let[@inline always] count_leading_zeros n =
7878+ match Stubs.available with
7979+ | true -> Stubs.count_leading_zeros n
8080+ | false -> Naive.count_leading_zeros n
8181+;;
8282+8383+let[@inline always] count_leading_zeros_nonzero_arg n =
8484+ match Stubs.available with
8585+ | true -> Stubs.count_leading_zeros_nonzero_arg n
8686+ | false -> Naive.count_leading_zeros n
8787+;;
8888+8989+let[@inline always] count_trailing_zeros n =
9090+ match Stubs.available with
9191+ | true -> Stubs.count_trailing_zeros n
9292+ | false -> Naive.count_trailing_zeros n
9393+;;
9494+9595+let[@inline always] count_trailing_zeros_nonzero_arg n =
9696+ match Stubs.available with
9797+ | true -> Stubs.count_trailing_zeros_nonzero_arg n
9898+ | false -> Naive.count_trailing_zeros n
9999+;;
100100+101101+let[@inline always] count_set_bits n =
102102+ match Stubs.available with
103103+ | true -> Stubs.count_set_bits n
104104+ | false -> Naive.count_set_bits n
105105+;;
106106+107107+let[@inline always] shift_left x y =
108108+ match Stubs.available with
109109+ | true -> Stubs.shift_left x y
110110+ | false -> Naive.shift_left x y
111111+;;
112112+113113+let[@inline always] shift_right x y =
114114+ match Stubs.available with
115115+ | true -> Stubs.shift_right x y
116116+ | false -> Naive.shift_right x y
117117+;;
118118+119119+let[@inline always] shift_right_logical x y =
120120+ match Stubs.available with
121121+ | true -> Stubs.shift_right_logical x y
122122+ | false -> Naive.shift_right_logical x y
123123+;;
+47
vendor/opam/ocaml_intrinsics_kernel/src/int32.mli
···11+(** [count_leading_zeros n] returns the number of most-significant zero bits before the
22+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in [n],
33+ that is 32. *)
44+val count_leading_zeros : int32 -> int32
55+66+(** Same as [count_leading_zeros] except if the argument is zero, then the result is
77+ undefined. Emits more efficient code.
88+99+ This is no longer needed when using an flambda-backend compiler, which translates
1010+ [count_leading_zeros] to LZCNT by default (amd64). *)
1111+val count_leading_zeros_nonzero_arg : int32 -> int32
1212+1313+(** [count_trailing_zeros n] returns the number of least-significant zero bits before the
1414+ least significant set bit in [n]. If [n] is 0, the result is the number of bits in
1515+ [n], that is 32. *)
1616+val count_trailing_zeros : int32 -> int32
1717+1818+(** Same as [count_trailing_zeros] except if the argument is zero, then the result is
1919+ undefined. Emits more efficient code.
2020+2121+ This is no longer needed when using an flambda-backend compiler, which translates
2222+ [count_trailing_zeros] to TZCNT by default (amd64). *)
2323+val count_trailing_zeros_nonzero_arg : int32 -> int32
2424+2525+(** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
2626+val count_set_bits : int32 -> int32
2727+2828+(** Shift operations below differ from the corresponding [Stdlib.Int32.shift_*] operations
2929+ in two ways:
3030+ (a) shift count (second argument) is the same type as the first argument, allowing
3131+ unboxed types to be used as counts.
3232+ (b) the operations are defined for arbitrary shift counts and rely on the hardware to
3333+ mask the shift to [bitwidth-1] bits, where [bitwidth] is determined by the type of
3434+ the first argument. *)
3535+3636+(** [shift_left x y] shifts [x] to the left by [y & (bitwidth-1)] bits. *)
3737+val shift_left : int32 -> int32 -> int32
3838+3939+(** [Int32.shift_right x y] shifts [x] to the right by [y] bits. This is an arithmetic
4040+ shift: the sign bit of [x] is replicated and inserted in the vacated bits. *)
4141+val shift_right : int32 -> int32 -> int32
4242+4343+(** [Int32.shift_right_logical x y] shifts [x] to the right by [y] bits. This is a logical
4444+ shift: zeroes are inserted in the vacated bits regardless of the sign of [x]. *)
4545+val shift_right_logical : int32 -> int32 -> int32
4646+4747+module Naive : Naive_ints.S with type t = int32
+123
vendor/opam/ocaml_intrinsics_kernel/src/int64.ml
···11+module Stubs = struct
22+ let available = Common.available
33+44+ (** [count_leading_zeros n] returns the number of most-significant zero bits before the
55+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in
66+ [n], that is 64. *)
77+ external count_leading_zeros
88+ : (int64[@unboxed] [@local_opt])
99+ -> (int64[@unboxed])
1010+ = "caml_int64_clz" "caml_int64_clz_unboxed_to_untagged"
1111+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
1212+1313+ (** Same as [count_leading_zeros] except if the argument is zero, then the result is
1414+ undefined. Emits more efficient code. *)
1515+ external count_leading_zeros_nonzero_arg
1616+ : (int64[@unboxed] [@local_opt])
1717+ -> (int64[@unboxed])
1818+ = "caml_int64_clz" "caml_int64_clz_nonzero_unboxed_to_untagged"
1919+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2020+2121+ (** [count_trailing_zeros n] returns the number of least-significant zero bits before
2222+ the least significant set bit in [n]. If [n] is 0, the result is the number of bits
2323+ in [n], that is 64. *)
2424+ external count_trailing_zeros
2525+ : (int64[@unboxed] [@local_opt])
2626+ -> (int64[@unboxed])
2727+ = "caml_int64_ctz" "caml_int64_ctz_unboxed_to_untagged"
2828+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2929+3030+ (** Same as [count_trailing_zeros] except if the argument is zero, then the result is
3131+ undefined. Emits more efficient code. *)
3232+ external count_trailing_zeros_nonzero_arg
3333+ : (int64[@unboxed] [@local_opt])
3434+ -> (int64[@unboxed])
3535+ = "caml_int64_ctz" "caml_int64_ctz_nonzero_unboxed_to_untagged"
3636+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
3737+3838+ (** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
3939+ external count_set_bits
4040+ : (int64[@unboxed] [@local_opt])
4141+ -> (int64[@unboxed])
4242+ = "caml_int64_popcnt" "caml_int64_popcnt_unboxed_to_untagged"
4343+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
4444+4545+ external shift_left
4646+ : (int64[@local_opt])
4747+ -> (int64[@local_opt])
4848+ -> (int64[@local_opt])
4949+ = "caml_int64_shift_left_by_int64" "caml_int64_shift_left_by_int64_unboxed"
5050+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
5151+5252+ external shift_right
5353+ : (int64[@local_opt])
5454+ -> (int64[@local_opt])
5555+ -> (int64[@local_opt])
5656+ = "caml_int64_shift_right_by_int64" "caml_int64_shift_right_by_int64_unboxed"
5757+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
5858+5959+ external shift_right_logical
6060+ : (int64[@local_opt])
6161+ -> (int64[@local_opt])
6262+ -> (int64[@local_opt])
6363+ = "caml_int64_shift_right_logical_by_int64"
6464+ "caml_int64_shift_right_logical_by_int64_unboxed"
6565+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
6666+end
6767+6868+module Naive = Naive_ints.Make (struct
6969+ include Stdlib.Int64
7070+7171+ external compare : t -> t -> int = "%compare"
7272+ external equal : t -> t -> bool = "%equal"
7373+7474+ let bitwidth = 64L
7575+ end)
7676+7777+let[@inline always] count_leading_zeros n =
7878+ match Stubs.available with
7979+ | true -> Stubs.count_leading_zeros n
8080+ | false -> Naive.count_leading_zeros n
8181+;;
8282+8383+let[@inline always] count_leading_zeros_nonzero_arg n =
8484+ match Stubs.available with
8585+ | true -> Stubs.count_leading_zeros_nonzero_arg n
8686+ | false -> Naive.count_leading_zeros n
8787+;;
8888+8989+let[@inline always] count_trailing_zeros n =
9090+ match Stubs.available with
9191+ | true -> Stubs.count_trailing_zeros n
9292+ | false -> Naive.count_trailing_zeros n
9393+;;
9494+9595+let[@inline always] count_trailing_zeros_nonzero_arg n =
9696+ match Stubs.available with
9797+ | true -> Stubs.count_trailing_zeros_nonzero_arg n
9898+ | false -> Naive.count_trailing_zeros n
9999+;;
100100+101101+let[@inline always] count_set_bits n =
102102+ match Stubs.available with
103103+ | true -> Stubs.count_set_bits n
104104+ | false -> Naive.count_set_bits n
105105+;;
106106+107107+let[@inline always] shift_left x y =
108108+ match Stubs.available with
109109+ | true -> Stubs.shift_left x y
110110+ | false -> Naive.shift_left x y
111111+;;
112112+113113+let[@inline always] shift_right x y =
114114+ match Stubs.available with
115115+ | true -> Stubs.shift_right x y
116116+ | false -> Naive.shift_right x y
117117+;;
118118+119119+let[@inline always] shift_right_logical x y =
120120+ match Stubs.available with
121121+ | true -> Stubs.shift_right_logical x y
122122+ | false -> Naive.shift_right_logical x y
123123+;;
+48
vendor/opam/ocaml_intrinsics_kernel/src/int64.mli
···11+(** [count_leading_zeros n] returns the number of most-significant zero bits before the
22+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in [n],
33+ that is 64. *)
44+val count_leading_zeros : int64 -> int64
55+66+(** Same as [count_leading_zeros] except if the argument is zero, then the result is
77+ undefined. Emits more efficient code.
88+99+ This is no longer needed when using an flambda-backend compiler, which translates
1010+ [count_leading_zeros] to LZCNT by default (amd64). *)
1111+val count_leading_zeros_nonzero_arg : int64 -> int64
1212+1313+(** [count_trailing_zeros n] returns the number of least-significant zero bits before the
1414+ least significant set bit in [n]. If [n] is 0, the result is the number of bits in
1515+ [n], that is 64. *)
1616+val count_trailing_zeros : int64 -> int64
1717+1818+(** Same as [count_trailing_zeros] except if the argument is zero, then the result is
1919+ undefined. Emits more efficient code.
2020+2121+ This is no longer needed when using an flambda-backend compiler, which translates
2222+ [count_trailing_zeros] to TZCNT by default (amd64). *)
2323+val count_trailing_zeros_nonzero_arg : int64 -> int64
2424+2525+(** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
2626+2727+val count_set_bits : int64 -> int64
2828+2929+(** Shift operations below differ from the corresponding [Stdlib.Int64.shift_*] operations
3030+ in two ways:
3131+ (a) shift count (second argument) is the same type as the first argument, allowing
3232+ unboxed types to be used as counts.
3333+ (b) the operations are defined for arbitrary shift counts and rely on the hardware to
3434+ mask the count to [bitwidth-1] bits, where [bitwidth] is determined by the type of
3535+ the first argument. *)
3636+3737+(** [shift_left x y] shifts [x] to the left by [y & (bitwidth-1)] bits. *)
3838+val shift_left : int64 -> int64 -> int64
3939+4040+(** [Int64.shift_right x y] shifts [x] to the right by [y] bits. This is an arithmetic
4141+ shift: the sign bit of [x] is replicated and inserted in the vacated bits. *)
4242+val shift_right : int64 -> int64 -> int64
4343+4444+(** [Int64.shift_right_logical x y] shifts [x] to the right by [y] bits. This is a logical
4545+ shift: zeroes are inserted in the vacated bits regardless of the sign of [x]. *)
4646+val shift_right_logical : int64 -> int64 -> int64
4747+4848+module Naive : Naive_ints.S with type t = int64
···11+module type Intlike = sig
22+ type t
33+44+ val logand : t -> t -> t
55+ val zero : t
66+ val one : t
77+ val equal : t -> t -> bool
88+ val compare : t -> t -> int
99+ val shift_right : t -> int -> t
1010+ val shift_right_logical : t -> int -> t
1111+ val shift_left : t -> int -> t
1212+ val bitwidth : t
1313+ val to_int : t -> int
1414+ val of_int : int -> t
1515+end
1616+1717+module type S = sig
1818+ type t
1919+2020+ (** See documentation of [Int]. *)
2121+ val count_leading_zeros : t -> t
2222+2323+ val count_set_bits : t -> t
2424+ val count_trailing_zeros : t -> t
2525+ val shift_left : t -> t -> t
2626+ val shift_right : t -> t -> t
2727+ val shift_right_logical : t -> t -> t
2828+end
2929+3030+module Make (Int : Intlike) : S with type t = Int.t = struct
3131+ type t = Int.t
3232+3333+ let least_significant_bit n = Int.logand n Int.one
3434+3535+ let is_least_significant_bit_set n =
3636+ let lsb = least_significant_bit n in
3737+ if Int.equal lsb Int.one
3838+ then true
3939+ else if Int.equal lsb Int.zero
4040+ then false
4141+ else assert false
4242+ ;;
4343+4444+ let is_most_significant_bit_set n = if Int.compare n Int.zero < 0 then true else false
4545+4646+ let count_trailing_zeros n =
4747+ let rec loop ~acc ~mask =
4848+ if is_least_significant_bit_set mask
4949+ then acc
5050+ else (
5151+ let mask = Int.shift_right_logical mask 1 in
5252+ let acc = acc + 1 in
5353+ loop ~mask ~acc)
5454+ in
5555+ if Int.equal n Int.zero then Int.bitwidth else loop ~acc:0 ~mask:n |> Int.of_int
5656+ ;;
5757+5858+ let count_leading_zeros n =
5959+ let rec loop ~acc ~mask =
6060+ if is_most_significant_bit_set mask
6161+ then acc
6262+ else (
6363+ let mask = Int.shift_left mask 1 in
6464+ let acc = acc + 1 in
6565+ loop ~mask ~acc)
6666+ in
6767+ if Int.equal n Int.zero then Int.bitwidth else loop ~acc:0 ~mask:n |> Int.of_int
6868+ ;;
6969+7070+ let count_set_bits n =
7171+ let rec loop ~acc ~mask =
7272+ if Int.equal mask Int.zero
7373+ then acc
7474+ else (
7575+ let acc = if is_least_significant_bit_set mask then acc + 1 else acc in
7676+ let mask = Int.shift_right_logical mask 1 in
7777+ loop ~mask ~acc)
7878+ in
7979+ loop ~acc:0 ~mask:n |> Int.of_int
8080+ ;;
8181+8282+ let shift_mask = (Int.bitwidth |> Int.to_int) - 1 |> Int.of_int
8383+ let to_int_shift y = Int.logand y shift_mask |> Int.to_int
8484+ let shift_left x y = Int.shift_left x (to_int_shift y)
8585+ let shift_right x y = Int.shift_right x (to_int_shift y)
8686+ let shift_right_logical x y = Int.shift_right_logical x (to_int_shift y)
8787+end
···11+module type Intlike = sig
22+ type t
33+44+ val logand : t -> t -> t
55+ val zero : t
66+ val one : t
77+ val equal : t -> t -> bool
88+ val compare : t -> t -> int
99+ val shift_right : t -> int -> t
1010+ val shift_right_logical : t -> int -> t
1111+ val shift_left : t -> int -> t
1212+ val bitwidth : t
1313+ val to_int : t -> int
1414+ val of_int : int -> t
1515+end
1616+1717+module type S = sig
1818+ type t
1919+2020+ (** See documentation of [Int]. *)
2121+ val count_leading_zeros : t -> t
2222+2323+ val count_set_bits : t -> t
2424+ val count_trailing_zeros : t -> t
2525+ val shift_left : t -> t -> t
2626+ val shift_right : t -> t -> t
2727+ val shift_right_logical : t -> t -> t
2828+end
2929+3030+module Make (I : Intlike) : S with type t = I.t
···11+module Stubs = struct
22+ let available = Common.available
33+44+ (** [count_leading_zeros n] returns the number of most-significant zero bits before the
55+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in
66+ [n], that is 32 or 64, depending on the target. *)
77+ external count_leading_zeros
88+ : (nativeint[@unboxed] [@local_opt])
99+ -> (nativeint[@unboxed])
1010+ = "caml_nativeint_clz" "caml_nativeint_clz_unboxed_to_untagged"
1111+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
1212+1313+ (** Same as [count_leading_zeros] except if the argument is zero, then the result is
1414+ undefined. Emits more efficient code. *)
1515+ external count_leading_zeros_nonzero_arg
1616+ : (nativeint[@unboxed] [@local_opt])
1717+ -> (nativeint[@unboxed])
1818+ = "caml_nativeint_clz" "caml_nativeint_clz_nonzero_unboxed_to_untagged"
1919+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2020+2121+ (** [count_trailing_zeros n] returns the number of least-significant zero bits before
2222+ the least significant set bit in [n]. If [n] is 0, the result is the number of bits
2323+ in [n], that is 32 or 64, depending on the target. *)
2424+ external count_trailing_zeros
2525+ : (nativeint[@unboxed] [@local_opt])
2626+ -> (nativeint[@unboxed])
2727+ = "caml_nativeint_ctz" "caml_nativeint_ctz_unboxed_to_untagged"
2828+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
2929+3030+ (** Same as [count_trailing_zeros] except if the argument is zero, then the result is
3131+ undefined. Emits more efficient code. *)
3232+ external count_trailing_zeros_nonzero_arg
3333+ : (nativeint[@unboxed] [@local_opt])
3434+ -> (nativeint[@unboxed])
3535+ = "caml_nativeint_ctz" "caml_nativeint_ctz_nonzero_unboxed_to_untagged"
3636+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
3737+3838+ (** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
3939+ external count_set_bits
4040+ : (nativeint[@unboxed] [@local_opt])
4141+ -> (nativeint[@unboxed])
4242+ = "caml_nativeint_popcnt" "caml_nativeint_popcnt_unboxed_to_untagged"
4343+ [@@noalloc] [@@builtin] [@@no_effects] [@@no_coeffects]
4444+4545+ external shift_left
4646+ : (nativeint[@local_opt])
4747+ -> (nativeint[@local_opt])
4848+ -> (nativeint[@local_opt])
4949+ = "caml_nativeint_shift_left_by_nativeint"
5050+ "caml_nativeint_shift_left_by_nativeint_unboxed"
5151+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
5252+5353+ external shift_right
5454+ : (nativeint[@local_opt])
5555+ -> (nativeint[@local_opt])
5656+ -> (nativeint[@local_opt])
5757+ = "caml_nativeint_shift_right_by_nativeint"
5858+ "caml_nativeint_shift_right_by_nativeint_unboxed"
5959+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
6060+6161+ external shift_right_logical
6262+ : (nativeint[@local_opt])
6363+ -> (nativeint[@local_opt])
6464+ -> (nativeint[@local_opt])
6565+ = "caml_nativeint_shift_right_logical_by_nativeint"
6666+ "caml_nativeint_shift_right_logical_by_nativeint_unboxed"
6767+ [@@noalloc] (* [@@builtin] *) [@@no_effects] [@@no_coeffects] [@@unboxed]
6868+end
6969+7070+module Naive = Naive_ints.Make (struct
7171+ include Stdlib.Nativeint
7272+7373+ external compare : t -> t -> int = "%compare"
7474+ external equal : t -> t -> bool = "%equal"
7575+7676+ let bitwidth = Sys.word_size |> of_int
7777+ end)
7878+7979+let[@inline always] count_leading_zeros n =
8080+ match Stubs.available with
8181+ | true -> Stubs.count_leading_zeros n
8282+ | false -> Naive.count_leading_zeros n
8383+;;
8484+8585+let[@inline always] count_leading_zeros_nonzero_arg n =
8686+ match Stubs.available with
8787+ | true -> Stubs.count_leading_zeros_nonzero_arg n
8888+ | false -> Naive.count_leading_zeros n
8989+;;
9090+9191+let[@inline always] count_trailing_zeros n =
9292+ match Stubs.available with
9393+ | true -> Stubs.count_trailing_zeros n
9494+ | false -> Naive.count_trailing_zeros n
9595+;;
9696+9797+let[@inline always] count_trailing_zeros_nonzero_arg n =
9898+ match Stubs.available with
9999+ | true -> Stubs.count_trailing_zeros_nonzero_arg n
100100+ | false -> Naive.count_trailing_zeros n
101101+;;
102102+103103+let[@inline always] count_set_bits n =
104104+ match Stubs.available with
105105+ | true -> Stubs.count_set_bits n
106106+ | false -> Naive.count_set_bits n
107107+;;
108108+109109+let[@inline always] shift_left x y =
110110+ match Stubs.available with
111111+ | true -> Stubs.shift_left x y
112112+ | false -> Naive.shift_left x y
113113+;;
114114+115115+let[@inline always] shift_right x y =
116116+ match Stubs.available with
117117+ | true -> Stubs.shift_right x y
118118+ | false -> Naive.shift_right x y
119119+;;
120120+121121+let[@inline always] shift_right_logical x y =
122122+ match Stubs.available with
123123+ | true -> Stubs.shift_right_logical x y
124124+ | false -> Naive.shift_right_logical x y
125125+;;
···11+(** [count_leading_zeros n] returns the number of most-significant zero bits before the
22+ most significant set bit in [n]. If [n] is 0, the result is the number of bits in [n],
33+ that is 32 or 64, depending on the target. *)
44+val count_leading_zeros : nativeint -> nativeint
55+66+(** Same as [count_leading_zeros] except if the argument is zero, then the result is
77+ undefined. Emits more efficient code.
88+99+ This is no longer needed when using an flambda-backend compiler, which translates
1010+ [count_leading_zeros] to LZCNT by default (amd64). *)
1111+val count_leading_zeros_nonzero_arg : nativeint -> nativeint
1212+1313+(** [count_trailing_zeros n] returns the number of least-significant zero bits before the
1414+ least significant set bit in [n]. If [n] is 0, the result is the number of bits in
1515+ [n], that is 32 or 64, depending on the target. *)
1616+val count_trailing_zeros : nativeint -> nativeint
1717+1818+(** Same as [count_trailing_zeros] except if the argument is zero, then the result is
1919+ undefined. Emits more efficient code.
2020+2121+ This is no longer needed when using an flambda-backend compiler, which translates
2222+ [count_trailing_zeros] to TZCNT by default (amd64). *)
2323+val count_trailing_zeros_nonzero_arg : nativeint -> nativeint
2424+2525+(** [count_set_bits n] returns the number of bits that are 1 in [n]. *)
2626+val count_set_bits : nativeint -> nativeint
2727+2828+(** Shift operations below differ from the corresponding [Stdlib.Nativeint.shift_*]
2929+ operations in two ways:
3030+ (a) shift count (second argument) is the same type as the first argument, allowing
3131+ unboxed types to be used as counts.
3232+ (b) the operations are defined for arbitrary shift counts and rely on the hardware to
3333+ mask the shift to [bitwidth-1] bits, where [bitwidth] is determined by the type of
3434+ the first argument. *)
3535+3636+(** [shift_left x y] shifts [x] to the left by [y & (bitwidth-1)] bits. *)
3737+val shift_left : nativeint -> nativeint -> nativeint
3838+3939+(** [Nativeint.shift_right x y] shifts [x] to the right by [y] bits. This is an arithmetic
4040+ shift: the sign bit of [x] is replicated and inserted in the vacated bits. *)
4141+val shift_right : nativeint -> nativeint -> nativeint
4242+4343+(** [Nativeint.shift_right_logical x y] shifts [x] to the right by [y] bits. This is a
4444+ logical shift: zeroes are inserted in the vacated bits regardless of the sign of [x]. *)
4545+val shift_right_logical : nativeint -> nativeint -> nativeint
4646+4747+module Naive : Naive_ints.S with type t = nativeint
···11+open Base
22+open Stdio
33+44+module type Hum = sig
55+ type t
66+77+ val to_string_hum : ?delimiter:char -> t -> string
88+end
99+1010+module Hum_string (H : Hum) = struct
1111+ include H
1212+1313+ let to_string = to_string_hum
1414+end
1515+1616+let test
1717+ (type i o)
1818+ (module Input : Hum with type t = i)
1919+ (module Output : Stringable.S with type t = o)
2020+ ~name
2121+ ~op
2222+ x
2323+ =
2424+ let module Input = Hum_string (Input) in
2525+ print_endline [%string "%{name} %{x#Input} = %{op x#Output}"]
2626+;;
2727+2828+let test_shifts
2929+ (type t)
3030+ (module Input : Hum with type t = t)
3131+ (module Shift : Hum with type t = t)
3232+ ~name
3333+ ~(op : t -> t -> t)
3434+ ~(expected_op : t -> t -> t)
3535+ x
3636+ y
3737+ =
3838+ let module Input = Hum_string (Input) in
3939+ let module Shift = Hum_string (Shift) in
4040+ let expected = expected_op x y in
4141+ let res = op x y in
4242+ print_endline [%string "%{x#Input} %{name} by %{y#Shift} ="];
4343+ print_endline [%string.global "%{res#Input}"];
4444+ if Stdlib.compare res expected <> 0
4545+ then print_endline [%string "%{expected#Input} expected"]
4646+;;
···11+open Base
22+open Stdio
33+module I = Ocaml_intrinsics_kernel.Conditional
44+55+let%expect_test "csel int" =
66+ let inputs = [ 0; 1; 4; 6; 5 ] in
77+ List.iter inputs ~f:(fun a ->
88+ let expect = if a % 2 = 0 then a else a + 1 in
99+ let actual = I.select_value (a % 2 = 0) a (a + 1) in
1010+ printf "%d %d\n" expect actual);
1111+ [%expect
1212+ {|
1313+ 0 0
1414+ 2 2
1515+ 4 4
1616+ 6 6
1717+ 6 6
1818+ |}]
1919+;;
2020+2121+let%expect_test "csel max int value" =
2222+ let inputs = [ 0, 1; 4, 5 ] in
2323+ List.iter inputs ~f:(fun (a, b) ->
2424+ let expect = if a > b then a else b in
2525+ let actual = I.select_value (a > b) a b in
2626+ printf "%d %d\n" expect actual);
2727+ [%expect
2828+ {|
2929+ 1 1
3030+ 5 5
3131+ |}]
3232+;;
3333+3434+let%expect_test "csel max float value" =
3535+ let inputs = [ 0.5, Float.neg_infinity; 0.0, 0.1; Float.nan, 5.0 ] in
3636+ List.iter inputs ~f:(fun (a, b) ->
3737+ let expect = if Float.(a > b) then a else b in
3838+ let actual = I.select_value Float.(a > b) a b in
3939+ printf "%f %f\n" expect actual);
4040+ [%expect
4141+ {|
4242+ 0.500000 0.500000
4343+ 0.100000 0.100000
4444+ 5.000000 5.000000
4545+ |}]
4646+;;
4747+4848+let%expect_test "csel max int untagged" =
4949+ let inputs = [ 0, 1; 4, 5 ] in
5050+ List.iter inputs ~f:(fun (a, b) ->
5151+ let expect = if a > b then a else b in
5252+ let actual = I.select_int (a > b) a b in
5353+ printf "%d %d\n" expect actual);
5454+ [%expect
5555+ {|
5656+ 1 1
5757+ 5 5
5858+ |}]
5959+;;
6060+6161+let%expect_test "csel max int64 unboxed" =
6262+ let inputs = [ 0L, 1L; 4L, 5L; Int64.max_value, Int64.min_value ] in
6363+ List.iter inputs ~f:(fun (a, b) ->
6464+ let expect = if Int64.(a > b) then a else b in
6565+ let actual = I.select_int64 Int64.(a > b) a b in
6666+ printf "%Ld %Ld\n" expect actual);
6767+ [%expect
6868+ {|
6969+ 1 1
7070+ 5 5
7171+ 9223372036854775807 9223372036854775807
7272+ |}]
7373+;;
7474+7575+let%expect_test "csel max int64#" =
7676+ let inputs = [ 0L, 1L; 4L, 5L; Int64.max_value, Int64.min_value ] in
7777+ List.iter inputs ~f:(fun (a, b) ->
7878+ let a = Int64_u.of_int64 a in
7979+ let b = Int64_u.of_int64 b in
8080+ let expect = if Int64_u.(a > b) then a else b in
8181+ let actual = I.Unboxed.select_int64 Int64_u.(a > b) a b in
8282+ printf "%Ld %Ld\n" (Int64_u.to_int64 expect) (Int64_u.to_int64 actual));
8383+ [%expect
8484+ {|
8585+ 1 1
8686+ 5 5
8787+ 9223372036854775807 9223372036854775807
8888+ |}]
8989+;;
9090+9191+let%expect_test "csel max int32 unboxed" =
9292+ let inputs = [ 0l, 1l; 4l, 5l; Int32.max_value, Int32.min_value ] in
9393+ List.iter inputs ~f:(fun (a, b) ->
9494+ let expect = if Int32.(a > b) then a else b in
9595+ let actual = I.select_int32 Int32.(a > b) a b in
9696+ printf "%ld %ld\n" expect actual);
9797+ [%expect
9898+ {|
9999+ 1 1
100100+ 5 5
101101+ 2147483647 2147483647
102102+ |}]
103103+;;
104104+105105+let%expect_test "csel max int32#" =
106106+ let inputs = [ 0l, 1l; 4l, 5l; Int32.max_value, Int32.min_value ] in
107107+ List.iter inputs ~f:(fun (a, b) ->
108108+ let a = Int32_u.of_int32 a in
109109+ let b = Int32_u.of_int32 b in
110110+ let expect = if Int32_u.(a > b) then a else b in
111111+ let actual = I.Unboxed.select_int32 Int32_u.(a > b) a b in
112112+ printf "%ld %ld\n" (Int32_u.to_int32 expect) (Int32_u.to_int32 actual));
113113+ [%expect
114114+ {|
115115+ 1 1
116116+ 5 5
117117+ 2147483647 2147483647
118118+ |}]
119119+;;
120120+121121+module%test [@tags "64-bits-only"] Arch64 = struct
122122+ let%expect_test "csel max nativeint unboxed" =
123123+ let inputs = [ 0n, 1n; 4n, 5n; Nativeint.max_value, Nativeint.min_value ] in
124124+ List.iter inputs ~f:(fun (a, b) ->
125125+ let expect = if Nativeint.(a > b) then a else b in
126126+ let actual = I.select_nativeint Nativeint.(a > b) a b in
127127+ printf "%nd %nd\n" expect actual);
128128+ [%expect
129129+ {|
130130+ 1 1
131131+ 5 5
132132+ 9223372036854775807 9223372036854775807
133133+ |}]
134134+ ;;
135135+136136+ let%expect_test "csel max nativeint#" =
137137+ let inputs = [ 0n, 1n; 4n, 5n; Nativeint.max_value, Nativeint.min_value ] in
138138+ List.iter inputs ~f:(fun (a, b) ->
139139+ let a = Nativeint_u.of_nativeint a in
140140+ let b = Nativeint_u.of_nativeint b in
141141+ let expect = if Nativeint_u.(a > b) then a else b in
142142+ let actual = I.Unboxed.select_nativeint Nativeint_u.(a > b) a b in
143143+ printf
144144+ "%nd %nd\n"
145145+ (Nativeint_u.to_nativeint expect)
146146+ (Nativeint_u.to_nativeint actual));
147147+ [%expect
148148+ {|
149149+ 1 1
150150+ 5 5
151151+ 9223372036854775807 9223372036854775807
152152+ |}]
153153+ ;;
154154+end
155155+156156+module%test [@tags "32-bits-only", "js-only"] Arch32 = struct
157157+ let%expect_test "csel max nativeint unboxed" =
158158+ let inputs = [ 0n, 1n; 4n, 5n; Nativeint.max_value, Nativeint.min_value ] in
159159+ List.iter inputs ~f:(fun (a, b) ->
160160+ let expect = if Nativeint.(a > b) then a else b in
161161+ let actual = I.select_nativeint Nativeint.(a > b) a b in
162162+ printf "%nd %nd\n" expect actual);
163163+ [%expect
164164+ {|
165165+ 1 1
166166+ 5 5
167167+ 2147483647 2147483647
168168+ |}]
169169+ ;;
170170+171171+ let%expect_test "csel max nativeint#" =
172172+ let inputs = [ 0n, 1n; 4n, 5n; Nativeint.max_value, Nativeint.min_value ] in
173173+ List.iter inputs ~f:(fun (a, b) ->
174174+ let a = Nativeint_u.of_nativeint a in
175175+ let b = Nativeint_u.of_nativeint b in
176176+ let expect = if Nativeint_u.(a > b) then a else b in
177177+ let actual = I.Unboxed.select_nativeint Nativeint_u.(a > b) a b in
178178+ printf
179179+ "%nd %nd\n"
180180+ (Nativeint_u.to_nativeint expect)
181181+ (Nativeint_u.to_nativeint actual));
182182+ [%expect
183183+ {|
184184+ 1 1
185185+ 5 5
186186+ 2147483647 2147483647
187187+ |}]
188188+ ;;
189189+end
190190+191191+let%expect_test "csel sideffects" =
192192+ let inputs = [ 0, 1; 5, 4 ] in
193193+ List.iter inputs ~f:(fun (a, b) ->
194194+ let expect =
195195+ if a > b
196196+ then (
197197+ printf "hello 0\n";
198198+ a)
199199+ else (
200200+ printf "world 0\n";
201201+ b)
202202+ in
203203+ let actual =
204204+ I.select_value
205205+ (a > b)
206206+ (printf "hello 1\n";
207207+ a)
208208+ (printf "world 1\n";
209209+ b)
210210+ in
211211+ printf "%d %d\n" expect actual);
212212+ [%expect
213213+ {|
214214+ world 0
215215+ world 1
216216+ hello 1
217217+ 1 1
218218+ hello 0
219219+ world 1
220220+ hello 1
221221+ 5 5
222222+ |}]
223223+;;
224224+225225+let%expect_test "min extra moves" =
226226+ (* Currently [min] emits extra moves:
227227+ *
228228+ * actual:
229229+ *
230230+ * camlT__min_266:
231231+ * movq %rax, %rdi
232232+ * movq %rbx, %rax
233233+ * cmpq %rax, %rdi
234234+ * cmovl %rdi, %rax
235235+ * ret
236236+ *
237237+ * [min2] is
238238+ *
239239+ * camlT__min2_273:
240240+ * cmpq %rax, %rbx
241241+ * cmovl %rbx, %rax
242242+ * ret
243243+ * ret *)
244244+ let[@inline never] min (x : int) (y : int) = I.select_value (x < y) x y in
245245+ let[@inline never] min2 (x : int) (y : int) = I.select_value (y < x) y x in
246246+ let inputs = [ 0, 1; 5, 4 ] in
247247+ List.iter inputs ~f:(fun (a, b) ->
248248+ printf "%d " (min a b);
249249+ printf "%d\n" (min2 a b));
250250+ [%expect
251251+ {|
252252+ 0 0
253253+ 4 4
254254+ |}]
255255+;;
256256+257257+let%expect_test "float deadcode" =
258258+ (* Currently [nop_float] emits extra loads, because there is no dead code elimination
259259+ * after register allocation:
260260+ *
261261+ * camlT__nop_float_292:
262262+ * movsd (%rbx), %xmm0
263263+ * movsd (%rax), %xmm1
264264+ * ret *)
265265+ let[@inline never] nop_float (x : float) (y : float) : float =
266266+ I.select_value Float.(x > y) x x
267267+ in
268268+ let inputs =
269269+ [ 0.5, Float.neg_infinity; 0.0, 0.1; Float.nan, 5.0; Float.infinity, -0.0 ]
270270+ in
271271+ List.iter inputs ~f:(fun (a, b) -> printf "%f " (nop_float a b));
272272+ [%expect {| 0.500000 0.000000 nan inf |}]
273273+;;