Skip to content

Commit 70e0ceb

Browse files
committed
Clean up IR diagnostics
Replace the ambiguous internal -bs-diagnose option with -debug-ir while preserving its role as an umbrella mode that also enables Lam invariant checks. Keep diagnostic state per compilation so reentrant and multi-file compiler processes produce deterministic artifacts. Write Lam and JS snapshots into one <output-prefix>.debug-ir directory, use a unified chronological counter, and remove recognized stale artifacts before each run. Centralize dumping in Ir_diagnostics instead of keeping module-global counters in Lam_util and Js_pass_debug. Remove Js_pass_debug entirely and rename lam_util.cppo.ml now that it no longer contains CPPO directives. Add a build integration test that verifies Lam, grouped-Lam, and JS artifacts, consecutive numbering, stale-artifact cleanup, and removal by rescript clean. Signed-off-by: Cristiano Calcagno <cristianoc@users.noreply.github.com>
1 parent c478363 commit 70e0ceb

15 files changed

Lines changed: 255 additions & 249 deletions

compiler/bsc/rescript_compiler_main.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,9 @@ let command_line_flags : (string * Bsc_args.spec * string) array =
409409
( "-bs-no-cross-module-opt",
410410
clear Js_config.cross_module_inline,
411411
"*internal* Disable cross module inlining(experimental)" );
412-
("-bs-diagnose", set Js_config.diagnose, "*internal* More verbose output");
412+
( "-debug-ir",
413+
set Js_config.debug_ir,
414+
"*internal* Dump compiler IR and enable Lam invariant checks" );
413415
( "-check-lam",
414416
set Js_config.check_lam,
415417
"*internal* Check Lam invariants after optimization passes" );

compiler/common/ext_log.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type 'a logging = ('a, Format.formatter, unit, unit, unit, unit) format6 -> 'a
2626

2727
(* TODO: add {[@.]} later for all *)
2828
let dwarn ?(__POS__ : (string * int * int * int) option) f =
29-
if !Js_config.diagnose then
29+
if !Js_config.debug_ir then
3030
match __POS__ with
3131
| None -> Format.fprintf Format.err_formatter ("WARN: " ^^ f ^^ "@.")
3232
| Some (file, line, _, _) ->

compiler/common/js_config.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ let no_version_header = ref false
3232

3333
let directives = ref []
3434
let cross_module_inline = ref false
35-
let diagnose = ref false
35+
let debug_ir = ref false
3636
let check_lam = ref false
3737

