Skip to content

Commit aa4594b

Browse files
committed
Compiler: simplify branch
1 parent 2cc664d commit aa4594b

File tree

4 files changed

+481
-600
lines changed

4 files changed

+481
-600
lines changed

CHANGES.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Compiler: support for OCaml 4.14.3+trunk (#1844)
88
* Compiler: add the `--empty-sourcemap` flag
99
* Compiler: improve debug/sourcemap location of closures (#1947)
10-
* Compiler: optimize compilation of switches
10+
* Compiler: optimize compilation of switches (#1921, #2057)
1111
* Compiler: evaluate statically more primitives (#1912, #1915, #1965, #1969)
1212
* Compiler: rewrote inlining pass (#1935, #2018, #2027)
1313
* Compiler: improve tailcall optimization (#1943)

compiler/lib/eval.ml

Lines changed: 111 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

732838
exception 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

compiler/tests-compiler/cond.ml

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,15 +100,64 @@ let rip_relative_kind_beq x y =
100100
|}
101101
in
102102
print_fun_decl program (Some "rip_relative_kind_beq");
103-
[%expect {|
103+
[%expect
104+
{|
105+
function rip_relative_kind_beq(x, y){
106+
switch(x){
107+
case 0:
108+
return 0 === y ? 1 : 0;
109+
case 1:
110+
return 1 === y ? 1 : 0;
111+
default: return 2 === y ? 1 : 0;
112+
}
113+
}
114+
//end
115+
|}]
116+
117+
let%expect_test "conditional" =
118+
let program =
119+
compile_and_parse
120+
{|
121+
type rip_relative_kind =
122+
| Explicitly_rip_relative
123+
| Implicitly_rip_relative
124+
| Not_rip_relative
125+
126+
(** val rip_relative_kind_beq :
127+
rip_relative_kind -> rip_relative_kind -> bool **)
128+
129+
let rip_relative_kind_beq x y =
130+
let i = match x with
131+
| Explicitly_rip_relative ->
132+
(match y with
133+
| Explicitly_rip_relative -> 1
134+
| Implicitly_rip_relative -> 2
135+
| Not_rip_relative -> 2)
136+
| Implicitly_rip_relative ->
137+
(match y with
138+
| Explicitly_rip_relative -> 2
139+
| Implicitly_rip_relative -> 1
140+
| Not_rip_relative -> 2)
141+
| Not_rip_relative ->
142+
(match y with
143+
| Explicitly_rip_relative -> 2
144+
| Implicitly_rip_relative -> 2
145+
| Not_rip_relative -> 1)
146+
in print_int i
147+
|}
148+
in
149+
print_fun_decl program (Some "rip_relative_kind_beq");
150+
[%expect
151+
{|
104152
function rip_relative_kind_beq(x, y){
105153
switch(x){
106154
case 0:
107-
switch(y){case 0: return 1;case 1: return 0;default: return 0;}
155+
var i = 0 === y ? 1 : 2; break;
108156
case 1:
109-
switch(y){case 0: return 0;case 1: return 1;default: return 0;}
110-
default: switch(y){case 0: return 0;case 1: return 0;default: return 1;}
157+
var i = 1 === y ? 1 : 2; break;
158+
default: var i = 2 === y ? 1 : 2;
111159
}
160+
return caml_call1(Stdlib[44], i);
112161
}
113162
//end
114163
|}]

0 commit comments

Comments
 (0)