Skip to content

Commit ee229f5

Browse files
committed
Compiler: propagate arity across unit boundary (WIP)
1 parent 659945d commit ee229f5

24 files changed

+2228
-2826
lines changed

compiler/lib/code.ml

+14-4
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,7 @@ type expr =
339339
; args : Var.t list
340340
; exact : bool
341341
}
342-
| Block of int * Var.t array * array_or_not
342+
| Block of int * Var.t array * array_or_not * bool
343343
| Field of Var.t * int
344344
| Closure of Var.t list * cont
345345
| Constant of constant
@@ -479,8 +479,18 @@ module Print = struct
479479
if exact
480480
then Format.fprintf f "%a!(%a)" Var.print g var_list args
481481
else Format.fprintf f "%a(%a)" Var.print g var_list args
482-
| Block (t, a, _) ->
483-
Format.fprintf f "{tag=%d" t;
482+
| Block (t, a, k, imm) ->
483+
Format.fprintf
484+
f
485+
"{%s%s:tag=%d"
486+
(match imm with
487+
| true -> "Imm"
488+
| false -> "")
489+
(match k with
490+
| Array -> "A"
491+
| NotArray -> "NA"
492+
| Unknown -> "U")
493+
t;
484494
for i = 0 to Array.length a - 1 do
485495
Format.fprintf f "; %d = %a" i Var.print a.(i)
486496
done;
@@ -732,7 +742,7 @@ let invariant { blocks; start; _ } =
732742
in
733743
let check_expr = function
734744
| Apply _ -> ()
735-
| Block (_, _, _) -> ()
745+
| Block (_, _, _, _) -> ()
736746
| Field (_, _) -> ()
737747
| Closure (l, cont) ->
738748
List.iter l ~f:define;

compiler/lib/code.mli

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ type expr =
186186
; args : Var.t list
187187
; exact : bool (* if true, then # of arguments = # of parameters *)
188188
}
189-
| Block of int * Var.t array * array_or_not
189+
| Block of int * Var.t array * array_or_not * bool
190190
| Field of Var.t * int
191191
| Closure of Var.t list * cont
192192
| Constant of constant

compiler/lib/deadcode.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ and mark_expr st e =
7070
| Apply { f; args; _ } ->
7171
mark_var st f;
7272
List.iter args ~f:(fun x -> mark_var st x)
73-
| Block (_, a, _) -> Array.iter a ~f:(fun x -> mark_var st x)
73+
| Block (_, a, _, _) -> Array.iter a ~f:(fun x -> mark_var st x)
7474
| Field (x, _) -> mark_var st x
7575
| Closure (_, (pc, _)) -> mark_reachable st pc
7676
| Special _ -> ()

compiler/lib/driver.ml