3838
(* let (//) = Filename.concat *)

compiler/common/js_config.mli

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ val directives : string list ref
4949
val cross_module_inline : bool ref
5050
(** cross module inline option *)
5151

52-
val diagnose : bool ref
53-
(** diagnose option *)
52+
val debug_ir : bool ref
53+
(** dump intermediate representations and related diagnostics *)
5454

5555
val check_lam : bool ref
5656
(** check Lam invariants after optimization passes *)

compiler/core/dune

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,8 @@
1313
(action
1414
(run %{bin:cppo} %{env:CPPO_FLAGS=} %{deps} -o %{target})))
1515

16-
(rule
17-
(target js_pass_debug.ml)
18-
(deps js_pass_debug.cppo.ml)
19-
(action
20-
(run %{bin:cppo} %{env:CPPO_FLAGS=} %{deps} -o %{target})))
21-
2216
(rule
2317
(target lam_compile_main.ml)
2418
(deps lam_compile_main.cppo.ml)
2519
(action
2620
(run %{bin:cppo} %{env:CPPO_FLAGS=} %{deps} -o %{target})))
27-
28-
(rule
29-
(target lam_util.ml)
30-
(deps lam_util.cppo.ml)
31-
(action
32-
(run %{bin:cppo} %{env:CPPO_FLAGS=} %{deps} -o %{target})))

compiler/core/ir_diagnostics.ml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
type t = {directory: string; mutable next_index: int}
2+
3+
let is_artifact filename =
4+
match Ext_filename.get_extension_maybe filename with
5+
| ".lam" | ".lambda" | ".jsx" -> true
6+
| _ -> false
7+
8+
let remove_stale_artifacts directory =
9+
Sys.readdir directory
10+
|> Array.iter (fun filename ->
11+
if is_artifact filename then
12+
Misc.remove_file (Filename.concat directory filename))
13+
14+
let create ~output_prefix =
15+
let directory = output_prefix ^ ".debug-ir" in
16+
if Sys.file_exists directory then (
17+
if not (Ext_sys.is_directory_no_exn directory) then
18+
failwith (Printf.sprintf "%s exists and is not a directory" directory);
19+
remove_stale_artifacts directory)
20+
else Sys.mkdir directory 0o755;
21+
Ext_log.dwarn ~__POS__ "Writing IR diagnostics to %s" directory;
22+
{directory; next_index = 1}
23+
24+
let next_path diagnostics ~kind ~pass ~extension =
25+
let index = diagnostics.next_index in
26+
diagnostics.next_index <- index + 1;
27+
Filename.concat diagnostics.directory
28+
(Printf.sprintf "%02d-%s-%s%s" index kind pass extension)
29+
30+
let dump_lam diagnostics ~pass lam =
31+
let path = next_path diagnostics ~kind:"lam" ~pass ~extension:".lam" in
32+
Ext_log.dwarn ~__POS__ "Dumping Lam pass %s to %s" pass path;
33+
Lam_print.serialize path lam
34+
35+
let dump_groups diagnostics groups =
36+
let path =
37+
next_path diagnostics ~kind:"lam" ~pass:"groups" ~extension:".lambda"
38+
in
39+
Ext_log.dwarn ~__POS__ "Dumping Lam groups to %s" path;
40+
Ext_fmt.with_file_as_pp path (fun fmt ->
41+
Format.pp_print_list ~pp_sep:Format.pp_print_newline Lam_group.pp_group
42+
fmt groups)
43+
44+
let dump_js diagnostics ~pass program =
45+
let path = next_path diagnostics ~kind:"js" ~pass ~extension:".jsx" in
46+
Ext_log.dwarn ~__POS__ "Dumping JS pass %s to %s" pass path;
47+
Ext_pervasives.with_file_as_chan path (fun channel ->
48+
Js_dump_program.dump_program program channel)

compiler/core/ir_diagnostics.mli

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
type t
2+
3+
val create : output_prefix:string -> t
4+
val dump_lam : t -> pass:string -> Lam.t -> unit
5+
val dump_groups : t -> Lam_group.t list -> unit
6+
val dump_js : t -> pass:string -> J.program -> unit

compiler/core/js_pass_debug.cppo.ml

Lines changed: 0 additions & 38 deletions
This file was deleted.

compiler/core/js_pass_debug.mli

Lines changed: 0 additions & 25 deletions
This file was deleted.

compiler/core/lam_compile_main.cppo.ml

Lines changed: 51 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -116,32 +116,38 @@ let no_side_effects (rest : Lam_group.t list) : string option =
116116
else None (* TODO :*))
117117

118118

