@@ -4691,3 +4691,270 @@ let reperform ~dbg ~eff ~cont ~last_fiber =
4691
4691
dbg )
4692
4692
4693
4693
let poll ~dbg = return_unit dbg (Cop (Cpoll , [] , dbg))
4694
+
4695
+ module Scalar_type = struct
4696
+ module Float_width = struct
4697
+ type t = Cmm .float_width =
4698
+ | Float64
4699
+ | Float32
4700
+
4701
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4702
+ match src, dst with
4703
+ | Float64 , Float64 -> exp
4704
+ | Float32 , Float32 -> exp
4705
+ | Float32 , Float64 -> float_of_float32 ~dbg exp
4706
+ | Float64 , Float32 -> float32_of_float ~dbg exp
4707
+ end
4708
+
4709
+ module Signedness = struct
4710
+ type t =
4711
+ | Signed
4712
+ | Unsigned
4713
+
4714
+ let equal (x : t ) (y : t ) = x = y
4715
+
4716
+ let print ppf t =
4717
+ match t with
4718
+ | Signed -> Format. pp_print_string ppf " signed"
4719
+ | Unsigned -> Format. pp_print_string ppf " unsigned"
4720
+ end
4721
+
4722
+ module Bit_width_and_signedness : sig
4723
+ (* * An integer with signedness [signedness t] that fits into a general-purpose
4724
+ register. It is canonically stored in twos-complement representation, in the lower
4725
+ [bits] bits of its container (whether that be memory or a register), and is sign-
4726
+ or zero-extended to fill the entire container. *)
4727
+ type t [@@immediate]
4728
+
4729
+ val create_exn : bit_width :int -> signedness :Signedness .t -> t
4730
+
4731
+ val bit_width : t -> int
4732
+
4733
+ val signedness : t -> Signedness .t
4734
+
4735
+ val equal : t -> t -> bool
4736
+ end = struct
4737
+ (* [signedness t] is stored in the low bit of [t], and [bit_width t] is
4738
+ stored in the remaining high bits of [t]. We use this encoding to fit [t]
4739
+ into an immediate value. This is worth trying since we expect to create
4740
+ one of these for ~every integer operation, so it should cut down on
4741
+ garbage *)
4742
+ type t = { bit_width_and_signedness : int } [@@ unboxed]
4743
+
4744
+ let [@ inline] equal { bit_width_and_signedness = x }
4745
+ { bit_width_and_signedness = y } =
4746
+ Int. equal x y
4747
+
4748
+ let [@ inline] bit_width { bit_width_and_signedness } =
4749
+ bit_width_and_signedness lsr 1
4750
+
4751
+ let [@ inline] signedness { bit_width_and_signedness } =
4752
+ match bit_width_and_signedness land 1 with
4753
+ | 0 -> Signedness. Signed
4754
+ | 1 -> Signedness. Unsigned
4755
+ | _ -> assert false
4756
+
4757
+ let [@ inline] int_of_signedness : Signedness. t -> int = function
4758
+ | Signed -> 0
4759
+ | Unsigned -> 1
4760
+
4761
+ let [@ inline] create_exn ~bit_width ~signedness =
4762
+ assert (0 < bit_width && bit_width < = arch_bits);
4763
+ { bit_width_and_signedness =
4764
+ (bit_width lsl 1 ) + int_of_signedness signedness
4765
+ }
4766
+ end
4767
+
4768
+ module Integral_type = struct
4769
+ include Bit_width_and_signedness
4770
+
4771
+ let [@ inline] with_signedness t ~signedness =
4772
+ create_exn ~bit_width: (bit_width t) ~signedness
4773
+
4774
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4775
+
4776
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4777
+
4778
+ (* * Determines whether [dst] can represent every value of [src], preserving sign *)
4779
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4780
+ match signedness src, signedness dst with
4781
+ | Signed , Signed | Unsigned , Unsigned -> bit_width src < = bit_width dst
4782
+ | Unsigned , Signed -> bit_width src < bit_width dst
4783
+ | Signed , Unsigned -> false
4784
+
4785
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4786
+ if can_cast_without_losing_information ~src ~dst
4787
+ then
4788
+ (* Since [Bit_width_and_signedness] represents sign- or zero-extended
4789
+ expressions, this is a no-op *)
4790
+ exp
4791
+ else
4792
+ match signedness dst with
4793
+ | Signed -> sign_extend ~bits: (bit_width dst) exp ~dbg
4794
+ | Unsigned -> zero_extend ~bits: (bit_width dst) exp ~dbg
4795
+
4796
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4797
+ x
4798
+ |> static_cast ~src: outer ~dst: inner ~dbg
4799
+ |> f
4800
+ |> static_cast ~src: inner ~dst: outer ~dbg
4801
+ end
4802
+
4803
+ module Integer = struct
4804
+ include Integral_type
4805
+
4806
+ let print ppf t =
4807
+ Format. fprintf ppf " %a int%d" Signedness. print (signedness t)
4808
+ (bit_width t)
4809
+
4810
+ let nativeint = create_exn ~bit_width: arch_bits ~signedness: Signed
4811
+ end
4812
+
4813
+ (* * An {!Integer.t} but with the additional stipulation that its container must
4814
+ reserve its lowest bit to be 1. The [bit_width] field includes this bit. *)
4815
+ module Tagged_integer = struct
4816
+ include Integral_type
4817
+
4818
+ let [@ inline] create_exn ~bit_width_including_tag_bit: bit_width ~signedness =
4819
+ assert (bit_width > 1 );
4820
+ create_exn ~bit_width ~signedness
4821
+
4822
+ let immediate =
4823
+ create_exn ~bit_width_including_tag_bit: arch_bits ~signedness: Signed
4824
+
4825
+ let [@ inline] bit_width_including_tag_bit t = bit_width t
4826
+
4827
+ let [@ inline] bit_width_excluding_tag_bit t = bit_width t - 1
4828
+
4829
+ let [@ inline] untagged t =
4830
+ Integer. create_exn
4831
+ ~bit_width: (bit_width_excluding_tag_bit t)
4832
+ ~signedness: (signedness t)
4833
+
4834
+ let [@ inline] untag ~dbg t exp =
4835
+ match signedness t with
4836
+ | Signed -> asr_const exp 1 dbg
4837
+ | Unsigned -> lsr_const exp 1 dbg
4838
+
4839
+ let print ppf t =
4840
+ Format. fprintf ppf " tagged %a int%d" Signedness. print (signedness t)
4841
+ (bit_width_excluding_tag_bit t)
4842
+ end
4843
+
4844
+ module Integral = struct
4845
+ type t =
4846
+ | Untagged of Integer .t
4847
+ | Tagged of Tagged_integer .t
4848
+
4849
+ let nativeint = Untagged Integer. nativeint
4850
+
4851
+ let [@ inline] untagged_or_identity = function
4852
+ | Untagged t -> t
4853
+ | Tagged t -> Tagged_integer. untagged t
4854
+
4855
+ let signedness = function
4856
+ | Untagged t -> Integer. signedness t
4857
+ | Tagged t -> Tagged_integer. signedness t
4858
+
4859
+ let with_signedness t ~signedness =
4860
+ match t with
4861
+ | Untagged t -> Untagged (Integer. with_signedness t ~signedness )
4862
+ | Tagged t -> Tagged (Tagged_integer. with_signedness t ~signedness )
4863
+
4864
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4865
+
4866
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4867
+
4868
+ let [@ inline] equal x y =
4869
+ match x, y with
4870
+ | Untagged x , Untagged y -> Integer. equal x y
4871
+ | Untagged _ , _ -> false
4872
+ | Tagged x , Tagged y -> Tagged_integer. equal x y
4873
+ | Tagged _ , _ -> false
4874
+
4875
+ let print ppf t =
4876
+ match t with
4877
+ | Untagged untagged -> Integer. print ppf untagged
4878
+ | Tagged tagged -> Tagged_integer. print ppf tagged
4879
+
4880
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4881
+ Integer. can_cast_without_losing_information
4882
+ ~src: (untagged_or_identity src) ~dst: (untagged_or_identity dst)
4883
+
4884
+ let static_cast ~dbg ~src ~dst exp =
4885
+ match src, dst with
4886
+ | Untagged src , Untagged dst -> Integer. static_cast ~dbg ~src ~dst exp
4887
+ | Tagged src , Tagged dst -> Tagged_integer. static_cast ~dbg ~src ~dst exp
4888
+ | Untagged src , Tagged dst ->
4889
+ tag_int
4890
+ (Integer. static_cast ~dbg ~src ~dst: (Tagged_integer. untagged dst) exp)
4891
+ dbg
4892
+ | Tagged src , Untagged dst ->
4893
+ Integer. static_cast ~dbg
4894
+ ~src: (Tagged_integer. untagged src)
4895
+ ~dst
4896
+ (Tagged_integer. untag ~dbg src exp)
4897
+
4898
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4899
+ x
4900
+ |> static_cast ~src: outer ~dst: inner ~dbg
4901
+ |> f
4902
+ |> static_cast ~src: inner ~dst: outer ~dbg
4903
+ end
4904
+
4905
+ type t =
4906
+ | Integral of Integral .t
4907
+ | Float of Float_width .t
4908
+
4909
+ let static_cast ~dbg ~src ~dst exp =
4910
+ match src, dst with
4911
+ | Integral src , Integral dst -> Integral. static_cast ~dbg ~src ~dst exp
4912
+ | Float src , Float dst -> Float_width. static_cast ~dbg ~src ~dst exp
4913
+ | Integral src , Float dst ->
4914
+ let float_of_int_arg = Integral. nativeint in
4915
+ if not
4916
+ (Integral. can_cast_without_losing_information ~src
4917
+ ~dst: float_of_int_arg)
4918
+ then
4919
+ Misc. fatal_errorf " static_cast: casting %a to float is not implemented"
4920
+ Integral. print src
4921
+ else
4922
+ unary (Cstatic_cast (Float_of_int dst)) ~dbg
4923
+ (Integral. static_cast exp ~dbg ~src ~dst: float_of_int_arg)
4924
+ | Float src , Integral dst -> (
4925
+ match Integral. signedness dst with
4926
+ | Unsigned ->
4927
+ Misc. fatal_errorf
4928
+ " static_cast: casting floats to unsigned values is not implemented"
4929
+ | Signed ->
4930
+ (* we can truncate because casting from float -> int is unspecified when
4931
+ the rounded value doesn't fit in the integral type. We can't promote
4932
+ since nativeint is already the largest integral type supported
4933
+ here. *)
4934
+ let exp = unary (Cstatic_cast (Int_of_float src)) exp ~dbg in
4935
+ let src = Integral. nativeint in
4936
+ (* assert that nativeint is indeed the largest integer width *)
4937
+ assert (Integral. can_cast_without_losing_information ~src: dst ~dst: src);
4938
+ Integral. static_cast exp ~dbg ~src ~dst )
4939
+
4940
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4941
+ x
4942
+ |> static_cast ~src: outer ~dst: inner ~dbg
4943
+ |> f
4944
+ |> static_cast ~src: inner ~dst: outer ~dbg
4945
+
4946
+ module Untagged = struct
4947
+ type numeric = t
4948
+
4949
+ type t =
4950
+ | Untagged of Integer .t
4951
+ | Float of float_width
4952
+
4953
+ let to_numeric : t -> numeric = function
4954
+ | Untagged width -> Integral (Untagged width)
4955
+ | Float float -> Float float
4956
+
4957
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4958
+ static_cast ~dbg ~src: (to_numeric src) ~dst: (to_numeric dst) exp
4959
+ end
4960
+ end
0 commit comments