Skip to content

Commit 705e7d0

Browse files
committed
Compiler: lower level switch
1 parent 0df7260 commit 705e7d0

File tree

15 files changed

+236
-261
lines changed

15 files changed

+236
-261
lines changed

compiler/lib/code.ml

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ type last =
354354
| Stop
355355
| Branch of cont
356356
| Cond of Var.t * cont * cont
357-
| Switch of Var.t * cont array * cont array
357+
| Switch of Var.t * cont array
358358
| Pushtrap of cont * Var.t * cont * Addr.Set.t
359359
| Poptrap of cont
360360

@@ -499,10 +499,9 @@ module Print = struct
499499
| Branch c -> Format.fprintf f "branch %a" cont c
500500
| Cond (x, cont1, cont2) ->
501501
Format.fprintf f "if %a then %a else %a" Var.print x cont cont1 cont cont2
502-
| Switch (x, a1, a2) ->
502+
| Switch (x, a1) ->
503503
Format.fprintf f "switch %a {" Var.print x;
504504
Array.iteri a1 ~f:(fun i c -> Format.fprintf f "int %d -> %a; " i cont c);
505-
Array.iteri a2 ~f:(fun i c -> Format.fprintf f "tag %d -> %a; " i cont c);
506505
Format.fprintf f "}"
507506
| Pushtrap (cont1, x, cont2, pcs) ->
508507
Format.fprintf
@@ -598,9 +597,8 @@ let fold_children blocks pc f accu =
598597
let accu = f pc1 accu in
599598
let accu = f pc2 accu in
600599
accu
601-
| Switch (_, a1, a2) ->
600+
| Switch (_, a1) ->
602601
let accu = Array.fold_right ~init:accu ~f:(fun (pc, _) accu -> f pc accu) a1 in
603-
let accu = Array.fold_right ~init:accu ~f:(fun (pc, _) accu -> f pc accu) a2 in
604602
accu
605603

606604
type 'c fold_blocs = block Addr.Map.t -> Addr.t -> (Addr.t -> 'c -> 'c) -> 'c -> 'c
@@ -726,9 +724,7 @@ let invariant { blocks; start; _ } =
726724
| Cond (_x, cont1, cont2) ->
727725
check_cont cont1;
728726
check_cont cont2
729-
| Switch (_x, a1, a2) ->
730-
Array.iteri a1 ~f:(fun _ cont -> check_cont cont);
731-
Array.iteri a2 ~f:(fun _ cont -> check_cont cont)
727+
| Switch (_x, a1) -> Array.iteri a1 ~f:(fun _ cont -> check_cont cont)
732728
| Pushtrap (cont1, _x, cont2, _pcs) ->
733729
check_cont cont1;
734730
check_cont cont2

compiler/lib/code.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ type last =
201201
| Stop
202202
| Branch of cont
203203
| Cond of Var.t * cont * cont
204-
| Switch of Var.t * cont array * cont array
204+
| Switch of Var.t * cont array
205205
| Pushtrap of cont * Var.t * cont * Addr.Set.t
206206
| Poptrap of cont
207207