119-
let _d = fun s lam ->
120-
let diagnose = !Js_config.diagnose in
121-
if diagnose then begin
122-
Lam_util.dump s lam;
123-
Ext_log.dwarn ~__POS__ "START CHECKING PASS %s@." s
124-
end;
125-
if !Js_config.check_lam || diagnose then begin
126-
ignore @@ Lam_check.check ~file:!Location.input_name ~pass:s lam;
127-
if diagnose then Ext_log.dwarn ~__POS__ "FINISH CHECKING PASS %s@." s
128-
end;
129-
lam
130-
131-
let _j name program =
132-
if !Js_config.diagnose then Js_pass_debug.dump name program else program
133-
134119
(** Actually simplify_lets is kind of global optimization since it requires you to know whether
135120
it's used or not
136121
*)
137122
let compile
138123
(output_prefix : string)
139124
export_idents
140125
(lam : Lambda.lambda) =
126+
let debug_ir = !Js_config.debug_ir in
127+
let diagnostics =
128+
if debug_ir then Some (Ir_diagnostics.create ~output_prefix) else None
129+
in
130+
let d pass lam =
131+
(match diagnostics with
132+
| Some diagnostics ->
133+
Ir_diagnostics.dump_lam diagnostics ~pass lam;
134+
Ext_log.dwarn ~__POS__ "START CHECKING PASS %s@." pass
135+
| None -> ());
136+
if !Js_config.check_lam || debug_ir then begin
137+
ignore @@ Lam_check.check ~file:!Location.input_name ~pass lam;
138+
if debug_ir then Ext_log.dwarn ~__POS__ "FINISH CHECKING PASS %s@." pass
139+
end;
140+
lam
141+
in
142+
let j pass program =
143+
Ext_option.iter diagnostics (fun diagnostics ->
144+
Ir_diagnostics.dump_js diagnostics ~pass program);
145+
program
146+
in
141147
let export_ident_sets = Set_ident.of_list export_idents in
142148
(* To make toplevel happy - reentrant for js-demo *)
143149
let () =
144-
if !Js_config.diagnose then begin
150+
if debug_ir then begin
145151
Ext_list.iter export_idents
146152
(fun id -> Ext_log.dwarn ~__POS__ "export idents: %s/%d" id.name id.stamp)
147153
end;
@@ -150,9 +156,9 @@ let compile
150156
let lam, may_required_modules = Lam_convert.convert export_ident_sets lam in
151157

152158

153-
let lam = _d "initial" lam in
159+
let lam = d "initial" lam in
154160
let lam = Lam_pass_deep_flatten.deep_flatten lam in
155-
let lam = _d "flatten0" lam in
161+
let lam = d "flatten0" lam in
156162
let meta : Lam_stats.t =
157163
Lam_stats.make
158164
~export_idents
@@ -161,19 +167,19 @@ let compile
161167
let lam =
162168
let lam =
163169
lam
164-
|> _d "flattern1"
170+
|> d "flatten1"
165171
|> Lam_pass_exits.simplify_exits
166-
|> _d "simplyf_exits"
172+
|> d "simplify_exits"
167173
|> (fun lam ->
168174
Lam_pass_collect.collect_info meta lam;
169-
if !Js_config.diagnose then
175+
if debug_ir then
170176
Ext_log.dwarn ~__POS__ "Before simplify_alias: %a@." Lam_stats.print
171177
meta;
172178
lam)
173179
|> Lam_pass_remove_alias.simplify_alias meta
174-
|> _d "simplify_alias"
180+
|> d "simplify_alias"
175181
|> Lam_pass_deep_flatten.deep_flatten
176-
|> _d "flatten2"
182+
|> d "flatten2"
177183
in (* Inling happens*)
178184

179185
let () = Lam_pass_collect.collect_info meta lam in
@@ -182,31 +188,31 @@ let compile
182188
let () = Lam_pass_collect.collect_info meta lam in
183189
let lam =
184190
lam
185-
|> _d "alpha_before"
191+
|> d "alpha_before"
186192
|> Lam_pass_alpha_conversion.alpha_conversion meta
187-
|> _d "alpha_after"
193+
|> d "alpha_after"
188194
|> Lam_pass_exits.simplify_exits in
189195
let () = Lam_pass_collect.collect_info meta lam in
190196

191197

