@@ -4551,3 +4551,270 @@ let reperform ~dbg ~eff ~cont ~last_fiber =
4551
4551
dbg )
4552
4552
4553
4553
let poll ~dbg = return_unit dbg (Cop (Cpoll , [] , dbg))
4554
+
4555
+ module Scalar_type = struct
4556
+ module Float_width = struct
4557
+ type t = Cmm .float_width =
4558
+ | Float64
4559
+ | Float32
4560
+
4561
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4562
+ match src, dst with
4563
+ | Float64 , Float64 -> exp
4564
+ | Float32 , Float32 -> exp
4565
+ | Float32 , Float64 -> float_of_float32 ~dbg exp
4566
+ | Float64 , Float32 -> float32_of_float ~dbg exp
4567
+ end
4568
+
4569
+ module Signedness = struct
4570
+ type t =
4571
+ | Signed
4572
+ | Unsigned
4573
+
4574
+ let equal (x : t ) (y : t ) = x = y
4575
+
4576
+ let print ppf t =
4577
+ match t with
4578
+ | Signed -> Format. pp_print_string ppf " signed"
4579
+ | Unsigned -> Format. pp_print_string ppf " unsigned"
4580
+ end
4581
+
4582
+ module Bit_width_and_signedness : sig
4583
+ (* * An integer with signedness [signedness t] that fits into a general-purpose
4584
+ register. It is canonically stored in twos-complement representation, in the lower
4585
+ [bits] bits of its container (whether that be memory or a register), and is sign-
4586
+ or zero-extended to fill the entire container. *)
4587
+ type t [@@immediate]
4588
+
4589
+ val create_exn : bit_width :int -> signedness :Signedness .t -> t
4590
+
4591
+ val bit_width : t -> int
4592
+
4593
+ val signedness : t -> Signedness .t
4594
+
4595
+ val equal : t -> t -> bool
4596
+ end = struct
4597
+ (* [signedness t] is stored in the low bit of [t], and [bit_width t] is
4598
+ stored in the remaining high bits of [t]. We use this encoding to fit [t]
4599
+ into an immediate value. This is worth trying since we expect to create
4600
+ one of these for ~every integer operation, so it should cut down on
4601
+ garbage *)
4602
+ type t = { bit_width_and_signedness : int } [@@ unboxed]
4603
+
4604
+ let [@ inline] equal { bit_width_and_signedness = x }
4605
+ { bit_width_and_signedness = y } =
4606
+ Int. equal x y
4607
+
4608
+ let [@ inline] bit_width { bit_width_and_signedness } =
4609
+ bit_width_and_signedness lsr 1
4610
+
4611
+ let [@ inline] signedness { bit_width_and_signedness } =
4612
+ match bit_width_and_signedness land 1 with
4613
+ | 0 -> Signedness. Signed
4614
+ | 1 -> Signedness. Unsigned
4615
+ | _ -> assert false
4616
+
4617
+ let [@ inline] int_of_signedness : Signedness. t -> int = function
4618
+ | Signed -> 0
4619
+ | Unsigned -> 1
4620
+
4621
+ let [@ inline] create_exn ~bit_width ~signedness =
4622
+ assert (0 < bit_width && bit_width < = arch_bits);
4623
+ { bit_width_and_signedness =
4624
+ (bit_width lsl 1 ) + int_of_signedness signedness
4625
+ }
4626
+ end
4627
+
4628
+ module Integral_type = struct
4629
+ include Bit_width_and_signedness
4630
+
4631
+ let [@ inline] with_signedness t ~signedness =
4632
+ create_exn ~bit_width: (bit_width t) ~signedness
4633
+
4634
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4635
+
4636
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4637
+
4638
+ (* * Determines whether [dst] can represent every value of [src], preserving sign *)
4639
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4640
+ match signedness src, signedness dst with
4641
+ | Signed , Signed | Unsigned , Unsigned -> bit_width src < = bit_width dst
4642
+ | Unsigned , Signed -> bit_width src < bit_width dst
4643
+ | Signed , Unsigned -> false
4644
+
4645
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4646
+ if can_cast_without_losing_information ~src ~dst
4647
+ then
4648
+ (* Since [Bit_width_and_signedness] represents sign- or zero-extended
4649
+ expressions, this is a no-op *)
4650
+ exp
4651
+ else
4652
+ match signedness dst with
4653
+ | Signed -> sign_extend ~bits: (bit_width dst) exp ~dbg
4654
+ | Unsigned -> zero_extend ~bits: (bit_width dst) exp ~dbg
4655
+
4656
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4657
+ x
4658
+ |> static_cast ~src: outer ~dst: inner ~dbg
4659
+ |> f
4660
+ |> static_cast ~src: inner ~dst: outer ~dbg
4661
+ end
4662
+
4663
+ module Integer = struct
4664
+ include Integral_type
4665
+
4666
+ let print ppf t =
4667
+ Format. fprintf ppf " %a int%d" Signedness. print (signedness t)
4668
+ (bit_width t)
4669
+
4670
+ let nativeint = create_exn ~bit_width: arch_bits ~signedness: Signed
4671
+ end
4672
+
4673
+ (* * An {!Integer.t} but with the additional stipulation that its container must
4674
+ reserve its lowest bit to be 1. The [bit_width] field includes this bit. *)
4675
+ module Tagged_integer = struct
4676
+ include Integral_type
4677
+
4678
+ let [@ inline] create_exn ~bit_width_including_tag_bit: bit_width ~signedness =
4679
+ assert (bit_width > 1 );
4680
+ create_exn ~bit_width ~signedness
4681
+
4682
+ let immediate =
4683
+ create_exn ~bit_width_including_tag_bit: arch_bits ~signedness: Signed
4684
+
4685
+ let [@ inline] bit_width_including_tag_bit t = bit_width t
4686
+
4687
+ let [@ inline] bit_width_excluding_tag_bit t = bit_width t - 1
4688
+
4689
+ let [@ inline] untagged t =
4690
+ Integer. create_exn
4691
+ ~bit_width: (bit_width_excluding_tag_bit t)
4692
+ ~signedness: (signedness t)
4693
+
4694
+ let [@ inline] untag ~dbg t exp =
4695
+ match signedness t with
4696
+ | Signed -> asr_const exp 1 dbg
4697
+ | Unsigned -> lsr_const exp 1 dbg
4698
+
4699
+ let print ppf t =
4700
+ Format. fprintf ppf " tagged %a int%d" Signedness. print (signedness t)
4701
+ (bit_width_excluding_tag_bit t)
4702
+ end
4703
+
4704
+ module Integral = struct
4705
+ type t =
4706
+ | Untagged of Integer .t
4707
+ | Tagged of Tagged_integer .t
4708
+
4709
+ let nativeint = Untagged Integer. nativeint
4710
+
4711
+ let [@ inline] untagged_or_identity = function
4712
+ | Untagged t -> t
4713
+ | Tagged t -> Tagged_integer. untagged t
4714
+
4715
+ let signedness = function
4716
+ | Untagged t -> Integer. signedness t
4717
+ | Tagged t -> Tagged_integer. signedness t
4718
+
4719
+ let with_signedness t ~signedness =
4720
+ match t with
4721
+ | Untagged t -> Untagged (Integer. with_signedness t ~signedness )
4722
+ | Tagged t -> Tagged (Tagged_integer. with_signedness t ~signedness )
4723
+
4724
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4725
+
4726
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4727
+
4728
+ let [@ inline] equal x y =
4729
+ match x, y with
4730
+ | Untagged x , Untagged y -> Integer. equal x y
4731
+ | Untagged _ , _ -> false
4732
+ | Tagged x , Tagged y -> Tagged_integer. equal x y
4733
+ | Tagged _ , _ -> false
4734
+
4735
+ let print ppf t =
4736
+ match t with
4737
+ | Untagged untagged -> Integer. print ppf untagged
4738
+ | Tagged tagged -> Tagged_integer. print ppf tagged
4739
+
4740
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4741
+ Integer. can_cast_without_losing_information
4742
+ ~src: (untagged_or_identity src) ~dst: (untagged_or_identity dst)
4743
+
4744
+ let static_cast ~dbg ~src ~dst exp =
4745
+ match src, dst with
4746
+ | Untagged src , Untagged dst -> Integer. static_cast ~dbg ~src ~dst exp
4747
+ | Tagged src , Tagged dst -> Tagged_integer. static_cast ~dbg ~src ~dst exp
4748
+ | Untagged src , Tagged dst ->
4749
+ tag_int
4750
+ (Integer. static_cast ~dbg ~src ~dst: (Tagged_integer. untagged dst) exp)
4751
+ dbg
4752
+ | Tagged src , Untagged dst ->
4753
+ Integer. static_cast ~dbg
4754
+ ~src: (Tagged_integer. untagged src)
4755
+ ~dst
4756
+ (Tagged_integer. untag ~dbg src exp)
4757
+
4758
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4759
+ x
4760
+ |> static_cast ~src: outer ~dst: inner ~dbg
4761
+ |> f
4762
+ |> static_cast ~src: inner ~dst: outer ~dbg
4763
+ end
4764
+
4765
+ type t =
4766
+ | Integral of Integral .t
4767
+ | Float of Float_width .t
4768
+
4769
+ let static_cast ~dbg ~src ~dst exp =
4770
+ match src, dst with
4771
+ | Integral src , Integral dst -> Integral. static_cast ~dbg ~src ~dst exp
4772
+ | Float src , Float dst -> Float_width. static_cast ~dbg ~src ~dst exp
4773
+ | Integral src , Float dst ->
4774
+ let float_of_int_arg = Integral. nativeint in
4775
+ if not
4776
+ (Integral. can_cast_without_losing_information ~src
4777
+ ~dst: float_of_int_arg)
4778
+ then
4779
+ Misc. fatal_errorf " static_cast: casting %a to float is not implemented"
4780
+ Integral. print src
4781
+ else
4782
+ unary (Cstatic_cast (Float_of_int dst)) ~dbg
4783
+ (Integral. static_cast exp ~dbg ~src ~dst: float_of_int_arg)
4784
+ | Float src , Integral dst -> (
4785
+ match Integral. signedness dst with
4786
+ | Unsigned ->
4787
+ Misc. fatal_errorf
4788
+ " static_cast: casting floats to unsigned values is not implemented"
4789
+ | Signed ->
4790
+ (* we can truncate because casting from float -> int is unspecified when
4791
+ the rounded value doesn't fit in the integral type. We can't promote
4792
+ since nativeint is already the largest integral type supported
4793
+ here. *)
4794
+ let exp = unary (Cstatic_cast (Int_of_float src)) exp ~dbg in
4795
+ let src = Integral. nativeint in
4796
+ (* assert that nativeint is indeed the largest integer width *)
4797
+ assert (Integral. can_cast_without_losing_information ~src: dst ~dst: src);
4798
+ Integral. static_cast exp ~dbg ~src ~dst )
4799
+
4800
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4801
+ x
4802
+ |> static_cast ~src: outer ~dst: inner ~dbg
4803
+ |> f
4804
+ |> static_cast ~src: inner ~dst: outer ~dbg
4805
+
4806
+ module Untagged = struct
4807
+ type numeric = t
4808
+
4809
+ type t =
4810
+ | Untagged of Integer .t
4811
+ | Float of float_width
4812
+
4813
+ let to_numeric : t -> numeric = function
4814
+ | Untagged width -> Integral (Untagged width)
4815
+ | Float float -> Float float
4816
+
4817
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4818
+ static_cast ~dbg ~src: (to_numeric src) ~dst: (to_numeric dst) exp
4819
+ end
4820
+ end
0 commit comments