@@ -4476,3 +4476,270 @@ let reperform ~dbg ~eff ~cont ~last_fiber =
4476
4476
dbg )
4477
4477
4478
4478
let poll ~dbg = return_unit dbg (Cop (Cpoll , [] , dbg))
4479
+
4480
+ module Scalar_type = struct
4481
+ module Float_width = struct
4482
+ type t = Cmm .float_width =
4483
+ | Float64
4484
+ | Float32
4485
+
4486
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4487
+ match src, dst with
4488
+ | Float64 , Float64 -> exp
4489
+ | Float32 , Float32 -> exp
4490
+ | Float32 , Float64 -> float_of_float32 ~dbg exp
4491
+ | Float64 , Float32 -> float32_of_float ~dbg exp
4492
+ end
4493
+
4494
+ module Signedness = struct
4495
+ type t =
4496
+ | Signed
4497
+ | Unsigned
4498
+
4499
+ let equal (x : t ) (y : t ) = x = y
4500
+
4501
+ let print ppf t =
4502
+ match t with
4503
+ | Signed -> Format. pp_print_string ppf " signed"
4504
+ | Unsigned -> Format. pp_print_string ppf " unsigned"
4505
+ end
4506
+
4507
+ module Bit_width_and_signedness : sig
4508
+ (* * An integer with signedness [signedness t] that fits into a general-purpose
4509
+ register. It is canonically stored in twos-complement representation, in the lower
4510
+ [bits] bits of its container (whether that be memory or a register), and is sign-
4511
+ or zero-extended to fill the entire container. *)
4512
+ type t [@@immediate]
4513
+
4514
+ val create_exn : bit_width :int -> signedness :Signedness .t -> t
4515
+
4516
+ val bit_width : t -> int
4517
+
4518
+ val signedness : t -> Signedness .t
4519
+
4520
+ val equal : t -> t -> bool
4521
+ end = struct
4522
+ (* [signedness t] is stored in the low bit of [t], and [bit_width t] is
4523
+ stored in the remaining high bits of [t]. We use this encoding to fit [t]
4524
+ into an immediate value. This is worth trying since we expect to create
4525
+ one of these for ~every integer operation, so it should cut down on
4526
+ garbage *)
4527
+ type t = { bit_width_and_signedness : int } [@@ unboxed]
4528
+
4529
+ let [@ inline] equal { bit_width_and_signedness = x }
4530
+ { bit_width_and_signedness = y } =
4531
+ Int. equal x y
4532
+
4533
+ let [@ inline] bit_width { bit_width_and_signedness } =
4534
+ bit_width_and_signedness lsr 1
4535
+
4536
+ let [@ inline] signedness { bit_width_and_signedness } =
4537
+ match bit_width_and_signedness land 1 with
4538
+ | 0 -> Signedness. Signed
4539
+ | 1 -> Signedness. Unsigned
4540
+ | _ -> assert false
4541
+
4542
+ let [@ inline] int_of_signedness : Signedness. t -> int = function
4543
+ | Signed -> 0
4544
+ | Unsigned -> 1
4545
+
4546
+ let [@ inline] create_exn ~bit_width ~signedness =
4547
+ assert (0 < bit_width && bit_width < = arch_bits);
4548
+ { bit_width_and_signedness =
4549
+ (bit_width lsl 1 ) + int_of_signedness signedness
4550
+ }
4551
+ end
4552
+
4553
+ module Integral_type = struct
4554
+ include Bit_width_and_signedness
4555
+
4556
+ let [@ inline] with_signedness t ~signedness =
4557
+ create_exn ~bit_width: (bit_width t) ~signedness
4558
+
4559
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4560
+
4561
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4562
+
4563
+ (* * Determines whether [dst] can represent every value of [src], preserving sign *)
4564
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4565
+ match signedness src, signedness dst with
4566
+ | Signed , Signed | Unsigned , Unsigned -> bit_width src < = bit_width dst
4567
+ | Unsigned , Signed -> bit_width src < bit_width dst
4568
+ | Signed , Unsigned -> false
4569
+
4570
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4571
+ if can_cast_without_losing_information ~src ~dst
4572
+ then
4573
+ (* Since [Bit_width_and_signedness] represents sign- or zero-extended
4574
+ expressions, this is a no-op *)
4575
+ exp
4576
+ else
4577
+ match signedness dst with
4578
+ | Signed -> sign_extend ~bits: (bit_width dst) exp ~dbg
4579
+ | Unsigned -> zero_extend ~bits: (bit_width dst) exp ~dbg
4580
+
4581
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4582
+ x
4583
+ |> static_cast ~src: outer ~dst: inner ~dbg
4584
+ |> f
4585
+ |> static_cast ~src: inner ~dst: outer ~dbg
4586
+ end
4587
+
4588
+ module Integer = struct
4589
+ include Integral_type
4590
+
4591
+ let print ppf t =
4592
+ Format. fprintf ppf " %a int%d" Signedness. print (signedness t)
4593
+ (bit_width t)
4594
+
4595
+ let nativeint = create_exn ~bit_width: arch_bits ~signedness: Signed
4596
+ end
4597
+
4598
+ (* * An {!Integer.t} but with the additional stipulation that its container must
4599
+ reserve its lowest bit to be 1. The [bit_width] field includes this bit. *)
4600
+ module Tagged_integer = struct
4601
+ include Integral_type
4602
+
4603
+ let [@ inline] create_exn ~bit_width_including_tag_bit: bit_width ~signedness =
4604
+ assert (bit_width > 1 );
4605
+ create_exn ~bit_width ~signedness
4606
+
4607
+ let immediate =
4608
+ create_exn ~bit_width_including_tag_bit: arch_bits ~signedness: Signed
4609
+
4610
+ let [@ inline] bit_width_including_tag_bit t = bit_width t
4611
+
4612
+ let [@ inline] bit_width_excluding_tag_bit t = bit_width t - 1
4613
+
4614
+ let [@ inline] untagged t =
4615
+ Integer. create_exn
4616
+ ~bit_width: (bit_width_excluding_tag_bit t)
4617
+ ~signedness: (signedness t)
4618
+
4619
+ let [@ inline] untag ~dbg t exp =
4620
+ match signedness t with
4621
+ | Signed -> asr_const exp 1 dbg
4622
+ | Unsigned -> lsr_const exp 1 dbg
4623
+
4624
+ let print ppf t =
4625
+ Format. fprintf ppf " tagged %a int%d" Signedness. print (signedness t)
4626
+ (bit_width_excluding_tag_bit t)
4627
+ end
4628
+
4629
+ module Integral = struct
4630
+ type t =
4631
+ | Untagged of Integer .t
4632
+ | Tagged of Tagged_integer .t
4633
+
4634
+ let nativeint = Untagged Integer. nativeint
4635
+
4636
+ let [@ inline] untagged_or_identity = function
4637
+ | Untagged t -> t
4638
+ | Tagged t -> Tagged_integer. untagged t
4639
+
4640
+ let signedness = function
4641
+ | Untagged t -> Integer. signedness t
4642
+ | Tagged t -> Tagged_integer. signedness t
4643
+
4644
+ let with_signedness t ~signedness =
4645
+ match t with
4646
+ | Untagged t -> Untagged (Integer. with_signedness t ~signedness )
4647
+ | Tagged t -> Tagged (Tagged_integer. with_signedness t ~signedness )
4648
+
4649
+ let [@ inline] signed t = with_signedness t ~signedness: Signed
4650
+
4651
+ let [@ inline] unsigned t = with_signedness t ~signedness: Unsigned
4652
+
4653
+ let [@ inline] equal x y =
4654
+ match x, y with
4655
+ | Untagged x , Untagged y -> Integer. equal x y
4656
+ | Untagged _ , _ -> false
4657
+ | Tagged x , Tagged y -> Tagged_integer. equal x y
4658
+ | Tagged _ , _ -> false
4659
+
4660
+ let print ppf t =
4661
+ match t with
4662
+ | Untagged untagged -> Integer. print ppf untagged
4663
+ | Tagged tagged -> Tagged_integer. print ppf tagged
4664
+
4665
+ let [@ inline] can_cast_without_losing_information ~src ~dst =
4666
+ Integer. can_cast_without_losing_information
4667
+ ~src: (untagged_or_identity src) ~dst: (untagged_or_identity dst)
4668
+
4669
+ let static_cast ~dbg ~src ~dst exp =
4670
+ match src, dst with
4671
+ | Untagged src , Untagged dst -> Integer. static_cast ~dbg ~src ~dst exp
4672
+ | Tagged src , Tagged dst -> Tagged_integer. static_cast ~dbg ~src ~dst exp
4673
+ | Untagged src , Tagged dst ->
4674
+ tag_int
4675
+ (Integer. static_cast ~dbg ~src ~dst: (Tagged_integer. untagged dst) exp)
4676
+ dbg
4677
+ | Tagged src , Untagged dst ->
4678
+ Integer. static_cast ~dbg
4679
+ ~src: (Tagged_integer. untagged src)
4680
+ ~dst
4681
+ (Tagged_integer. untag ~dbg src exp)
4682
+
4683
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4684
+ x
4685
+ |> static_cast ~src: outer ~dst: inner ~dbg
4686
+ |> f
4687
+ |> static_cast ~src: inner ~dst: outer ~dbg
4688
+ end
4689
+
4690
+ type t =
4691
+ | Integral of Integral .t
4692
+ | Float of Float_width .t
4693
+
4694
+ let static_cast ~dbg ~src ~dst exp =
4695
+ match src, dst with
4696
+ | Integral src , Integral dst -> Integral. static_cast ~dbg ~src ~dst exp
4697
+ | Float src , Float dst -> Float_width. static_cast ~dbg ~src ~dst exp
4698
+ | Integral src , Float dst ->
4699
+ let float_of_int_arg = Integral. nativeint in
4700
+ if not
4701
+ (Integral. can_cast_without_losing_information ~src
4702
+ ~dst: float_of_int_arg)
4703
+ then
4704
+ Misc. fatal_errorf " static_cast: casting %a to float is not implemented"
4705
+ Integral. print src
4706
+ else
4707
+ unary (Cstatic_cast (Float_of_int dst)) ~dbg
4708
+ (Integral. static_cast exp ~dbg ~src ~dst: float_of_int_arg)
4709
+ | Float src , Integral dst -> (
4710
+ match Integral. signedness dst with
4711
+ | Unsigned ->
4712
+ Misc. fatal_errorf
4713
+ " static_cast: casting floats to unsigned values is not implemented"
4714
+ | Signed ->
4715
+ (* we can truncate because casting from float -> int is unspecified when
4716
+ the rounded value doesn't fit in the integral type. We can't promote
4717
+ since nativeint is already the largest integral type supported
4718
+ here. *)
4719
+ let exp = unary (Cstatic_cast (Int_of_float src)) exp ~dbg in
4720
+ let src = Integral. nativeint in
4721
+ (* assert that nativeint is indeed the largest integer width *)
4722
+ assert (Integral. can_cast_without_losing_information ~src: dst ~dst: src);
4723
+ Integral. static_cast exp ~dbg ~src ~dst )
4724
+
4725
+ let [@ inline] conjugate ~outer ~inner ~dbg ~f x =
4726
+ x
4727
+ |> static_cast ~src: outer ~dst: inner ~dbg
4728
+ |> f
4729
+ |> static_cast ~src: inner ~dst: outer ~dbg
4730
+
4731
+ module Untagged = struct
4732
+ type numeric = t
4733
+
4734
+ type t =
4735
+ | Untagged of Integer .t
4736
+ | Float of float_width
4737
+
4738
+ let to_numeric : t -> numeric = function
4739
+ | Untagged width -> Integral (Untagged width)
4740
+ | Float float -> Float float
4741
+
4742
+ let [@ inline] static_cast ~dbg ~src ~dst exp =
4743
+ static_cast ~dbg ~src: (to_numeric src) ~dst: (to_numeric dst) exp
4744
+ end
4745
+ end
0 commit comments