192198
lam
193-
|> _d "simplify_alias_before"
199+
|> d "simplify_alias_before"
194200
|> Lam_pass_remove_alias.simplify_alias meta
195-
|> _d "alpha_conversion"
201+
|> d "alpha_conversion"
196202
|> Lam_pass_alpha_conversion.alpha_conversion meta
197-
|> _d "before-simplify_lets"
203+
|> d "before-simplify_lets"
198204
(* we should investigate a better way to put different passes : )*)
199205
|> Lam_pass_lets_dce.simplify_lets
200206

201-
|> _d "before-simplify-exits"
207+
|> d "before-simplify-exits"
202208
(* |> (fun lam -> Lam_pass_collect.collect_info meta lam
203209
; Lam_pass_remove_alias.simplify_alias meta lam) *)
204210
(* |> Lam_group_pass.scc_pass
205-
|> _d "scc" *)
211+
|> d "scc" *)
206212
|> Lam_pass_exits.simplify_exits
207-
|> _d "simplify_lets"
213+
|> d "simplify_lets"
208214
|> (fun lam ->
209-
if !Js_config.diagnose then
215+
if debug_ir then
210216
Ext_log.dwarn ~__POS__ "Before coercion: %a@." Lam_stats.print meta;
211217
lam)
212218
in
@@ -216,19 +222,15 @@ let compile
216222
in
217223

218224
let () =
219-
if !Js_config.diagnose then begin
225+
if debug_ir then begin
220226
Ext_log.dwarn ~__POS__ "After coercion: %a@." Lam_stats.print meta;
221-
let f =
222-
Ext_filename.new_extension !Location.input_name ".lambda" in
223-
Ext_fmt.with_file_as_pp f begin fun fmt ->
224-
Format.pp_print_list ~pp_sep:Format.pp_print_newline
225-
Lam_group.pp_group fmt (coerced_input.groups)
226-
end
227+
Ext_option.iter diagnostics (fun diagnostics ->
228+
Ir_diagnostics.dump_groups diagnostics coerced_input.groups)
227229
end
228230
in
229231
let maybe_pure = no_side_effects groups in
230232
let () =
231-
if !Js_config.diagnose then
233+
if debug_ir then
232234
Ext_log.dwarn ~__POS__ "\n@[[TIME:]Pre-compile: %f@]@."
233235
(Sys.time () *. 1000.)
234236
in
@@ -238,7 +240,7 @@ let body =
238240
|> Js_output.output_as_block
239241
in
240242
let () =
241-
if !Js_config.diagnose then
243+
if debug_ir then
242244
Ext_log.dwarn ~__POS__ "\n@[[TIME:]Post-compile: %f@]@."
243245
(Sys.time () *. 1000.)
244246
in
@@ -253,22 +255,22 @@ let js : J.program =
253255
block = body}
254256
in
255257
js
256-
|> _j "initial"
258+
|> j "initial"
257259
|> Js_pass_flatten.program
258-
|> _j "flatten"
260+
|> j "flatten"
259261
|> Js_pass_external_shadow.program
260-
|> _j "external_shadow"
262+
|> j "external_shadow"
261263
|> Js_pass_tailcall_inline.tailcall_inline
262-
|> _j "inline_and_shake"
264+
|> j "inline_and_shake"
263265
|> Js_pass_record_rest.program
264-
|> _j "record_rest"
266+
|> j "record_rest"
265267
|> Js_pass_flatten_and_mark_dead.program
266-
|> _j "flatten_and_mark_dead"
268+
|> j "flatten_and_mark_dead"
267269
(* |> Js_inline_and_eliminate.inline_and_shake *)
268-
(* |> _j "inline_and_shake" *)
270+
(* |> j "inline_and_shake" *)
269271
|> (fun js -> ignore @@ Js_pass_scope.program js ; js )
270272
|> Js_shake.shake_program
271-
|> _j "shake"
273+
|> j "shake"
272274
|> ( fun (program: J.program) ->
273275
let external_module_ids : Lam_module_ident.t list =
274276
if !Js_config.all_module_aliases then []

0 commit comments

Comments
 (0)