compiler/lib/deadcode.ml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,9 @@ and mark_reachable st pc =
9797
mark_var st x;
9898
mark_cont_reachable st cont1;
9999
mark_cont_reachable st cont2
100-
| Switch (x, a1, a2) ->
100+
| Switch (x, a1) ->
101101
mark_var st x;
102-
Array.iter a1 ~f:(fun cont -> mark_cont_reachable st cont);
103-
Array.iter a2 ~f:(fun cont -> mark_cont_reachable st cont)
102+
Array.iter a1 ~f:(fun cont -> mark_cont_reachable st cont)
104103
| Pushtrap (cont1, _, cont2, _) ->
105104
mark_cont_reachable st cont1;
106105
mark_cont_reachable st cont2)
@@ -136,11 +135,8 @@ let filter_live_last blocks st (l, loc) =
136135
| Branch cont -> Branch (filter_cont blocks st cont)
137136
| Cond (x, cont1, cont2) ->
138137
Cond (x, filter_cont blocks st cont1, filter_cont blocks st cont2)
139-
| Switch (x, a1, a2) ->
140-
Switch
141-
( x
142-
, Array.map a1 ~f:(fun cont -> filter_cont blocks st cont)
143-
, Array.map a2 ~f:(fun cont -> filter_cont blocks st cont) )
138+
| Switch (x, a1) ->
139+
Switch (x, Array.map a1 ~f:(fun cont -> filter_cont blocks st cont))
144140
| Pushtrap (cont1, x, cont2, pcs) ->
145141
Pushtrap
146142
( filter_cont blocks st cont1
@@ -204,9 +200,7 @@ let f ({ blocks; _ } as p : Code.program) =
204200
| Cond (_, cont1, cont2) ->
205201
add_cont_dep blocks defs cont1;
206202
add_cont_dep blocks defs cont2
207-
| Switch (_, a1, a2) ->
208-
Array.iter a1 ~f:(fun cont -> add_cont_dep blocks defs cont);
209-
Array.iter a2 ~f:(fun cont -> add_cont_dep blocks defs cont)
203+
| Switch (_, a1) -> Array.iter a1 ~f:(fun cont -> add_cont_dep blocks defs cont)
210204
| Pushtrap (cont, _, cont_h, _) ->
211205
add_cont_dep blocks defs cont_h;
212206
add_cont_dep blocks defs cont

compiler/lib/effects.ml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -418,13 +418,11 @@ let cps_last ~st ~alloc_jump_closures pc ((last, last_loc) : last * loc) ~k :
418418
, cps_jump_cont ~st ~src:pc cont1 last_loc
419419
, cps_jump_cont ~st ~src:pc cont2 last_loc )
420420
, last_loc ) )
421-
| Switch (x, c1, c2) ->
421+
| Switch (x, c1) ->
422422
(* To avoid code duplication during JavaScript generation, we need
423423
to create a single block per continuation *)
424424
let cps_jump_cont = Fun.memoize (fun x -> cps_jump_cont ~st ~src:pc x last_loc) in
425-
( alloc_jump_closures
426-
, ( Switch (x, Array.map c1 ~f:cps_jump_cont, Array.map c2 ~f:cps_jump_cont)
427-
, last_loc ) )
425+
alloc_jump_closures, (Switch (x, Array.map c1 ~f:cps_jump_cont), last_loc)
428426
| Pushtrap (body_cont, exn, ((handler_pc, _) as handler_cont), _) -> (
429427
assert (Hashtbl.mem st.is_continuation handler_pc);
430428
match Addr.Set.mem handler_pc st.blocks_to_transform with
@@ -911,8 +909,7 @@ let remove_empty_blocks ~live_vars (p : Code.program) : Code.program =
911909
match branch with
912910
| Branch cont -> Branch (resolve cont)
913911
| Cond (x, cont1, cont2) -> Cond (x, resolve cont1, resolve cont2)
914-
| Switch (x, a1, a2) ->
915-
Switch (x, Array.map ~f:resolve a1, Array.map ~f:resolve a2)
912+
| Switch (x, a1) -> Switch (x, Array.map ~f:resolve a1)
916913
| Pushtrap (cont1, x, cont2, s) ->
917914
Pushtrap (resolve cont1, x, resolve cont2, s)
918915
| Poptrap cont -> Poptrap (resolve cont)

compiler/lib/eval.ml

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -341,14 +341,13 @@ let eval_branch info (l, loc) =
341341
| Zero -> Branch ffalse
342342
| Non_zero -> Branch ftrue
343343
| Unknown -> b)
344-
| Switch (x, const, tags) as b -> (
344+
| Switch (x, const) as b -> (
345345
(* [the_case_of info (Pv x)] might be meaningless when we're inside a dead code.
346346
The proper fix would be to remove the deadcode entirely.
347347
Meanwhile, add guards to prevent Invalid_argument("index out of bounds")
348348
see https://github.com/ocsigen/js_of_ocaml/issues/485 *)
349349
match the_case_of info (Pv x) with
350350
| CConst j when j >= 0 && j < Array.length const -> Branch const.(j)
351-
| CTag j when j >= 0 && j < Array.length tags -> Branch tags.(j)
352351
| CConst _ | CTag _ | Unknown -> b)
353352
| _ as b -> b
354353
in
@@ -380,15 +379,11 @@ let rec do_not_raise pc visited blocks =
380379
let visited = do_not_raise pc1 visited blocks in
381380
let visited = do_not_raise pc2 visited blocks in
382381
visited
383-
| Switch (_, a1, a2) ->
382+
| Switch (_, a1) ->
384383
let visited =
385384
Array.fold_left a1 ~init:visited ~f:(fun visited (pc, _) ->
386385
do_not_raise pc visited blocks)
387386
in
388-
let visited =
389-
Array.fold_left a2 ~init:visited ~f:(fun visited (pc, _) ->
390-
do_not_raise pc visited blocks)
391-
in
392387
visited
393388
| Pushtrap _ -> raise May_raise
394389

compiler/lib/flow.ml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,8 @@ let program_deps { blocks; _ } =
119119
| Cond (_, cont1, cont2) ->
120120
cont_deps blocks vars deps defs cont1;
121121
cont_deps blocks vars deps defs cont2
122-
| Switch (_, a1, a2) ->
123-
Array.iter a1 ~f:(fun cont -> cont_deps blocks vars deps defs cont);
124-
Array.iter a2 ~f:(fun cont -> cont_deps blocks vars deps defs cont)
122+
| Switch (_, a1) ->
123+
Array.iter a1 ~f:(fun cont -> cont_deps blocks vars deps defs cont)
125124
| Pushtrap (cont, x, cont_h, _) ->
126125
add_param_def vars defs x;
127126
cont_deps blocks vars deps defs cont_h;

compiler/lib/freevars.ml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,9 @@ let iter_last_free_var f l =
6464
f x;
6565
iter_cont_free_vars f cont1;
6666
iter_cont_free_vars f cont2
67-
| Switch (x, a1, a2) ->
67+
| Switch (x, a1) ->
6868
f x;
69-
Array.iter a1 ~f:(fun c -> iter_cont_free_vars f c);
70-
Array.iter a2 ~f:(fun c -> iter_cont_free_vars f c)
69+
Array.iter a1 ~f:(fun c -> iter_cont_free_vars f c)
7170
| Pushtrap (cont1, _, cont2, _) ->
7271
iter_cont_free_vars f cont1;
7372
iter_cont_free_vars f cont2

compiler/lib/generate.ml

Lines changed: 6 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -760,10 +760,9 @@ let fold_children blocks pc f accu =
760760
let accu = f pc2 accu in
761761
accu
762762
| Cond (_, cont1, cont2) -> DTree.fold_cont f (DTree.build_if cont1 cont2) accu
763-
| Switch (_, a1, a2) ->
764-
let a1 = DTree.build_switch a1 and a2 = DTree.build_switch a2 in
763+
| Switch (_, a1) ->
764+
let a1 = DTree.build_switch a1 in
765765
let accu = DTree.fold_cont f a1 accu in
766-
let accu = DTree.fold_cont f a2 accu in
767766
accu
768767

769768
let build_graph ctx pc =
@@ -1099,6 +1098,7 @@ let _ =
10991098
register_un_prim_ctx "%caml_format_int_special" `Pure (fun ctx cx loc ->
11001099
let s = J.EBin (J.Plus, str_js_utf8 "", cx) in
11011100
ocaml_string ~ctx ~loc s);
1101+
register_un_prim "%direct_obj_tag" `Mutator (fun cx _loc -> Mlvalue.Block.tag cx);
11021102
register_bin_prim "caml_array_unsafe_get" `Mutable (fun cx cy _ ->
11031103
Mlvalue.Array.field cx cy);
11041104
register_bin_prim "%int_add" `Pure (fun cx cy _ -> to_int (plus_int cx cy));
@@ -1769,7 +1769,7 @@ and colapse_frontier name st (new_frontier' : Addr.Set.t) interm =
17691769
let branch =
17701770
let cases = Array.of_list (List.map a ~f:(fun pc -> pc, [])) in
17711771
if Array.length cases > 2
1772-
then Code.Switch (x, cases, [||]), Code.noloc
1772+
then Code.Switch (x, cases), Code.noloc
17731773
else Code.Cond (x, cases.(1), cases.(0)), Code.noloc
17741774
in
17751775
( [ J.variable_declaration [ J.V x, (int default, J.N) ], J.N ]
@@ -1850,7 +1850,7 @@ and compile_conditional st queue last loop_stack backs frontier interm =
18501850
| Raise _ -> Format.eprintf "raise;@;"
18511851
| Stop -> Format.eprintf "stop;@;"
18521852
| Cond (x, _, _) -> Format.eprintf "@[<hv 2>cond(%a){@;" Code.Var.print x
1853-
| Switch (x, _, _) -> Format.eprintf "@[<hv 2>switch(%a){@;" Code.Var.print x);
1853+
| Switch (x, _) -> Format.eprintf "@[<hv 2>switch(%a){@;" Code.Var.print x);
18541854
let loc = source_location st.ctx pc in
18551855
let res =
18561856
match last with
@@ -1912,21 +1912,7 @@ and compile_conditional st queue last loop_stack backs frontier interm =
19121912
(DTree.build_if c1 c2)
19131913
in
19141914
never, flush_all queue b
1915-
| Switch (x, [||], a2) ->
1916-
let (_px, cx), queue = access_queue queue x in
1917-
let never, code =
1918-
compile_decision_tree
1919-
st
1920-
loop_stack
1921-
backs
1922-
frontier
1923-
interm
1924-
loc
1925-
(Mlvalue.Block.tag cx)
1926-
(DTree.build_switch a2)
1927-
in
1928-
never, flush_all queue code
1929-
| Switch (x, a1, [||]) ->
1915+
| Switch (x, a1) ->
19301916
let (_px, cx), queue = access_queue queue x in
19311917
let never, code =
19321918
compile_decision_tree
@@ -1940,41 +1926,6 @@ and compile_conditional st queue last loop_stack backs frontier interm =
19401926
(DTree.build_switch a1)
19411927
in
19421928
never, flush_all queue code
1943-
| Switch (x, a1, a2) ->
1944-
(* The variable x is accessed several times, so we can directly
1945-
refer to it *)
1946-
let never1, b1 =
1947-
compile_decision_tree
1948-
st
1949-
loop_stack
1950-
backs
1951-
frontier
1952-
interm
1953-
loc
1954-
(var x)
1955-
(DTree.build_switch a1)
1956-
in
1957-
let never2, b2 =
1958-
compile_decision_tree
1959-
st
1960-
loop_stack
1961-
backs
1962-
frontier
1963-
interm
1964-
loc
1965-
(Mlvalue.Block.tag (var x))
1966-
(DTree.build_switch a2)
1967-
in
1968-
let code =
1969-
Js_simpl.if_statement
1970-
(Mlvalue.is_immediate (var x))
1971-
loc
1972-
(Js_simpl.block b1)
1973-
never1
1974-
(Js_simpl.block b2)
1975-
never2
1976-
in
1977-
never1 && never2, flush_all queue code
19781929
in
19791930
(if debug ()
19801931
then

compiler/lib/global_flow.ml

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -243,14 +243,9 @@ let program_deps st { blocks; _ } =
243243
| Cond (x, cont1, cont2) ->
244244
cont_deps blocks st cont1;
245245
cont_deps blocks st ~ignore:x cont2
246-
| Switch (x, a1, a2) ->
246+
| Switch (x, a1) ->
247247
Array.iter a1 ~f:(fun cont -> cont_deps blocks st cont);
248-
Array.iter a2 ~f:(fun cont -> cont_deps blocks st cont);
249248
let h = Hashtbl.create 16 in
250-
Array.iteri
251-
~f:(fun i (pc, _) ->
252-
Hashtbl.replace h pc (i :: (try Hashtbl.find h pc with Not_found -> [])))
253-
a2;
254249
if not st.fast
255250
then
256251
Hashtbl.iter

compiler/lib/inline.ml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ let optimizable blocks pc _ =
3838
+
3939
match fst branch with
4040
| Cond _ -> 2
41-
| Switch (_, a1, a2) -> Array.length a1 + Array.length a2
41+
| Switch (_, a1) -> Array.length a1
4242
| _ -> 0)
4343
in
4444
let optimizable =
@@ -112,9 +112,8 @@ let fold_children blocks pc f accu =
112112
let accu = f pc1 accu in
113113
let accu = f pc2 accu in
114114
accu
115-
| Switch (_, a1, a2) ->
115+
| Switch (_, a1) ->
116116
let accu = Array.fold_right a1 ~init:accu ~f:(fun (pc, _) accu -> f pc accu) in
117-
let accu = Array.fold_right a2 ~init:accu ~f:(fun (pc, _) accu -> f pc accu) in
118117
accu
119118

120119
let rewrite_closure blocks cont_pc clos_pc =

compiler/lib/parse_bytecode.ml

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -850,10 +850,9 @@ let rec compile_block blocks debug_data code pc state =
850850
| Cond (_, (pc1, _), (pc2, _)) ->
851851
compile_block blocks debug_data code pc1 state';
852852
compile_block blocks debug_data code pc2 state'
853-
| Switch (_, l1, l2) ->
854-
Array.iter l1 ~f:(fun (pc', _) -> compile_block blocks debug_data code pc' state');
855-
Array.iter l2 ~f:(fun (pc', _) -> compile_block blocks debug_data code pc' state')
856-
| Pushtrap _ | Raise _ | Return _ | Stop -> ())
853+
| Switch (_, _) -> ()
854+
| Pushtrap _ -> ()
855+
| Raise _ | Return _ | Stop -> ())
857856

858857
and compile infos pc state instrs =
859858
if debug_parser () then State.print state;
@@ -1630,20 +1629,67 @@ and compile infos pc state instrs =
16301629
let x, _ = State.accu state in
16311630
let args = State.stack_vars state in
16321631
instrs, (Cond (x, (pc + 2, args), (pc + offset + 1, args)), loc), state
1633-
| SWITCH ->
1632+
| SWITCH -> (
16341633
if debug_parser () then Format.printf "switch ...@.";
16351634

16361635
let sz = getu code (pc + 1) in
16371636
let x, _ = State.accu state in
16381637
let args = State.stack_vars state in
16391638
let l = sz land 0xFFFF in
1639+
let isize = sz land 0XFFFF in
1640+
let bsize = sz lsr 16 in
16401641
let it =
16411642
Array.init (sz land 0XFFFF) ~f:(fun i -> pc + 2 + gets code (pc + 2 + i), args)
16421643
in
16431644
let bt =
16441645
Array.init (sz lsr 16) ~f:(fun i -> pc + 2 + gets code (pc + 2 + l + i), args)
16451646
in
1646-
instrs, (Switch (x, it, bt), loc), state
1647+
Array.iter it ~f:(fun (pc', _) ->
1648+
compile_block infos.blocks infos.debug code pc' state);
1649+
Array.iter bt ~f:(fun (pc', _) ->
1650+
compile_block infos.blocks infos.debug code pc' state);
1651+
match isize, bsize with
1652+
| _, 0 -> instrs, (Switch (x, it), loc), state
1653+
| 0, _ ->
1654+
let x_tag = Var.fresh () in
1655+
let instrs =
1656+
(Let (x_tag, Prim (Extern "%direct_obj_tag", [ Pv x ])), loc) :: instrs
1657+
in
1658+
instrs, (Switch (x_tag, bt), loc), state
1659+
| _, _ ->
1660+
let isint_branch = pc + 1 in
1661+
let isblock_branch = pc + 2 in
1662+
let i_state = State.start_block isint_branch state in
1663+
let i_args = State.stack_vars i_state in
1664+
let b_state = State.start_block isblock_branch state in
1665+
let b_args = State.stack_vars b_state in
1666+
tagged_blocks := Addr.Set.add isint_branch !tagged_blocks;
1667+
tagged_blocks := Addr.Set.add isblock_branch !tagged_blocks;
1668+
let it = Array.map it ~f:(fun (x, _) -> x, i_args) in
1669+
let bt = Array.map bt ~f:(fun (x, _) -> x, b_args) in
1670+
let x_tag = Var.fresh () in
1671+
let () =
1672+
compiled_blocks :=
1673+
Addr.Map.add
1674+
isint_branch
1675+
(i_state, [], (Switch (x, it), loc))
1676+
!compiled_blocks
1677+
in
1678+
let () =
1679+
let instrs =
1680+
[ Let (x_tag, Prim (Extern "%direct_obj_tag", [ Pv x ])), loc ]
1681+
in
1682+
compiled_blocks :=
1683+
Addr.Map.add
1684+
isblock_branch
1685+
(b_state, instrs, (Switch (x_tag, bt), loc))
1686+
!compiled_blocks
1687+
in
1688+
let isint_var = Var.fresh () in
1689+
let instrs = (Let (isint_var, Prim (IsInt, [ Pv x ])), loc) :: instrs in
1690+
( instrs
1691+
, (Cond (isint_var, (isint_branch, args), (isblock_branch, args)), loc)
1692+
, state ))
16471693
| BOOLNOT ->
16481694
let y, _ = State.accu state in
16491695
let x, state = State.fresh_var state loc in

0 commit comments

Comments
 (0)