Skip to content

Commit a1885af

Browse files
committed
Improved compilation of switches
1 parent dcf9970 commit a1885af

File tree

4 files changed

+62
-2
lines changed

4 files changed

+62
-2
lines changed

compiler/lib/driver.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,8 @@ let optimize ~profile p =
693693
Code.Var.fresh_n "dummy"
694694
in
695695
let opt =
696-
specialize_js_once
696+
Specialize.switches
697+
+> specialize_js_once
697698
+> (match profile with
698699
| O1 -> o1
699700
| O2 -> o2

compiler/lib/generate.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ let _ =
11201120
register_un_prim_ctx "%caml_format_int_special" `Pure (fun ctx cx loc ->
11211121
let s = J.EBin (J.Plus, str_js_utf8 "", cx) in
11221122
ocaml_string ~ctx ~loc s);
1123-
register_un_prim "%direct_obj_tag" `Mutator (fun cx _loc -> Mlvalue.Block.tag cx);
1123+
register_un_prim "%direct_obj_tag" `Pure (fun cx _loc -> Mlvalue.Block.tag cx);
11241124
register_bin_prim "caml_array_unsafe_get" `Mutable (fun cx cy _ ->
11251125
Mlvalue.Array.field cx cy);
11261126
register_bin_prim "%int_add" `Pure (fun cx cy _ ->

compiler/lib/specialize.ml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,60 @@ let specialize_instrs ~function_arity p =
117117
{ p with blocks; free_pc }
118118

119119
let f = specialize_instrs
120+
121+
(***)
122+
123+
(* For switches, at this point, we know that this it is sufficient to
124+
check the [pc]. *)
125+
let equal (pc, _) (pc', _) = pc = pc'
126+
127+
let find_outlier_index arr =
128+
let len = Array.length arr in
129+
if len < 3
130+
then if len = 1 || equal arr.(0) arr.(1) then `All_equals else `Distinguished 0
131+
else
132+
let majority =
133+
if equal arr.(0) arr.(1) || equal arr.(0) arr.(2) then arr.(0) else arr.(1)
134+
in
135+
let rec find i =
136+
if i >= len
137+
then `All_equals
138+
else if equal arr.(i) majority
139+
then find (i + 1)
140+
else `Distinguished i
141+
in
142+
match find 0 with
143+
| `All_equals as res -> res
144+
| `Distinguished i as res -> (
145+
match find (i + 1) with
146+
| `All_equals -> res
147+
| `Distinguished _ -> `Many_cases)
148+
149+
let switches p =
150+
{ p with
151+
blocks =
152+
Addr.Map.fold
153+
(fun pc block blocks ->
154+
match block.branch with
155+
| Switch (x, l) -> (
156+
match find_outlier_index l with
157+
| `All_equals -> Addr.Map.add pc { block with branch = Branch l.(0) } blocks
158+
| `Distinguished i ->
159+
let block =
160+
let v = Var.fresh () in
161+
let c = Var.fresh () in
162+
{ block with
163+
body =
164+
block.body
165+
@ [ Let (v, Constant (Int (Targetint.of_int_exn i)))
166+
; Let (c, Prim (Eq, [ Pv x; Pv v ]))
167+
]
168+
; branch = Cond (c, l.(i), l.((i + 1) mod Array.length l))
169+
}
170+
in
171+
Addr.Map.add pc block blocks
172+
| `Many_cases -> blocks)
173+
| _ -> blocks)
174+
p.blocks
175+
p.blocks
176+
}

compiler/lib/specialize.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@
2121
val function_arity : Flow.Info.t -> Code.Var.t -> int option
2222

2323
val f : function_arity:(Code.Var.t -> int option) -> Code.program -> Code.program
24+
25+
val switches : Code.program -> Code.program

0 commit comments

Comments
 (0)