@@ -710,7 +710,96 @@ let the_cond_of info x =
710710 | _ -> Unknown )
711711 x
712712
713- let eval_branch update_branch info l =
713+ module Simple_block : sig
714+ type t
715+
716+ val hash : t -> int
717+
718+ val equal : t -> t -> bool
719+
720+ val make : block -> t
721+ end = struct
722+ type t = block
723+
724+ let subst_cont s (pc , arg ) = pc, List. map arg ~f: s
725+
726+ let expr s e =
727+ match e with
728+ | Constant _ -> e
729+ | Apply { f; args; exact } -> Apply { f = s f; args = List. map args ~f: s; exact }
730+ | Block (n , a , k , mut ) -> Block (n, Array. map a ~f: s, k, mut)
731+ | Field (x , n , typ ) -> Field (s x, n, typ)
732+ | Closure (l , pc , loc ) -> Closure (l, subst_cont s pc, loc)
733+ | Special _ -> e
734+ | Prim (p , l ) ->
735+ Prim
736+ ( p
737+ , List. map l ~f: (fun x ->
738+ match x with
739+ | Pv x -> Pv (s x)
740+ | Pc _ -> x) )
741+
742+ let instr s d i =
743+ match i with
744+ | Let (x , e ) ->
745+ let x = d x in
746+ Let (x, expr s e)
747+ | Assign (x , y ) -> Assign (s x, s y)
748+ | Set_field (x , n , typ , y ) -> Set_field (s x, n, typ, s y)
749+ | Offset_ref (x , n ) -> Offset_ref (s x, n)
750+ | Array_set (x , y , z ) -> Array_set (s x, s y, s z)
751+ | Event _ -> Event Parse_info. zero
752+
753+ let instrs s d l = List. map l ~f: (fun i -> instr s d i)
754+
755+ let last s l =
756+ match l with
757+ | Stop -> l
758+ | Branch cont -> Branch (subst_cont s cont)
759+ | Pushtrap (cont1 , x , cont2 ) -> Pushtrap (subst_cont s cont1, s x, subst_cont s cont2)
760+ | Return x -> Return (s x)
761+ | Raise (x , k ) -> Raise (s x, k)
762+ | Cond (x , cont1 , cont2 ) -> Cond (s x, subst_cont s cont1, subst_cont s cont2)
763+ | Switch (x , conts ) -> Switch (s x, Array. map conts ~f: (fun cont -> subst_cont s cont))
764+ | Poptrap cont -> Poptrap (subst_cont s cont)
765+
766+ let block s d block =
767+ let params = List. map block.params ~f: s in
768+ let body = instrs s d block.body in
769+ let branch = last s block.branch in
770+ { params; body; branch }
771+
772+ let make blk =
773+ let t = Var.Hashtbl. create 17 in
774+ let s x =
775+ match Var.Hashtbl. find_opt t x with
776+ | None -> x
777+ | Some x -> x
778+ in
779+ let d x =
780+ let v = Var. of_idx (- Var.Hashtbl. length t) in
781+ Var.Hashtbl. add t x v;
782+ v
783+ in
784+ block s d blk
785+
786+ let instr_equal a b =
787+ match a, b with
788+ | Event _ , Event _ -> true
789+ | Event _ , _ | _ , Event _ -> false
790+ | a , b -> Poly. equal a b
791+
792+ let equal a b =
793+ List. equal ~eq: Var. equal a.params b.params
794+ && List. equal ~eq: instr_equal a.body b.body
795+ && Poly. equal a.branch b.branch
796+
797+ let hash (x : block ) = Hashtbl. hash x
798+ end
799+
800+ module SBT = Hashtbl. Make (Simple_block )
801+
802+ let eval_branch blocks update_branch info l =
714803 match l with
715804 | Cond (x , ftrue , ffalse ) as b -> (
716805 match the_cond_of info x with
@@ -721,13 +810,30 @@ let eval_branch update_branch info l =
721810 incr update_branch;
722811 Branch ftrue
723812 | Unknown -> b)
724- | Switch (x , a ) as b -> (
813+ | Switch (x , a ) -> (
725814 match the_cont_of info x a with
726815 | Some cont ->
727816 incr update_branch;
728817 Branch cont
729- | None -> b)
730- | _ as b -> b
818+ | None ->
819+ let t = SBT. create 0 in
820+ let seen_pc = Addr.Hashtbl. create 0 in
821+ Switch
822+ ( x
823+ , Array. map a ~f: (function
824+ | pc , [] when not (Addr.Hashtbl. mem seen_pc pc) -> (
825+ let block = Code.Addr.Map. find pc blocks in
826+ let sb = Simple_block. make block in
827+ match SBT. find_opt t sb with
828+ | Some pc' when pc' <> pc ->
829+ incr update_branch;
830+ pc', []
831+ | Some _ | None ->
832+ SBT. add t sb pc;
833+ Addr.Hashtbl. add seen_pc pc () ;
834+ pc, [] )
835+ | cont -> cont) ))
836+ | cont -> cont
731837
732838exception May_raise
733839
@@ -808,7 +914,7 @@ let eval update_count update_branch inline_constant ~target info blocks =
808914 block.body
809915 ~f: (eval_instr update_count inline_constant ~target info)
810916 in
811- let branch = eval_branch update_branch info block.branch in
917+ let branch = eval_branch blocks update_branch info block.branch in
812918 { block with Code. body; Code. branch })
813919 blocks
814920
0 commit comments