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