diff --git a/compiler/eval.ml b/compiler/eval.ml index afd59adc67..7a958cce5f 100644 --- a/compiler/eval.ml +++ b/compiler/eval.ml @@ -58,7 +58,6 @@ let eval_prim x = | _ -> fun _ -> None in let float_binop_bool f = float_binop_aux (fun i j -> Int (if f i j then 1 else 0)) in (match name, l with - | "caml_ml_string_length", [String s] -> Some (Int (String.length s)) (* int *) | "%int_add", _ -> int_binop (Int.add) | "%int_sub", _ -> int_binop (Int.sub) @@ -108,6 +107,23 @@ let eval_prim x = exception Not_constant + +let the_length_of info x = + get_approx info + (fun x -> + match info.info_defs.(Var.idx x) with + | Expr (Constant (String s)) + | Expr (Constant (IString s)) -> Val (String.length s) + | _ -> Top) + Top Bottom + (fun u v -> match u,v with + | Val l,Val l' when l = l' -> Val l + | Bottom,x | x,Bottom -> x + | _ -> Top + ) + x + + let eval_instr info i = match i with | Let (x, Prim (Extern ("caml_js_equals"|"caml_equal"), [y;z])) -> @@ -120,6 +136,18 @@ let eval_instr info i = Let (x , Constant (Int c)) | _ -> i end + | Let (x,Prim (Extern "caml_ml_string_length", [s])) -> + let c = match s with + | Pc (String s) + | Pc (IString s) -> Some (String.length s) + | Pv v -> begin match the_length_of info v with + | Val i -> Some i + | _ -> None end + | _ -> None + in + (match c with + | None -> i + | Some c -> Let(x,Constant (Int c))) | Let (x,Prim (prim, prim_args)) -> begin let prim_args' = List.map (fun x -> diff --git a/compiler/flow.ml b/compiler/flow.ml index 8d48dcbf4a..53f95a3c9f 100644 --- a/compiler/flow.ml +++ b/compiler/flow.ml @@ -27,10 +27,23 @@ open Code let add_var = VarISet.add -type def = Phi of VarSet.t | Expr of Code.expr | Param +type def = Phi of VarSet.t | Expr of Code.expr | Param of (Var.t * int) option + + +type 'a v = + | Bottom + | Val of 'a + | Top + +let string_of_approx f = function + | Bottom -> "Bottom" + | Top -> "Top" + | Val i -> Printf.sprintf "Val %s" (f i) + type info = { info_defs:def array; + info_params: VarSet.t array array; info_known_origins : Code.VarSet.t Code.VarTbl.t; info_maybe_unknown : bool Code.VarTbl.t; info_possibly_mutable : bool array @@ -50,16 +63,32 @@ let add_assign_def vars defs x y = add_var vars x; let idx = Var.idx x in match defs.(idx) with - Expr _ | Param -> + Expr _ | Param _ -> assert false | Phi s -> defs.(idx) <- Phi (VarSet.add y s) -let add_param_def vars defs x = + +let add_params_origin state f args = + let fx = Var.idx f in + let argsl = List.length args in + let a = + if Array.length state.(fx) < argsl + then + let a = Array.make argsl VarSet.empty in + Array.blit state.(fx) 0 a 0 (Array.length state.(fx)); + state.(fx) <- a; + a + else state.(fx) in + List.iteri (fun i ar -> a.(i) <- VarSet.add ar a.(i) ) args + +let add_param_def vars defs x extra = add_var vars x; let idx = Var.idx x in - assert (is_undefined defs.(idx) || defs.(idx) = Param); - defs.(idx) <- Param + match defs.(idx) with + | x when is_undefined x -> defs.(idx) <- Param extra + | Param x' when x' = extra -> () + | _ -> assert false (* x depends on y *) let add_dep deps x y = @@ -79,16 +108,18 @@ let cont_deps blocks vars deps defs (pc, args) = let block = AddrMap.find pc blocks in arg_deps vars deps defs block.params args -let expr_deps blocks vars deps defs x e = +let expr_deps blocks vars deps defs params x e = match e with - Const _ | Constant _ | Apply _ | Prim _ -> + | Const _ | Constant _ | Prim _ -> () - | Closure (l, cont) -> - List.iter (fun x -> add_param_def vars defs x) l; + | Apply (f,args,_) -> + add_params_origin params f args + | Closure (l, cont) -> + List.iteri (fun i v -> add_param_def vars defs v (Some (x,i))) l; cont_deps blocks vars deps defs cont - | Block (_, a) -> + | Block (_, a) -> Array.iter (fun y -> add_dep deps x y) a - | Field (y, _) -> + | Field (y, _) -> add_dep deps x y let program_deps (_, blocks, _) = @@ -96,21 +127,22 @@ let program_deps (_, blocks, _) = let vars = VarISet.empty () in let deps = Array.make nv VarSet.empty in let defs = Array.make nv undefined in + let params = Array.make nv [||] in AddrMap.iter (fun pc block -> List.iter (fun i -> match i with - Let (x, e) -> + | Let (x, e) -> add_var vars x; add_expr_def defs x e; - expr_deps blocks vars deps defs x e - | Set_field _ | Array_set _ | Offset_ref _ -> + expr_deps blocks vars deps defs params x e + | Set_field _ | Array_set _ | Offset_ref _ -> ()) block.body; Util.opt_iter (fun (x, cont) -> - add_param_def vars defs x; + add_param_def vars defs x None; cont_deps blocks vars deps defs cont) block.handler; match block.branch with @@ -127,14 +159,14 @@ let program_deps (_, blocks, _) = | Pushtrap (cont, _, _, _) -> cont_deps blocks vars deps defs cont) blocks; - (vars, deps, defs) + (vars, deps, defs,params) let var_set_lift f s = VarSet.fold (fun y s -> VarSet.union (f y) s) s VarSet.empty let propagate1 deps defs st x = match defs.(Var.idx x) with - Param -> + Param _ -> VarSet.singleton x | Phi s -> var_set_lift (fun y -> VarTbl.get st y) s @@ -151,7 +183,7 @@ let propagate1 deps defs st x = let t = a.(n) in add_dep deps x t; VarTbl.get st t - | Phi _ | Param | Expr _ -> + | Phi _ | Param _ | Expr _ -> VarSet.empty) (VarTbl.get st y) @@ -253,7 +285,7 @@ let approx_lift f s = VarSet.fold (fun y u -> a_max (f y) u) s Known let propagate2 ?(skip_param=false) defs known_origins possibly_mutable st x = match defs.(Var.idx x) with - Param -> skip_param + Param _ -> skip_param | Phi s -> VarSet.exists (fun y -> VarTbl.get st y) s | Expr e -> @@ -272,7 +304,7 @@ let propagate2 ?(skip_param=false) defs known_origins possibly_mutable st x = possibly_mutable.(Var.idx z) || VarTbl.get st a.(n) - | Phi _ | Param | Expr _ -> + | Phi _ | Param _| Expr _ -> true) (VarTbl.get known_origins y) @@ -291,33 +323,77 @@ let solver2 ?skip_param vars deps defs known_origins possibly_mutable = in Solver2.f () g (propagate2 ?skip_param defs known_origins possibly_mutable) -let get_approx {info_defs; info_known_origins;info_maybe_unknown} f top join x = - let s = VarTbl.get info_known_origins x in - if VarTbl.get info_maybe_unknown x then top else - match VarSet.cardinal s with - 0 -> top - | 1 -> f (VarSet.choose s) - | _ -> VarSet.fold (fun x u -> join (f x) u) s (f (VarSet.choose s)) +let get_approx {info_defs; info_known_origins;info_maybe_unknown;info_possibly_mutable;info_params} f top bottom join x = + let rec aux visited x = + let visited = VarSet.add x visited in + let s = VarTbl.get info_known_origins x in + if VarTbl.get info_maybe_unknown x then top,visited else + match VarSet.cardinal s with + | 0 -> bottom,visited + | 1 -> + begin + let x = VarSet.choose s in + match info_defs.(Var.idx x) with + | Param (Some (fct,i)) -> + let idx_f = Var.idx fct in + (* check if fct can escape *) + if info_possibly_mutable.(idx_f) + then top,visited + else + let a = info_params.(idx_f) in + if Array.length a > i + then + let s = a.(i) in + let s = VarSet.elements s in + let rec loop visited res = function + | [] -> res,visited + | x::xs -> + if VarSet.mem x visited + then loop visited res xs + else + let visited = VarSet.add x visited in + let r,visited = aux visited x in + let res = join r res in + loop visited res xs + in loop visited bottom s + else top,visited + | _ -> f x,visited + end + | _ -> VarSet.fold (fun x (u,visited) -> join (f x) u, visited) s (f (VarSet.choose s), visited) + in + fst(aux VarSet.empty x) + let the_def_of info x = match x with - | Pv x -> - get_approx info - (fun x -> match info.info_defs.(Var.idx x) with Expr e -> Some e | _ -> None) - None (fun u v -> None) x | Pc c -> Some (Constant c) + | Pv x -> + let v = get_approx info + (fun x -> match info.info_defs.(Var.idx x) with + | Expr e -> Val e + | _ -> Top) + Top Bottom (fun u v -> Top) x in + match v with + | Val v -> Some v + | _ -> None let the_int info x = match x with - | Pv x -> - get_approx info + | Pv x -> begin + let v = get_approx info (fun x -> match info.info_defs.(Var.idx x) with - | Expr (Const i) -> Some i - | Expr (Constant (Int i)) -> Some i - | _ -> None) - None - (fun u v -> match u, v with Some i, Some j when i = j -> u | _ -> None) - x + | Expr (Const i) -> Val i + | Expr (Constant (Int i)) -> Val i + | _ -> Top) + Top Bottom + (fun u v -> match u, v with + | Val i, Val j when i = j -> u + | Bottom, x | x, Bottom -> x + | _ -> Top) x in + match v with + | Val v -> Some v + | _ -> None + end | Pc (Int i) -> Some i | _ -> None @@ -333,7 +409,7 @@ let direct_approx info x = Some a.(n) | _ -> None) - None + None None (fun u v -> match u, v with Some n, Some m when Var.compare n m = 0 -> u @@ -364,7 +440,7 @@ let build_subst info vars = let f ?skip_param ((pc, blocks, free_pc) as p) = let t = Util.Timer.make () in let t1 = Util.Timer.make () in - let (vars, deps, defs) = program_deps p in + let (vars, deps, defs,params) = program_deps p in if times () then Format.eprintf " flow analysis 1: %a@." Util.Timer.print t1; let t2 = Util.Timer.make () in let known_origins = solver1 vars deps defs in @@ -391,6 +467,7 @@ let f ?skip_param ((pc, blocks, free_pc) as p) = let t5 = Util.Timer.make () in let info = { info_defs = defs; + info_params = params; info_known_origins = known_origins; info_maybe_unknown = maybe_unknown; info_possibly_mutable = possibly_mutable; diff --git a/compiler/flow.mli b/compiler/flow.mli index 0437386263..ae91e651ba 100644 --- a/compiler/flow.mli +++ b/compiler/flow.mli @@ -37,17 +37,25 @@ val get_label : t -> Code.Var.t option *) -type def = Phi of Code.VarSet.t | Expr of Code.expr | Param +type def = Phi of Code.VarSet.t | Expr of Code.expr | Param of (Code.Var.t * int) option + +type 'a v = + | Bottom + | Val of 'a + | Top + +val string_of_approx : ('a -> string ) -> 'a v -> string type info = { info_defs:def array; + info_params: Code.VarSet.t array array; info_known_origins : Code.VarSet.t Code.VarTbl.t; info_maybe_unknown : bool Code.VarTbl.t; info_possibly_mutable : bool array; } val get_approx : info -> (Code.VarSet.elt -> 'b) -> - 'b -> ('b -> 'b -> 'b) -> Code.VarTbl.key -> 'b + 'b -> 'b -> ('b -> 'b -> 'b) -> Code.VarTbl.key -> 'b val the_def_of : info -> Code.prim_arg -> Code.expr option diff --git a/compiler/specialize.ml b/compiler/specialize.ml index a23dd17b67..f43561a80a 100644 --- a/compiler/specialize.ml +++ b/compiler/specialize.ml @@ -24,17 +24,24 @@ open Flow let function_cardinality info x = get_approx info (fun x -> - match info.info_defs.(Var.idx x) with - Expr (Closure (l, _)) -> Some (List.length l) - | _ -> None) - None - (fun u v -> match u, v with Some n, Some m when n = m -> u | _ -> None) + match info.info_defs.(Var.idx x) with + | Expr (Closure (l, _)) -> + Val (List.length l) + | _ -> Top) + Top Bottom + (fun u v -> match u, v with + | Val n, Val m when n = m -> u + | Bottom, x | x, Bottom -> x + | x -> Top) x let specialize_instr info i = match i with - | Let (x, Apply (f, l, _)) when Option.Optim.optcall () -> - Let (x, Apply (f, l, function_cardinality info f)) + | Let (x, Apply (f, l, None)) when Option.Optim.optcall () -> + let nopt = match function_cardinality info f with + | Val n -> Some n + | _ -> None in + Let (x, Apply (f, l, nopt)) | _ -> i