Skip to content

Commit f65e3a4

Browse files
committed
Compiler: consume hints for immutable blocks
1 parent 8de4c99 commit f65e3a4

File tree

5 files changed

+438
-352
lines changed

5 files changed

+438
-352
lines changed

compiler/lib/ocaml_compiler.ml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,4 +283,6 @@ module Cmo_format = struct
283283
let imports (t : t) = t.cu_imports
284284

285285
let force_link (t : t) = t.cu_force_link
286+
287+
let hints_pos (t : t) = t.cu_hint
286288
end

compiler/lib/ocaml_compiler.mli

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@ module Cmo_format : sig
7373
val force_link : t -> bool
7474

7575
val imports : t -> (string * string option) list
76+
77+
val hints_pos : t -> int
7678
end

compiler/lib/parse_bytecode.ml

Lines changed: 114 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,63 @@ end = struct
333333
StringSet.of_list (List.concat paths)
334334
end
335335

336+
module Hints = struct
337+
module Primitive = struct
338+
type boxed_integer =
339+
| Pnativeint
340+
| Pint32
341+
| Pint64
342+
343+
type native_repr =
344+
| Same_as_ocaml_repr
345+
| Unboxed_float
346+
| Unboxed_integer of boxed_integer
347+
| Untagged_immediate
348+
349+
type description =
350+
{ prim_name : string (* Name of primitive or C function *)
351+
; prim_arity : int (* Number of arguments *)
352+
; prim_alloc : bool (* Does it allocates or raise? *)
353+
; prim_native_name : string (* Name of C function for the nat. code gen. *)
354+
; prim_native_repr_args : native_repr list
355+
; prim_native_repr_res : native_repr
356+
}
357+
[@@ocaml.warning "-unused-field"]
358+
end
359+
360+
type optimization_hint =
361+
| Hint_immutable
362+
| Hint_unsafe
363+
| Hint_int of Primitive.boxed_integer
364+
| Hint_array of Lambda.array_kind
365+
| Hint_bigarray of
366+
{ unsafe : bool
367+
; elt_kind : Lambda.bigarray_kind
368+
; layout : Lambda.bigarray_layout
369+
}
370+
| Hint_primitive of Primitive.description
371+
372+
type t = { hints : optimization_hint Int.Hashtbl.t }
373+
374+
let equal (a : optimization_hint) b = Poly.equal a b
375+
376+
let create () = { hints = Int.Hashtbl.create 17 }
377+
378+
let read t ~orig ic =
379+
let l : (int * optimization_hint) list = input_value ic in
380+
381+
List.iter l ~f:(fun (pos, hint) -> Int.Hashtbl.add t.hints ((pos + orig) / 4) hint)
382+
383+
let read_section t ic =
384+
let len = input_binary_int ic in
385+
for _i = 0 to len - 1 do
386+
let orig = input_binary_int ic in
387+
read t ~orig ic
388+
done
389+
390+
let find t pc = Int.Hashtbl.find_all t.hints pc
391+
end
392+
336393
(* Block analysis *)
337394
(* Detect each block *)
338395
module Blocks : sig
@@ -864,6 +921,7 @@ type compile_info =
864921
; code : string
865922
; limit : int
866923
; debug : Debug.t
924+
; hints : Hints.t
867925
}
868926

869927
let string_of_addr debug_data addr =
@@ -886,9 +944,11 @@ let string_of_addr debug_data addr =
886944
in
887945
Printf.sprintf "%s:%s-%s %s" file (pos loc.loc_start) (pos loc.loc_end) kind)
888946