+32-1
Original file line numberDiff line numberDiff line change
@@ -625,6 +625,29 @@ if (typeof module === 'object' && module.exports) {
625625
if times () then Format.eprintf " optimizing: %a@." Timer.print t;
626626
js
627627

628+
let collects_shapes p =
629+
let _, info = Flow.f p in
630+
let l = ref StringMap.empty in
631+
Code.Addr.Map.iter
632+
(fun _ block ->
633+
List.iter block.Code.body ~f:(fun (i, _) ->
634+
match i with
635+
| Code.Let
636+
( _
637+
, Prim
638+
( Extern "caml_register_global"
639+
, [ _code; Pv block; Pc (NativeString name) ] ) ) ->
640+
let shape = Flow.the_shape_of info block in
641+
let name =
642+
match name with
643+
| Byte s -> s
644+
| Utf (Utf8 s) -> s
645+
in
646+
l := StringMap.add name shape !l
647+
| _ -> ()))
648+
p.blocks;
649+
!l
650+
628651
let configure formatter =
629652
let pretty = Config.Flag.pretty () in
630653
Pretty_print.set_compact formatter (not pretty);
@@ -663,7 +686,15 @@ let full ~standalone ~wrap_with_fun ~profile ~linkall ~source_map formatter d p
663686
in
664687
if times () then Format.eprintf "Start Optimizing...@.";
665688
let t = Timer.make () in
666-
let r = opt p in
689+
let (((prog, _), _) as r) = opt p in
690+
let shapes = collects_shapes prog in
691+
StringMap.iter
692+
(fun name shape ->
693+
Shape.set_shape ~name shape;
694+
Pretty_print.string
695+
formatter
696+
(Printf.sprintf "//# shape: %s:%s\n" name (Shape.to_string shape)))
697+
shapes;
667698
let () = if times () then Format.eprintf " optimizations : %a@." Timer.print t in
668699
emit r
669700

compiler/lib/duplicate.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ let expr s e =
2626
| Constant _ -> e
2727
| Apply { f; args; exact } ->
2828
Apply { f = s f; args = List.map args ~f:(fun x -> s x); exact }
29-
| Block (n, a, k) -> Block (n, Array.map a ~f:(fun x -> s x), k)
29+
| Block (n, a, k, imm) -> Block (n, Array.map a ~f:(fun x -> s x), k, imm)
3030
| Field (x, n) -> Field (s x, n)
3131
| Closure _ -> failwith "Inlining/Duplicating closure is currenly not supported"
3232
| Special x -> Special x

compiler/lib/eval.ml

+5-5
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ let is_int info x =
177177
(fun x ->
178178
match Flow.Info.def info x with
179179
| Some (Constant (Int _)) -> Y
180-
| Some (Block (_, _, _) | Constant _) -> N
180+
| Some (Block (_, _, _, _) | Constant _) -> N
181181
| None | Some _ -> Unknown)
182182
Unknown
183183
(fun u v ->
@@ -196,7 +196,7 @@ let the_tag_of info x get =
196196
info
197197
(fun x ->
198198
match Flow.Info.def info x with
199-
| Some (Block (j, _, _)) ->
199+
| Some (Block (j, _, _, _)) ->
200200
if Flow.Info.possibly_mutable info x then None else get j
201201
| Some (Constant (Tuple (j, _, _))) -> get j
202202
| None | Some _ -> None)
@@ -278,7 +278,7 @@ let eval_instr info ((x, loc) as i) =
278278
| Let (x, Prim (Extern "caml_sys_const_backend_type", [ _ ])) ->
279279
let jsoo = Code.Var.fresh () in
280280
[ Let (jsoo, Constant (String "js_of_ocaml")), noloc
281-
; Let (x, Block (0, [| jsoo |], NotArray)), loc
281+
; Let (x, Block (0, [| jsoo |], NotArray, true)), loc
282282
]
283283
| Let (_, Prim (Extern ("%resume" | "%perform" | "%reperform"), _)) ->
284284
[ i ] (* We need that the arguments to this primitives remain variables *)
@@ -338,7 +338,7 @@ let the_cond_of info x =
338338
| NativeString _
339339
| Float_array _
340340
| Int64 _ )) -> Non_zero
341-
| Some (Block (_, _, _)) -> Non_zero
341+
| Some (Block (_, _, _, _)) -> Non_zero
342342
| Some (Field _ | Closure _ | Prim _ | Apply _ | Special _) -> Unknown
343343
| None -> Unknown)
344344
Unknown
@@ -381,7 +381,7 @@ let rec do_not_raise pc visited blocks =
381381
| Array_set (_, _, _) | Offset_ref (_, _) | Set_field (_, _, _) | Assign _ -> ()
382382
| Let (_, e) -> (
383383
match e with
384-
| Block (_, _, _) | Field (_, _) | Constant _ | Closure _ -> ()
384+
| Block (_, _, _, _) | Field (_, _) | Constant _ | Closure _ -> ()
385385
| Apply _ -> raise May_raise
386386
| Special _ -> ()
387387
| Prim (Extern name, _) when Primitive.is_pure name -> ()

compiler/lib/flow.ml

+38-10
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ let expr_deps blocks vars deps defs x e =
103103
| Closure (l, cont) ->
104104
List.iter l ~f:(fun x -> add_param_def vars defs x);
105105
cont_deps blocks vars deps defs cont
106-
| Block (_, a, _) -> Array.iter a ~f:(fun y -> add_dep deps x y)
106+
| Block (_, a, _, _) -> Array.iter a ~f:(fun y -> add_dep deps x y)
107107
| Field (y, _) -> add_dep deps x y
108108

109109
let program_deps { blocks; _ } =
@@ -152,7 +152,7 @@ let propagate1 deps defs st x =
152152
var_set_lift
153153
(fun z ->
154154
match defs.(Var.idx z) with
155-
| Expr (Block (_, a, _)) when n < Array.length a ->
155+
| Expr (Block (_, a, _, _)) when n < Array.length a ->
156156
let t = a.(n) in
157157
add_dep deps x t;
158158
Var.Tbl.get st t
@@ -186,15 +186,17 @@ type mutability_state =
186186
; possibly_mutable : Code.Var.ISet.t
187187
}
188188

189-
let rec block_escape st x =
189+
let rec block_escape st ?(immutable = false) x =
190190
Var.Set.iter
191191
(fun y ->
192192
if not (Code.Var.ISet.mem st.may_escape y)
193193
then (
194194
Code.Var.ISet.add st.may_escape y;
195-
Code.Var.ISet.add st.possibly_mutable y;
195+
if not immutable then Code.Var.ISet.add st.possibly_mutable y;
196+
196197
match st.defs.(Var.idx y) with
197-
| Expr (Block (_, l, _)) -> Array.iter l ~f:(fun z -> block_escape st z)
198+
| Expr (Block (_, l, _, immutable)) ->
199+
Array.iter l ~f:(fun z -> block_escape st ~immutable z)
198200
| _ -> ()))
199201
(Var.Tbl.get st.known_origins x)
200202

@@ -226,15 +228,18 @@ let expr_escape st _x e =
226228
| Pv v, `Shallow_const -> (
227229
match st.defs.(Var.idx v) with
228230
| Expr (Constant (Tuple _)) -> ()
229-
| Expr (Block (_, a, _)) -> Array.iter a ~f:(fun x -> block_escape st x)
231+
| Expr (Block (_, a, _, true)) ->
232+
Array.iter a ~f:(fun x -> block_escape st ~immutable:true x)
233+
| Expr (Block (_, a, _, false)) ->
234+
Array.iter a ~f:(fun x -> block_escape st x)
230235
| _ -> block_escape st v)
231236
| Pv v, `Object_literal -> (
232237
match st.defs.(Var.idx v) with
233238
| Expr (Constant (Tuple _)) -> ()
234-
| Expr (Block (_, a, _)) ->
239+
| Expr (Block (_, a, _, _)) ->
235240
Array.iter a ~f:(fun x ->
236241
match st.defs.(Var.idx x) with
237-
| Expr (Block (_, [| _k; v |], _)) -> block_escape st v
242+
| Expr (Block (_, [| _k; v |], _, _)) -> block_escape st v
238243
| Expr (Constant _) -> ()
239244
| _ -> block_escape st x)
240245
| _ -> block_escape st v)
@@ -282,7 +287,7 @@ let propagate2 ?(skip_param = false) defs known_origins possibly_mutable st x =
282287
|| Var.Set.exists
283288
(fun z ->
284289
match defs.(Var.idx z) with
285-
| Expr (Block (_, a, _)) ->
290+
| Expr (Block (_, a, _, _)) ->
286291
n >= Array.length a
287292
|| Var.ISet.mem possibly_mutable z
288293
|| Var.Tbl.get st a.(n)
@@ -382,7 +387,7 @@ let direct_approx (info : Info.t) x =
382387
then None
383388
else
384389
match info.info_defs.(Var.idx z) with
385-
| Expr (Block (_, a, _)) when n < Array.length a -> Some a.(n)
390+
| Expr (Block (_, a, _, _)) when n < Array.length a -> Some a.(n)
386391
| _ -> None)
387392
None
388393
(fun u v ->
@@ -392,6 +397,29 @@ let direct_approx (info : Info.t) x =
392397
y
393398
| _ -> None
394399

400+
let rec the_shape_of info x =
401+
get_approx
402+
info
403+
(fun x ->
404+
if Var.ISet.mem info.info_possibly_mutable x
405+
then Shape.Bot "possibly_mutable"
406+
else
407+
match info.info_defs.(Var.idx x) with
408+
| Expr (Block (_, a, _, true)) ->
409+
Shape.Block (List.map ~f:(the_shape_of info) (Array.to_list a))
410+
| Expr (Closure (l, _)) ->
411+
Shape.Function { arity = List.length l; pure = false; res = Bot "unk" }
412+
| Expr (Special (Alias_prim name)) -> (
413+
try
414+
let arity = Primitive.arity name in
415+
let pure = Primitive.is_pure name in
416+
Shape.Function { arity; pure; res = Bot "unk" }
417+
with _ -> Bot "other")
418+
| _ -> Shape.Bot "other")
419+
(Bot "init")
420+
(fun _u _v -> Shape.Bot "merge")
421+
x
422+
395423
let build_subst (info : Info.t) vars =
396424
let nv = Var.count () in
397425
let subst = Array.init nv ~f:(fun i -> Var.of_idx i) in

compiler/lib/flow.mli

+2
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,6 @@ val the_native_string_of : Info.t -> Code.prim_arg -> Code.Native_string.t optio
6060

6161
val the_int : Info.t -> Code.prim_arg -> int32 option
6262

63+
val the_shape_of : Info.t -> Code.Var.t -> Shape.t
64+
6365
val f : ?skip_param:bool -> Code.program -> Code.program * Info.t

compiler/lib/freevars.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ let iter_expr_free_vars f e =
3333
| Apply { f = x; args; _ } ->
3434
f x;
3535
List.iter ~f args
36-
| Block (_, a, _) -> Array.iter ~f a
36+
| Block (_, a, _, _) -> Array.iter ~f a
3737
| Field (x, _) -> f x
3838
| Closure _ -> ()
3939
| Special _ -> ()

compiler/lib/generate.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1042,7 +1042,7 @@ let rec translate_expr ctx queue loc x e level : _ * J.statement_list =
10421042
let prop = or_p prop prop' in
10431043
let e = apply_fun ctx f args exact cps loc in
10441044
(e, prop, queue), []
1045-
| Block (tag, a, array_or_not) ->
1045+
| Block (tag, a, array_or_not, _imm) ->
10461046
let contents, prop, queue =
10471047
List.fold_right
10481048
~f:(fun x (args, prop, queue) ->

compiler/lib/global_deadcode.ml

+6-6
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ let usages prog (global_info : Global_flow.info) : usage_kind Var.Map.t Var.Tbl.
126126
List.iter
127127
~f:(fun a -> if variable_may_escape a global_info then add_use Compute x a)
128128
args
129-
| Block (_, vars, _) -> Array.iter ~f:(add_use Compute x) vars
129+
| Block (_, vars, _, _) -> Array.iter ~f:(add_use Compute x) vars
130130
| Field (z, _) -> add_use Compute x z
131131
| Constant _ -> ()
132132
| Special _ -> ()
@@ -172,7 +172,7 @@ let expr_vars e =
172172
| Apply { f; args; _ } ->
173173
let vars = Var.Set.add f vars in
174174
List.fold_left ~f:(fun acc x -> Var.Set.add x acc) ~init:vars args
175-
| Block (_, params, _) ->
175+
| Block (_, params, _, _) ->
176176
Array.fold_left ~f:(fun acc x -> Var.Set.add x acc) ~init:vars params
177177
| Field (z, _) -> Var.Set.add z vars
178178
| Prim (_, args) ->
@@ -223,7 +223,7 @@ let liveness prog pure_funs (global_info : Global_flow.info) =
223223
List.iter
224224
~f:(fun x -> if variable_may_escape x global_info then add_top x)
225225
args
226-
| Block (_, _, _)
226+
| Block (_, _, _, _)
227227
| Field (_, _)
228228
| Closure (_, _)
229229
| Constant _
@@ -286,7 +286,7 @@ let propagate uses defs live_vars live_table x =
286286
(* If y is a live block, then x is the join of liveness fields that are x *)
287287
| Live fields -> (
288288
match Var.Tbl.get defs y with
289-
| Expr (Block (_, vars, _)) ->
289+
| Expr (Block (_, vars, _, _)) ->
290290
let found = ref false in
291291
Array.iteri
292292
~f:(fun i v ->
@@ -341,7 +341,7 @@ let zero prog sentinal live_table =
341341
match instr with
342342
| Let (x, e) -> (
343343
match e with
344-
| Block (start, vars, is_array) -> (
344+
| Block (start, vars, is_array, imm) -> (
345345
match Var.Tbl.get live_table x with
346346
| Live fields ->
347347
let vars =
@@ -350,7 +350,7 @@ let zero prog sentinal live_table =
350350
vars
351351
|> compact_vars
352352
in
353-
let e = Block (start, vars, is_array) in
353+
let e = Block (start, vars, is_array, imm) in
354354
Let (x, e)
355355
| _ -> instr)
356356
| Apply ap ->

compiler/lib/global_flow.ml

+6-6
Original file line numberDiff line numberDiff line change
@@ -194,15 +194,15 @@ let expr_deps blocks st x e =
194194
| Pv v, `Const -> do_escape st Escape_constant v
195195
| Pv v, `Shallow_const -> (
196196
match st.defs.(Var.idx v) with
197-
| Expr (Block (_, a, _)) ->
197+
| Expr (Block (_, a, _, _)) ->
198198
Array.iter a ~f:(fun x -> do_escape st Escape x)
199199
| _ -> do_escape st Escape v)
200200
| Pv v, `Object_literal -> (
201201
match st.defs.(Var.idx v) with
202-
| Expr (Block (_, a, _)) ->
202+
| Expr (Block (_, a, _, _)) ->
203203
Array.iter a ~f:(fun x ->
204204
match st.defs.(Var.idx x) with
205-
| Expr (Block (_, [| _k; v |], _)) -> do_escape st Escape v
205+
| Expr (Block (_, [| _k; v |], _, _)) -> do_escape st Escape v
206206
| _ -> do_escape st Escape x)
207207
| _ -> do_escape st Escape v)
208208
| Pv v, `Mutable -> do_escape st Escape v);
@@ -325,7 +325,7 @@ module Domain = struct
325325
then (
326326
st.may_escape.(idx) <- s;
327327
match st.defs.(idx) with
328-
| Expr (Block (_, a, _)) -> (
328+
| Expr (Block (_, a, _, _)) -> (
329329
Array.iter ~f:(fun y -> variable_escape ~update ~st ~approx s y) a;
330330
match s with
331331
| Escape ->
@@ -410,7 +410,7 @@ let propagate st ~update approx x =
410410
~approx
411411
(fun z ->
412412
match st.defs.(Var.idx z) with
413-
| Expr (Block (t, a, _))
413+
| Expr (Block (t, a, _, _))
414414
when n < Array.length a
415415
&&
416416
match tags with
@@ -440,7 +440,7 @@ let propagate st ~update approx x =
440440
~others
441441
(fun z ->
442442
match st.defs.(Var.idx z) with
443-
| Expr (Block (_, lst, _)) ->
443+
| Expr (Block (_, lst, _, _)) ->
444444
Array.iter ~f:(fun t -> add_dep st x t) lst;
445445
let a =
446446
Array.fold_left

0 commit comments

Comments
 (0)