(**************************************************************************) (* *) (* OCaml *) (* *) (* Pierre Chambart, OCamlPro *) (* Mark Shinwell and Leo White, Jane Street Europe *) (* *) (* Copyright 2013--2016 OCamlPro SAS *) (* Copyright 2014--2016 Jane Street Group LLC *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) [@@@ocaml.warning "+a-4-9-30-40-41-42-66"] open! Int_replace_polymorphic_compare module ASA = Augment_specialised_args module W = ASA.What_to_specialise module E = Inline_and_simplify_aux.Env module Transform = struct let pass_name = "unbox-closures" let precondition ~env ~(set_of_closures : Flambda.set_of_closures) = !Clflags.unbox_closures && not (E.at_toplevel env) && not (Variable.Map.is_empty set_of_closures.free_vars) let what_to_specialise ~env ~(set_of_closures : Flambda.set_of_closures) = let what_to_specialise = W.create ~set_of_closures in if not (precondition ~env ~set_of_closures) then what_to_specialise else begin let round = E.round env in let num_closure_vars = Variable.Map.cardinal set_of_closures.free_vars in let module B = Inlining_cost.Benefit in let saved_by_not_building_closure = (* For the moment assume that we're going to cause all functions in the set to become closed. *) B.remove_prims (B.remove_call B.zero) num_closure_vars in Flambda_iterators.fold_function_decls_ignoring_stubs set_of_closures ~init:what_to_specialise ~f:(fun ~fun_var ~(function_decl : Flambda.function_declaration) what_to_specialise -> let body_size = Inlining_cost.lambda_size function_decl.body in (* If the function is small enough, make a direct call surrogate for it, so that indirect calls are not penalised by having to bounce through the stub. (Making such a surrogate involves duplicating the function.) *) let small_enough_to_duplicate = let module W = Inlining_cost.Whether_sufficient_benefit in let wsb = W.create_estimate ~original_size:0 ~toplevel:false ~branch_depth:0 ~new_size:((body_size / !Clflags.unbox_closures_factor) + 1) ~benefit:saved_by_not_building_closure ~lifting:false ~round in W.evaluate wsb in let what_to_specialise = if small_enough_to_duplicate then W.make_direct_call_surrogate_for what_to_specialise ~fun_var else what_to_specialise in let bound_by_the_closure = Flambda_utils.variables_bound_by_the_closure (Closure_id.wrap fun_var) set_of_closures.function_decls in Variable.Set.fold (fun inner_free_var what_to_specialise -> W.new_specialised_arg what_to_specialise ~fun_var ~group:inner_free_var ~definition:(Existing_inner_free_var inner_free_var)) bound_by_the_closure what_to_specialise) end end include ASA.Make (Transform)