889-
let is_immutable _instr _infos _pc = (* We don't know yet *) Maybe_mutable
947+
let is_immutable _instr infos pc =
948+
let hints = Hints.find infos.hints pc in
949+
if List.mem ~eq:Hints.equal Hints.Hint_immutable hints then Immutable else Maybe_mutable
890950

891-
let rec compile_block blocks joins debug_data code pc state : unit =
951+
let rec compile_block blocks joins hints debug_data code pc state : unit =
892952
match Addr.Map.find_opt pc !tagged_blocks with
893953
| Some old_state -> (
894954
(* Check that the shape of the stack is compatible with the one used to compile the block *)
@@ -920,7 +980,7 @@ let rec compile_block blocks joins debug_data code pc state : unit =
920980
let state = if Addr.Set.mem pc joins then State.start_block pc state else state in
921981
tagged_blocks := Addr.Map.add pc state !tagged_blocks;
922982
let instr, last, state' =
923-
compile { blocks; joins; code; limit; debug = debug_data } pc state []
983+
compile { blocks; joins; code; limit; debug = debug_data; hints } pc state []
924984
in
925985
assert (not (Addr.Map.mem pc !compiled_blocks));
926986
(* When jumping to a block that was already visited and the
@@ -959,10 +1019,10 @@ let rec compile_block blocks joins debug_data code pc state : unit =
9591019
!compiled_blocks;
9601020
match last with
9611021
| Branch (pc', _) ->
962-
compile_block blocks joins debug_data code pc' (adjust_state pc')
1022+
compile_block blocks joins hints debug_data code pc' (adjust_state pc')
9631023
| Cond (_, (pc1, _), (pc2, _)) ->
964-
compile_block blocks joins debug_data code pc1 (adjust_state pc1);
965-
compile_block blocks joins debug_data code pc2 (adjust_state pc2)
1024+
compile_block blocks joins hints debug_data code pc1 (adjust_state pc1);
1025+
compile_block blocks joins hints debug_data code pc2 (adjust_state pc2)
9661026
| Poptrap (_, _) -> ()
9671027
| Switch (_, _) -> ()
9681028
| Raise _ | Return _ | Stop -> ()
@@ -1289,7 +1349,7 @@ and compile infos pc state (instrs : instr list) =
12891349
let params, state' = State.make_stack nparams state' in
12901350
if debug_parser () then Format.printf ") {@.";
12911351
let state' = State.clear_accu state' in
1292-
compile_block infos.blocks infos.joins infos.debug code addr state';
1352+
compile_block infos.blocks infos.joins infos.hints infos.debug code addr state';
12931353
if debug_parser () then Format.printf "}@.";
12941354
compile
12951355
infos
@@ -1347,7 +1407,14 @@ and compile infos pc state (instrs : instr list) =
13471407
let params, state' = State.make_stack nparams state' in
13481408
if debug_parser () then Format.printf ") {@.";
13491409
let state' = State.clear_accu state' in
1350-
compile_block infos.blocks infos.joins infos.debug code addr state';
1410+
compile_block
1411+
infos.blocks
1412+
infos.joins
1413+
infos.hints
1414+
infos.debug
1415+
code
1416+
addr
1417+
state';
13511418
if debug_parser () then Format.printf "}@.";
13521419
Let
13531420
( x
@@ -1759,9 +1826,9 @@ and compile infos pc state (instrs : instr list) =
17591826
let it = Array.init isize ~f:(fun i -> base + gets code (base + i)) in
17601827
let bt = Array.init bsize ~f:(fun i -> base + gets code (base + isize + i)) in
17611828
Array.iter it ~f:(fun pc' ->
1762-
compile_block infos.blocks infos.joins infos.debug code pc' state);
1829+
compile_block infos.blocks infos.joins infos.hints infos.debug code pc' state);
17631830
Array.iter bt ~f:(fun pc' ->
1764-
compile_block infos.blocks infos.joins infos.debug code pc' state);
1831+
compile_block infos.blocks infos.joins infos.hints infos.debug code pc' state);
17651832
match isize, bsize with
17661833
| _, 0 -> instrs, Switch (x, Array.map it ~f:(fun pc -> pc, [])), state
17671834
| 0, _ ->
@@ -1828,10 +1895,18 @@ and compile infos pc state (instrs : instr list) =
18281895
interm_addr
18291896
(Some handler_ctx_state, [], Pushtrap ((body_addr, []), x, (handler_addr, [])))
18301897
!compiled_blocks;
1831-
compile_block infos.blocks infos.joins infos.debug code handler_addr handler_state;
18321898
compile_block
18331899
infos.blocks
18341900
infos.joins
1901+
infos.hints
1902+
infos.debug
1903+
code
1904+
handler_addr
1905+
handler_state;
1906+
compile_block
1907+
infos.blocks
1908+
infos.joins
1909+
infos.hints
18351910
infos.debug
18361911
code
18371912
body_addr
@@ -1850,6 +1925,7 @@ and compile infos pc state (instrs : instr list) =
18501925
compile_block
18511926
infos.blocks
18521927
infos.joins
1928+
infos.hints
18531929
infos.debug
18541930
code
18551931
addr
@@ -2539,7 +2615,7 @@ type one =
25392615
; debug : Debug.summary
25402616
}
25412617

2542-
let parse_bytecode code globals debug_data =
2618+
let parse_bytecode code globals hints debug_data =
25432619
let immutable = Code.Var.Hashtbl.create 0 in
25442620
let state = State.initial globals immutable in
25452621
Code.Var.reset ();
@@ -2550,7 +2626,7 @@ let parse_bytecode code globals debug_data =
25502626
then (
25512627
let start = 0 in
25522628

2553-
compile_block blocks' joins debug_data code start state;
2629+
compile_block blocks' joins hints debug_data code start state;
25542630
let blocks =
25552631
Addr.Map.mapi
25562632
(fun _ (state, instr, last) ->
@@ -2674,6 +2750,7 @@ let from_exe
26742750
?(debug = false)
26752751
ic =
26762752
let debug_data = Debug.create ~include_cmis debug in
2753+
let hints = Hints.create () in
26772754
let toc = Toc.read ic in
26782755
let primitives = read_primitives toc ic in
26792756
let primitive_table = Array.of_list primitives in
@@ -2720,14 +2797,19 @@ let from_exe
27202797
available.@.");
27212798
if times () then Format.eprintf " read debug events: %a@." Timer.print t;
27222799

2800+
(try
2801+
ignore (Toc.seek_section toc ic "HINT");
2802+
Hints.read_section hints ic
2803+
with Not_found -> ());
2804+
27232805
let globals = make_globals (Array.length init_data) init_data primitive_table in
27242806
if linkall
27252807
then
27262808
(* export globals *)
27272809
Ocaml_compiler.Symtable.GlobalMap.iter symbols ~f:(fun id n ->
27282810
globals.named_value.(n) <- Some (Ocaml_compiler.Symtable.Global.name id);
27292811
globals.is_exported.(n) <- true);
2730-
let p = parse_bytecode code globals debug_data in
2812+
let p = parse_bytecode code globals hints debug_data in
27312813
(* register predefined exception *)
27322814
let body =
27332815
List.fold_left predefined_exceptions ~init:[] ~f:(fun body (i, name) ->
@@ -2835,6 +2917,7 @@ let from_exe
28352917
(* As input: list of primitives + size of global table *)
28362918
let from_bytes ~prims ~debug (code : bytecode) =
28372919
let debug_data = Debug.create ~include_cmis:false true in
2920+
let hints = Hints.create () in
28382921
let t = Timer.make () in
28392922
if Debug.names debug_data
28402923
then
@@ -2857,7 +2940,7 @@ let from_bytes ~prims ~debug (code : bytecode) =
28572940
t
28582941
in
28592942
let globals = make_globals 0 [||] prims in
2860-
let p = parse_bytecode code globals debug_data in
2943+
let p = parse_bytecode code globals hints debug_data in
28612944
let gdata = Var.fresh_n "global_data" in
28622945
let need_gdata = ref false in
28632946
let find_name i =
@@ -2989,7 +3072,7 @@ module Reloc = struct
29893072
globals
29903073
end
29913074

2992-
let from_compilation_units ~includes:_ ~include_cmis ~debug_data l =
3075+
let from_compilation_units ~includes:_ ~include_cmis ~hints ~debug_data l =
29933076
let reloc = Reloc.create () in
29943077
List.iter l ~f:(fun (compunit, code) -> Reloc.step1 reloc compunit code);
29953078
List.iter l ~f:(fun (compunit, code) -> Reloc.step2 reloc compunit code);
@@ -2998,7 +3081,7 @@ let from_compilation_units ~includes:_ ~include_cmis ~debug_data l =
29983081
let l = List.map l ~f:(fun (_, c) -> Bytes.to_string c) in
29993082
String.concat ~sep:"" l
30003083
in
3001-
let prog = parse_bytecode code globals debug_data in
3084+
let prog = parse_bytecode code globals hints debug_data in
30023085
let gdata = Var.fresh_n "global_data" in
30033086
let need_gdata = ref false in
30043087
let body =
@@ -3050,12 +3133,20 @@ let from_cmo ?(includes = []) ?(include_cmis = false) ?(debug = false) compunit
30503133
seek_in ic compunit.Cmo_format.cu_debug;
30513134
Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:0 ic);
30523135
if times () then Format.eprintf " read debug events: %a@." Timer.print t;
3053-
let p = from_compilation_units ~includes ~include_cmis ~debug_data [ compunit, code ] in
3136+
let hints = Hints.create () in
3137+
if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0
3138+
then (
3139+
seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit);
3140+
Hints.read hints ~orig:0 ic);
3141+
let p =
3142+
from_compilation_units ~includes ~include_cmis ~hints ~debug_data [ compunit, code ]
3143+
in
30543144
Code.invariant p.code;
30553145
p
30563146

30573147
let from_cma ?(includes = []) ?(include_cmis = false) ?(debug = false) lib ic =
30583148
let debug_data = Debug.create ~include_cmis debug in
3149+
let hints = Hints.create () in
30593150
let orig = ref 0 in
30603151
let t = ref 0. in
30613152
let units =
@@ -3068,12 +3159,16 @@ let from_cma ?(includes = []) ?(include_cmis = false) ?(debug = false) lib ic =
30683159
then (
30693160
seek_in ic compunit.Cmo_format.cu_debug;
30703161
Debug.read_event_list debug_data ~crcs:[] ~includes ~orig:!orig ic);
3162+
if Ocaml_compiler.Cmo_format.hints_pos compunit <> 0
3163+
then (
3164+
seek_in ic (Ocaml_compiler.Cmo_format.hints_pos compunit);
3165+
Hints.read hints ~orig:!orig ic);
30713166
t := !t +. Timer.get t0;
30723167
orig := !orig + compunit.Cmo_format.cu_codesize;
30733168
compunit, code)
30743169
in
30753170
if times () then Format.eprintf " read debug events: %.2f@." !t;
3076-
let p = from_compilation_units ~includes ~include_cmis ~debug_data units in
3171+
let p = from_compilation_units ~includes ~include_cmis ~hints ~debug_data units in
30773172
Code.invariant p.code;
30783173
p
30793174

compiler/tests-compiler/gh747.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ end
222222
1:
223223
2: //# unitInfo: Provides: Test
224224
3: //# unitInfo: Requires: Stdlib__Printf
225-
4: //# shape: Test:[N,N,[N],N,N,N,N,N,N,N,N,N,N,F(2),F(2),[F(4)]]
225+
4: //# shape: Test:[N,N,[N],N,N,N,N,N,N,N,N,N,[N,N],F(2),F(2),[F(4)]]
226226
5: (function
227227
6: (globalThis){
228228
7: "use strict";

0 commit comments

Comments
 (0)