|
@@ -523,6 +523,7 @@ module Ssa = struct
|
|
mutable var_conds : (condition list) IntMap.t;
|
|
mutable var_conds : (condition list) IntMap.t;
|
|
mutable loop_stack : (join_node * join_node) list;
|
|
mutable loop_stack : (join_node * join_node) list;
|
|
mutable exception_stack : join_node list;
|
|
mutable exception_stack : join_node list;
|
|
|
|
+ mutable block_depth : int;
|
|
}
|
|
}
|
|
|
|
|
|
let s_cond = function
|
|
let s_cond = function
|
|
@@ -634,6 +635,7 @@ module Ssa = struct
|
|
v.v_extra <- old
|
|
v.v_extra <- old
|
|
) :: ctx.cleanup;
|
|
) :: ctx.cleanup;
|
|
ctx.cur_data.nd_var_map <- IntMap.add v.v_id v ctx.cur_data.nd_var_map;
|
|
ctx.cur_data.nd_var_map <- IntMap.add v.v_id v ctx.cur_data.nd_var_map;
|
|
|
|
+ v.v_meta <- ((Meta.Custom ":blockDepth",[EConst (Int (string_of_int ctx.block_depth)),p],p)) :: v.v_meta;
|
|
set_origin_var v v p
|
|
set_origin_var v v p
|
|
|
|
|
|
let assign_var ctx v e p =
|
|
let assign_var ctx v e p =
|
|
@@ -926,7 +928,10 @@ module Ssa = struct
|
|
let e = loop ctx e in
|
|
let e = loop ctx e in
|
|
e :: (loop2 el)
|
|
e :: (loop2 el)
|
|
in
|
|
in
|
|
- {e with eexpr = TBlock(loop2 el)}
|
|
|
|
|
|
+ ctx.block_depth <- ctx.block_depth + 1;
|
|
|
|
+ let el = loop2 el in
|
|
|
|
+ ctx.block_depth <- ctx.block_depth - 1;
|
|
|
|
+ {e with eexpr = TBlock(el)}
|
|
| _ ->
|
|
| _ ->
|
|
begin match ctx.exception_stack with
|
|
begin match ctx.exception_stack with
|
|
| join :: _ when can_throw e -> add_branch join ctx.cur_data e.epos
|
|
| join :: _ when can_throw e -> add_branch join ctx.cur_data e.epos
|
|
@@ -941,6 +946,7 @@ module Ssa = struct
|
|
loop_stack = [];
|
|
loop_stack = [];
|
|
exception_stack = [];
|
|
exception_stack = [];
|
|
cleanup = [];
|
|
cleanup = [];
|
|
|
|
+ block_depth = 0;
|
|
} in
|
|
} in
|
|
let e = loop ctx e in
|
|
let e = loop ctx e in
|
|
e,ctx
|
|
e,ctx
|
|
@@ -978,7 +984,16 @@ module ConstPropagation = struct
|
|
| _ ->
|
|
| _ ->
|
|
false
|
|
false
|
|
|
|
|
|
- let can_be_inlined com e = match e.eexpr with
|
|
|
|
|
|
+ let get_block_depth v = try
|
|
|
|
+ let i = match Meta.get (Meta.Custom ":blockDepth") v.v_meta with
|
|
|
|
+ | _,[EConst(Int s),_],_ -> int_of_string s
|
|
|
|
+ | _ -> raise Not_found
|
|
|
|
+ in
|
|
|
|
+ i
|
|
|
|
+ with Not_found ->
|
|
|
|
+ -1
|
|
|
|
+
|
|
|
|
+ let can_be_inlined com d e = match e.eexpr with
|
|
| TConst ct ->
|
|
| TConst ct ->
|
|
begin match ct with
|
|
begin match ct with
|
|
| TThis | TSuper -> false
|
|
| TThis | TSuper -> false
|
|
@@ -987,6 +1002,20 @@ module ConstPropagation = struct
|
|
| TNull when (match com.platform with Php | Cpp -> true | _ -> false) -> false
|
|
| TNull when (match com.platform with Php | Cpp -> true | _ -> false) -> false
|
|
| _ -> true
|
|
| _ -> true
|
|
end
|
|
end
|
|
|
|
+ | TLocal v ->
|
|
|
|
+ not (Meta.has Meta.CompilerGenerated v.v_meta) &&
|
|
|
|
+ begin try
|
|
|
|
+ let v' = Ssa.get_origin_var v in
|
|
|
|
+ begin match v'.v_extra with
|
|
|
|
+ | Some ([],_) -> get_block_depth v <= d
|
|
|
|
+ | _ -> false
|
|
|
|
+ end
|
|
|
|
+ with Not_found ->
|
|
|
|
+ false
|
|
|
|
+ end
|
|
|
|
+ (* issues with duplicate vars in switch cases *)
|
|
|
|
+(* | TEnumParameter _ ->
|
|
|
|
+ true *)
|
|
| _ ->
|
|
| _ ->
|
|
false
|
|
false
|
|
|
|
|
|
@@ -994,7 +1023,7 @@ module ConstPropagation = struct
|
|
| TCall({eexpr = TField(_,FEnum _)},el) -> (try List.nth el i with Failure _ -> raise Not_found)
|
|
| TCall({eexpr = TField(_,FEnum _)},el) -> (try List.nth el i with Failure _ -> raise Not_found)
|
|
| _ -> raise Not_found
|
|
| _ -> raise Not_found
|
|
|
|
|
|
- let rec local ssa v e =
|
|
|
|
|
|
+ let rec local ssa force v e =
|
|
begin try
|
|
begin try
|
|
if v.v_capture then raise Not_found;
|
|
if v.v_capture then raise Not_found;
|
|
if type_has_analyzer_option v.v_type flag_no_const_propagation then raise Not_found;
|
|
if type_has_analyzer_option v.v_type flag_no_const_propagation then raise Not_found;
|
|
@@ -1005,7 +1034,7 @@ module ConstPropagation = struct
|
|
let e = Ssa.get_var_value v in
|
|
let e = Ssa.get_var_value v in
|
|
let old = v.v_extra in
|
|
let old = v.v_extra in
|
|
v.v_extra <- None;
|
|
v.v_extra <- None;
|
|
- let e = value ssa e in
|
|
|
|
|
|
+ let e = value ssa force e in
|
|
v.v_extra <- old;
|
|
v.v_extra <- old;
|
|
Ssa.set_var_value v e;
|
|
Ssa.set_var_value v e;
|
|
e
|
|
e
|
|
@@ -1013,44 +1042,49 @@ module ConstPropagation = struct
|
|
e
|
|
e
|
|
end
|
|
end
|
|
|
|
|
|
- and value ssa e = match e.eexpr with
|
|
|
|
|
|
+ (* force must only be true if the value is not used in the output *)
|
|
|
|
+ and value ssa force e = match e.eexpr with
|
|
| TUnop((Increment | Decrement),_,_)
|
|
| TUnop((Increment | Decrement),_,_)
|
|
| TBinop(OpAssignOp _,_,_)
|
|
| TBinop(OpAssignOp _,_,_)
|
|
| TBinop(OpAssign,_,_) ->
|
|
| TBinop(OpAssign,_,_) ->
|
|
e
|
|
e
|
|
| TBinop(op,e1,e2) ->
|
|
| TBinop(op,e1,e2) ->
|
|
- let e1 = value ssa e1 in
|
|
|
|
- let e2 = value ssa e2 in
|
|
|
|
|
|
+ let e1 = value ssa force e1 in
|
|
|
|
+ let e2 = value ssa force e2 in
|
|
let e = {e with eexpr = TBinop(op,e1,e2)} in
|
|
let e = {e with eexpr = TBinop(op,e1,e2)} in
|
|
let e' = Optimizer.optimize_binop e op e1 e2 in
|
|
let e' = Optimizer.optimize_binop e op e1 e2 in
|
|
if e == e' then
|
|
if e == e' then
|
|
e
|
|
e
|
|
else
|
|
else
|
|
- value ssa e'
|
|
|
|
|
|
+ value ssa force e'
|
|
| TUnop(op,flag,e1) ->
|
|
| TUnop(op,flag,e1) ->
|
|
- let e1 = value ssa e1 in
|
|
|
|
|
|
+ let e1 = value ssa force e1 in
|
|
let e = {e with eexpr = TUnop(op,flag,e1)} in
|
|
let e = {e with eexpr = TUnop(op,flag,e1)} in
|
|
let e' = Optimizer.optimize_unop e op flag e1 in
|
|
let e' = Optimizer.optimize_unop e op flag e1 in
|
|
if e == e' then
|
|
if e == e' then
|
|
e
|
|
e
|
|
else
|
|
else
|
|
- value ssa e'
|
|
|
|
|
|
+ value ssa force e'
|
|
| TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}}),el) ->
|
|
| TCall (({eexpr = TLocal {v_name = "__ssa_phi__"}}),el) ->
|
|
- let el = List.map (value ssa) el in
|
|
|
|
|
|
+ let el = List.map (value ssa force) el in
|
|
begin match el with
|
|
begin match el with
|
|
| [] -> assert false
|
|
| [] -> assert false
|
|
| e1 :: el ->
|
|
| e1 :: el ->
|
|
if List.for_all (fun e2 -> expr_eq e1 e2) el then
|
|
if List.for_all (fun e2 -> expr_eq e1 e2) el then
|
|
- value ssa e1
|
|
|
|
|
|
+ value ssa force e1
|
|
else
|
|
else
|
|
{e with eexpr = TCall(e1,el)}
|
|
{e with eexpr = TCall(e1,el)}
|
|
end
|
|
end
|
|
| TParenthesis e1 | TMeta(_,e1) ->
|
|
| TParenthesis e1 | TMeta(_,e1) ->
|
|
- value ssa e1
|
|
|
|
|
|
+ value ssa force e1
|
|
| TLocal v ->
|
|
| TLocal v ->
|
|
- local ssa v e
|
|
|
|
|
|
+ let e' = local ssa force v e in
|
|
|
|
+ if force || can_be_inlined ssa.com (get_block_depth v) e' then
|
|
|
|
+ e'
|
|
|
|
+ else
|
|
|
|
+ e
|
|
| TEnumParameter(e1,ef,i) ->
|
|
| TEnumParameter(e1,ef,i) ->
|
|
- let ev = value ssa e1 in
|
|
|
|
|
|
+ let ev = value ssa true e1 in
|
|
begin try semi_awkward_enum_value ssa ev i
|
|
begin try semi_awkward_enum_value ssa ev i
|
|
with Not_found -> e end
|
|
with Not_found -> e end
|
|
| _ ->
|
|
| _ ->
|
|
@@ -1059,7 +1093,7 @@ module ConstPropagation = struct
|
|
(* TODO: the name is quite accurate *)
|
|
(* TODO: the name is quite accurate *)
|
|
let awkward_get_enum_index ssa e =
|
|
let awkward_get_enum_index ssa e =
|
|
let e = awkward_get_enum_index ssa.com e in
|
|
let e = awkward_get_enum_index ssa.com e in
|
|
- let ev = (value ssa e) in
|
|
|
|
|
|
+ let ev = (value ssa true e) in
|
|
match ev.eexpr with
|
|
match ev.eexpr with
|
|
| TField(_,FEnum(_,ef)) -> TInt (Int32.of_int ef.ef_index)
|
|
| TField(_,FEnum(_,ef)) -> TInt (Int32.of_int ef.ef_index)
|
|
| TCall({eexpr = TField(_,FEnum(_,ef))},_) -> TInt (Int32.of_int ef.ef_index)
|
|
| TCall({eexpr = TField(_,FEnum(_,ef))},_) -> TInt (Int32.of_int ef.ef_index)
|
|
@@ -1074,8 +1108,8 @@ module ConstPropagation = struct
|
|
had_function := true;
|
|
had_function := true;
|
|
{e with eexpr = TFunction {tf with tf_expr = loop tf.tf_expr}}
|
|
{e with eexpr = TFunction {tf with tf_expr = loop tf.tf_expr}}
|
|
| TLocal v ->
|
|
| TLocal v ->
|
|
- let e' = local ssa v e in
|
|
|
|
- if can_be_inlined ssa.com e' then
|
|
|
|
|
|
+ let e' = local ssa false v e in
|
|
|
|
+ if can_be_inlined ssa.com (get_block_depth v) e' then
|
|
e'
|
|
e'
|
|
else
|
|
else
|
|
e
|
|
e
|
|
@@ -1285,7 +1319,7 @@ module LocalDce = struct
|
|
let rec has_side_effect e =
|
|
let rec has_side_effect e =
|
|
let rec loop e =
|
|
let rec loop e =
|
|
match e.eexpr with
|
|
match e.eexpr with
|
|
- | TLocal v when Meta.has Meta.CompilerGenerated v.v_meta -> raise Exit
|
|
|
|
|
|
+ | TLocal v when Meta.has Meta.CompilerGenerated v.v_meta -> (try loop (Ssa.get_var_value v) with Not_found -> ())
|
|
| TBinop((OpAssign | OpAssignOp _),{eexpr = TLocal v},e2) when is_used v || Optimizer.has_side_effect e2 || is_ref_type v.v_type -> raise Exit
|
|
| TBinop((OpAssign | OpAssignOp _),{eexpr = TLocal v},e2) when is_used v || Optimizer.has_side_effect e2 || is_ref_type v.v_type -> raise Exit
|
|
| TVar(v,None) when is_used v -> raise Exit
|
|
| TVar(v,None) when is_used v -> raise Exit
|
|
| TVar(v,Some e1) when is_used v || Optimizer.has_side_effect e1 -> raise Exit
|
|
| TVar(v,Some e1) when is_used v || Optimizer.has_side_effect e1 -> raise Exit
|
|
@@ -1310,7 +1344,8 @@ module LocalDce = struct
|
|
| _ ->
|
|
| _ ->
|
|
Type.iter collect e
|
|
Type.iter collect e
|
|
in
|
|
in
|
|
- let rec loop need_val e = match e.eexpr with
|
|
|
|
|
|
+ let rec loop need_val e =
|
|
|
|
+ match e.eexpr with
|
|
| TLocal v ->
|
|
| TLocal v ->
|
|
use v;
|
|
use v;
|
|
e
|
|
e
|
|
@@ -1321,7 +1356,7 @@ module LocalDce = struct
|
|
else
|
|
else
|
|
{e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v},e2)}
|
|
{e with eexpr = TBinop(OpAssign,{e1 with eexpr = TLocal v},e2)}
|
|
| TVar(v,Some e1) when not (is_used v) ->
|
|
| TVar(v,Some e1) when not (is_used v) ->
|
|
- let e1 = loop true e1 in
|
|
|
|
|
|
+ let e1 = if has_side_effect e1 then loop true e1 else e1 in
|
|
e1
|
|
e1
|
|
| TWhile(e1,e2,flag) ->
|
|
| TWhile(e1,e2,flag) ->
|
|
collect e2;
|
|
collect e2;
|