summaryrefslogtreecommitdiffstats
path: root/asmcomp/closure.ml
diff options
context:
space:
mode:
Diffstat (limited to 'asmcomp/closure.ml')
-rw-r--r--asmcomp/closure.ml201
1 files changed, 99 insertions, 102 deletions
diff --git a/asmcomp/closure.ml b/asmcomp/closure.ml
index 6183c351c..a103c22e2 100644
--- a/asmcomp/closure.ml
+++ b/asmcomp/closure.ml
@@ -25,19 +25,6 @@ let rec build_closure_env env_param pos = function
Tbl.add id (Uprim(Pfield pos, [Uvar env_param]))
(build_closure_env env_param (pos+1) rem)
-(* Auxiliaries for compiling recursive definitions *)
-
-type fun_analysis =
- { fa_desc: function_description;
- fa_params: Ident.t list;
- fa_body: lambda;
- fa_cenv: (Ident.t, ulambda) Tbl.t;
- fa_clos: ulambda list }
-
-type rec_approximation =
- Rec_function of fun_analysis
- | Rec_other of lambda
-
(* Uncurry an expression and explicitate closures.
Also return the approximation of the expression.
The approximation environment [fenv] maps idents to approximations.
@@ -45,14 +32,19 @@ type rec_approximation =
The closure environment [cenv] maps idents to [ulambda] terms.
It is used to substitute environment accesses for free identifiers. *)
+let close_var cenv id =
+ try Tbl.find id cenv with Not_found -> Uvar id
+
+let approx_var fenv id =
+ try Tbl.find id fenv with Not_found -> Value_unknown
+
let rec close fenv cenv = function
Lvar id ->
- (begin try Tbl.find id cenv with Not_found -> Uvar id end,
- begin try Tbl.find id fenv with Not_found -> Value_unknown end)
+ (close_var cenv id, approx_var fenv id)
| Lconst cst ->
(Uconst cst, Value_unknown)
| Lfunction(param, body) as funct ->
- close_function fenv cenv (Ident.new "fun") funct
+ close_one_function fenv cenv (Ident.new "fun") funct
| Lapply(funct, args) ->
let nargs = List.length args in
begin match close fenv cenv funct with
@@ -76,45 +68,40 @@ let rec close fenv cenv = function
(Ugeneric_apply(ufunct, close_list fenv cenv args), Value_unknown)
end
| Llet(id, lam, body) ->
- let (ulam, alam) = close_named fenv cenv id lam in
+ let (ulam, alam) = close_named fenv cenv id lam in
let (ubody, abody) = close (Tbl.add id alam fenv) cenv body in
(Ulet(id, ulam, ubody), abody)
- | Lletrec([id, (Lfunction(_, _) as funct)], body) ->
- let funapp = close_analyze_function_rec1 fenv cenv id funct in
- let (ufunct, approx) =
- close_build_function
- (Tbl.add id (Value_closure(funapp.fa_desc, Value_unknown)) fenv)
- funapp in
- let (ubody, approx) = close (Tbl.add id approx fenv) cenv body in
- (Ulet(id, ufunct, ubody), approx)
- | Lletrec(decls, body) ->
- let rec make_rec_fenv = function
- [] -> (fenv, [])
- | (id, lam) :: rem ->
- let (new_fenv, precomp) = make_rec_fenv rem in
- match lam with
- Lfunction(param, body) ->
- let funapp = close_analyze_function fenv cenv id lam in
- (Tbl.add id (Value_closure(funapp.fa_desc, Value_unknown))
- new_fenv,
- (id, Rec_function funapp) :: precomp)
- | _ ->
- (new_fenv, (id, Rec_other lam) :: precomp) in
- let (rec_fenv, precomp) = make_rec_fenv decls in
- let rec close_decls = function
- [] -> (fenv, [])
- | (id, pre) :: rem ->
- let (new_fenv, urem) = close_decls rem in
- match pre with
- Rec_function funapp ->
- let (ulam, approx) = close_build_function rec_fenv funapp in
- (Tbl.add id approx new_fenv, (id, ulam) :: urem)
- | Rec_other lam ->
- let (ulam, approx) = close rec_fenv cenv lam in
- (Tbl.add id approx new_fenv, (id, ulam) :: urem) in
- let (body_fenv, udecls) = close_decls precomp in
- let (ubody, approx) = close body_fenv cenv body in
- (Uletrec(udecls, ubody), approx)
+ | Lletrec(defs, body) ->
+ if List.for_all
+ (function (id, Lfunction(_, _)) -> true | _ -> false)
+ defs
+ then begin
+ (* Simple case: only function definitions *)
+ let (clos, infos) = close_functions fenv cenv defs in
+ let clos_ident = Ident.new "clos" in
+ let fenv_body =
+ List.fold_right
+ (fun (id, pos, approx) fenv -> Tbl.add id approx fenv)
+ infos fenv in
+ let cenv_body =
+ List.fold_right
+ (fun (id, pos, approx) cenv ->
+ Tbl.add id (Uoffset(Uvar clos_ident, pos)) cenv)
+ infos cenv in
+ let (ubody, approx) = close fenv_body cenv_body body in
+ (Ulet(clos_ident, clos, ubody), approx)
+ end else begin
+ (* General case: recursive definition of values *)
+ let rec clos_defs = function
+ [] -> ([], fenv)
+ | (id, lam) :: rem ->
+ let (udefs, fenv_body) = clos_defs rem in
+ let (ulam, approx) = close fenv cenv lam in
+ ((id, ulam) :: udefs, Tbl.add id approx fenv_body) in
+ let (udefs, fenv_body) = clos_defs defs in
+ let (ubody, approx) = close fenv_body cenv body in
+ (Uletrec(udefs, ubody), approx)
+ end
| Lprim(Pgetglobal id, []) ->
(Uprim(Pgetglobal id, []), Compilenv.global_approx id)
| Lprim(Psetglobal id, [lam]) ->
@@ -177,61 +164,71 @@ and close_list fenv cenv = function
and close_named fenv cenv id = function
Lfunction(param, body) as funct ->
- close_function fenv cenv id funct
+ close_one_function fenv cenv id funct
| lam ->
close fenv cenv lam
-(* Build a function closure with the given name *)
-
-and close_function fenv cenv id funct =
- close_build_function fenv (close_analyze_function fenv cenv id funct)
-
-(* Return preliminary information for a function closure *)
-
-and close_analyze_function fenv cenv id funct =
- let fv = IdentSet.elements(free_variables funct) in
- let label = Compilenv.current_unit_name() ^ "_" ^ Ident.unique_name id in
- let (params, body) = uncurry_fun funct in
- let arity = List.length params in
- let env_param = Ident.new "env" in
- let cenv_body =
- build_closure_env env_param (if arity > 1 then 3 else 2) fv in
- {fa_desc = {fun_label = label; fun_arity = arity; fun_closed = (fv=[])};
- fa_params = params @ [env_param];
- fa_body = body;
- fa_cenv = cenv_body;
- fa_clos = close_list fenv cenv (List.map (fun id -> Lvar id) fv)}
-
-(* Same, but for a simply recursive function. In this case, the closure for
- the function itself is in its environment parameter. *)
+(* Build a shared closure for a set of mutually recursive functions *)
-and close_analyze_function_rec1 fenv cenv id funct =
- let fv = IdentSet.elements(IdentSet.remove id (free_variables funct)) in
- let label = Compilenv.current_unit_name() ^ "_" ^ Ident.unique_name id in
- let (params, body) = uncurry_fun funct in
- let arity = List.length params in
- let env_param = Ident.new "env" in
- let cenv_body =
- Tbl.add id (Uvar env_param)
- (build_closure_env env_param (if arity > 1 then 3 else 2) fv) in
- (* Even if fv = [], env may be used inside to refer to the functional
- value of the function. Not detected here. *)
- {fa_desc = {fun_label = label; fun_arity = arity; fun_closed = false};
- fa_params = params @ [env_param];
- fa_body = body;
- fa_cenv = cenv_body;
- fa_clos = close_list fenv cenv (List.map (fun id -> Lvar id) fv)}
+and close_functions fenv cenv fun_defs =
+ (* Determine the free variables of the functions *)
+ let fv =
+ IdentSet.elements (free_variables (Lletrec(fun_defs, lambda_unit))) in
+ (* Uncurry the definitions and build their fundesc *)
+ let uncurried_defs =
+ List.map
+ (fun (id, def) ->
+ let label =
+ Compilenv.current_unit_name() ^ "_" ^ Ident.unique_name id in
+ let (params, body) = uncurry_fun def in
+ let fundesc =
+ {fun_label = Compilenv.current_unit_name() ^ "_" ^
+ Ident.unique_name id;
+ fun_arity = List.length params;
+ fun_closed = IdentSet.is_empty(free_variables def)} in
+ (id, params, body, fundesc))
+ fun_defs in
+ (* Build an approximate fenv for compiling the functions *)
+ let fenv_rec =
+ List.fold_right
+ (fun (id, params, body, fundesc) fenv ->
+ Tbl.add id (Value_closure(fundesc, Value_unknown)) fenv)
+ uncurried_defs fenv in
+ (* Determine the offsets of each function's closure in the shared block *)
+ let env_pos = ref (-1) in
+ let clos_offsets =
+ List.map
+ (fun (id, params, body, fundesc) ->
+ let pos = !env_pos + 1 in
+ env_pos := !env_pos + 1 + (if fundesc.fun_arity > 1 then 3 else 2);
+ pos)
+ uncurried_defs in
+ let fv_pos = !env_pos in
+ (* Translate each function definition *)
+ let clos_fundef (id, params, body, fundesc) env_pos =
+ let env_param = Ident.new "env" in
+ let cenv_fv =
+ build_closure_env env_param (fv_pos - env_pos) fv in
+ let cenv_body =
+ List.fold_right2
+ (fun (id, params, arity, body) pos env ->
+ Tbl.add id (Uoffset(Uvar env_param, pos - env_pos)) env)
+ uncurried_defs clos_offsets cenv_fv in
+ let (ubody, approx) = close fenv_rec cenv_body body in
+ ((fundesc.fun_label, fundesc.fun_arity, params @ [env_param], ubody),
+ (id, env_pos, Value_closure(fundesc, approx))) in
+ (* Translate all function definitions. Return the Uclosure node and
+ the list of all identifiers defined, with offsets and approximations. *)
+ let (clos, infos) =
+ List.split (List.map2 clos_fundef uncurried_defs clos_offsets) in
+ (Uclosure(clos, List.map (close_var cenv) fv), infos)
-(* Actually build the function closure based on infos returned by
- [close_analyze_function] *)
+(* Same, for one function *)
-and close_build_function fenv funapp =
- (* No need to add [params] to [fenv] since their approximations are
- unknown anyway *)
- let (ubody, approx) = close fenv funapp.fa_cenv funapp.fa_body in
- (Uclosure(funapp.fa_desc.fun_label, funapp.fa_desc.fun_arity,
- funapp.fa_params, ubody, funapp.fa_clos),
- Value_closure(funapp.fa_desc, approx))
+and close_one_function fenv cenv id funct =
+ match close_functions fenv cenv [id, funct] with
+ (clos, (id, pos, approx) :: _) -> (clos, approx)
+ | _ -> fatal_error "Closure.close_one_function"
(* Close a switch, preserving sharing between cases. *)