Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

COMPILER: improve approximation #56

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion compiler/eval.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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])) ->
Expand All @@ -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 ->
Expand Down
159 changes: 118 additions & 41 deletions compiler/flow.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 =
Expand All @@ -79,38 +108,41 @@ 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, _) =
let nv = Var.count () in
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
Expand All @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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 ->
Expand All @@ -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)

Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
12 changes: 10 additions & 2 deletions compiler/flow.mli
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
21 changes: 14 additions & 7 deletions compiler/specialize.ml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down