[preanalysis] kill copy-propagation code

Reviewed By: mbouaziz

Differential Revision: D5576344

fbshipit-source-id: 581da42
master
Sam Blackshear 8 years ago committed by Facebook Github Bot
parent 557faa4a46
commit 1157364a09

@ -95,7 +95,7 @@ let add_abstraction_instructions pdesc =
in
Procdesc.iter_nodes do_node pdesc
module BackwardCfg = ProcCfg.OneInstrPerNode (ProcCfg.Backward (ProcCfg.Exceptional))
module BackwardCfg = ProcCfg.Backward (ProcCfg.Exceptional)
module LivenessAnalysis = AbstractInterpreter.Make (BackwardCfg) (Liveness.TransferFunctions)
module VarDomain = Liveness.Domain
@ -115,7 +115,7 @@ module NullifyTransferFunctions = struct
type extras = LivenessAnalysis.invariant_map
let postprocess (reaching_defs, _ as astate) node {ProcData.extras} =
let node_id = (Procdesc.Node.get_id (CFG.underlying_node node), ProcCfg.Node_index) in
let node_id = Procdesc.Node.get_id (CFG.underlying_node node) in
match LivenessAnalysis.extract_state node_id extras with
(* note: because the analysis is backward, post and pre are reversed *)
| Some {AbstractInterpreter.post= live_before; pre= live_after}
@ -229,52 +229,6 @@ let add_nullify_instrs pdesc tenv liveness_inv_map =
let exit_node = ProcCfg.Exceptional.exit_node nullify_proc_cfg in
node_add_nullify_instructions exit_node (AddressTaken.Domain.elements address_taken_vars)
module ExceptionalOneInstrPerNodeCfg = ProcCfg.OneInstrPerNode (ProcCfg.Exceptional)
module CopyProp =
AbstractInterpreter.Make (ExceptionalOneInstrPerNodeCfg) (CopyPropagation.TransferFunctions)
let do_copy_propagation pdesc tenv =
let proc_cfg = ExceptionalOneInstrPerNodeCfg.from_pdesc pdesc in
let initial = CopyPropagation.Domain.empty in
let copy_prop_inv_map =
CopyProp.exec_cfg proc_cfg (ProcData.make_default pdesc tenv) ~initial ~debug:false
in
(* [var_map] represents a chain of variable. copies v_0 -> v_1 ... -> v_n. starting from some
ident v_j, we want to walk backward through the chain to find the lowest v_i that is also an
ident. *)
let id_sub var_map id =
(* [last_id] is the highest identifier in the chain that we've seen so far *)
let rec id_sub_inner var_map var last_id =
try
let var' = CopyPropagation.Domain.find var var_map in
let last_id' = match var' with Var.LogicalVar id -> id | _ -> last_id in
id_sub_inner var_map var' last_id'
with Not_found -> Exp.Var last_id
in
id_sub_inner var_map (Var.of_id id) id
in
(* perform copy-propagation on each instruction in [node] *)
let rev_transform_node_instrs node =
List.fold
~f:(fun (instrs, changed) (instr, id_opt) ->
match id_opt with
| Some id -> (
match CopyProp.extract_pre id copy_prop_inv_map with
| Some pre when not (CopyPropagation.Domain.is_empty pre)
-> let instr' = Sil.instr_sub_ids ~sub_id_binders:false (`Exp (id_sub pre)) instr in
(instr' :: instrs, changed || not (phys_equal instr' instr))
| _
-> (instr :: instrs, changed) )
| None
-> (instr :: instrs, changed))
~init:([], false) (ExceptionalOneInstrPerNodeCfg.instr_ids node)
in
List.iter
~f:(fun node ->
let instrs, changed = rev_transform_node_instrs node in
if changed then Procdesc.Node.replace_instrs node (List.rev instrs))
(Procdesc.get_nodes pdesc)
let do_liveness pdesc tenv =
let liveness_proc_cfg = BackwardCfg.from_pdesc pdesc in
let initial = Liveness.Domain.empty in
@ -282,7 +236,6 @@ let do_liveness pdesc tenv =
LivenessAnalysis.exec_cfg liveness_proc_cfg (ProcData.make_default pdesc tenv) ~initial
~debug:false
in
if Config.copy_propagation then do_copy_propagation pdesc tenv ;
add_nullify_instrs pdesc tenv liveness_inv_map ;
Procdesc.signal_did_preanalysis pdesc

@ -823,10 +823,6 @@ and continue =
~in_help:CLOpt.([(Analyze, manual_generic)])
"Continue the capture for the reactive analysis, increasing the changed files/procedures. (If a procedure was changed beforehand, keep the changed marking.)"
and copy_propagation =
CLOpt.mk_bool ~deprecated:["copy-propagation"] ~long:"copy-propagation"
"Perform copy-propagation on the IR"
and current_to_previous_script =
CLOpt.mk_string_opt ~long:"current-to-previous-script"
~in_help:CLOpt.([(Diff, manual_generic)])
@ -1930,8 +1926,6 @@ and continue_capture = !continue
and current_to_previous_script = !current_to_previous_script
and copy_propagation = !copy_propagation
and crashcontext = !crashcontext
and create_harness = !android_harness

@ -321,8 +321,6 @@ val compute_analytics : bool
val continue_capture : bool
val copy_propagation : bool
val crashcontext : bool
val create_harness : bool

@ -1,110 +0,0 @@
(*
* Copyright (c) 2016 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
module F = Format
module L = Logging
module Domain = struct
include Var.Map
type astate = Var.t Var.Map.t
(* return true if the key-value bindings in [rhs] are a subset of the key-value bindings in
[lhs] *)
let ( <= ) ~lhs ~rhs =
if phys_equal lhs rhs then true
else
Var.Map.for_all
(fun k v ->
try Var.equal v (Var.Map.find k lhs)
with Not_found -> false)
rhs
let join astate1 astate2 =
if phys_equal astate1 astate2 then astate1
else
let keep_if_same _ v1_opt v2_opt =
match (v1_opt, v2_opt) with
| Some v1, Some v2
-> if Var.equal v1 v2 then Some v1 else None
| _
-> None
in
Var.Map.merge keep_if_same astate1 astate2
let widen ~prev ~next ~num_iters:_ = join prev next
let pp fmt astate =
let pp_value = Var.pp in
Var.Map.pp ~pp_value fmt astate
let gen var1 var2 astate =
(* don't add tautological copies *)
if Var.equal var1 var2 then astate else Var.Map.add var1 var2 astate
let kill_copies_with_var var astate =
let do_kill lhs_var rhs_var astate_acc =
if Var.equal var lhs_var then astate_acc (* kill copies vith [var] on lhs *)
else if Var.equal var rhs_var then
(* delete [var] = [rhs_var] copy, but add [lhs_var] = M(rhs_var) copy*)
try Var.Map.add lhs_var (Var.Map.find rhs_var astate) astate_acc
with Not_found -> astate_acc
else (* copy is unaffected by killing [var]; keep it *)
Var.Map.add lhs_var rhs_var astate_acc
in
Var.Map.fold do_kill astate Var.Map.empty
(* kill the previous binding for [lhs_var], and add a new [lhs_var] -> [rhs_var] binding *)
let kill_then_gen lhs_var rhs_var astate =
let already_has_binding lhs_var rhs_var astate =
try Var.equal rhs_var (Var.Map.find lhs_var astate)
with Not_found -> false
in
if Var.equal lhs_var rhs_var || already_has_binding lhs_var rhs_var astate then astate
(* already have this binding; no need to kill or gen *)
else kill_copies_with_var lhs_var astate |> gen lhs_var rhs_var
end
module TransferFunctions (CFG : ProcCfg.S) = struct
module CFG = CFG
module Domain = Domain
type extras = ProcData.no_extras
let exec_instr astate _ _ = function
| Sil.Load (lhs_id, Exp.Lvar rhs_pvar, _, _) when not (Pvar.is_global rhs_pvar)
-> Domain.gen (Var.of_id lhs_id) (Var.of_pvar rhs_pvar) astate
| Sil.Store (Exp.Lvar lhs_pvar, _, Exp.Var rhs_id, _) when not (Pvar.is_global lhs_pvar)
-> Domain.kill_then_gen (Var.of_pvar lhs_pvar) (Var.of_id rhs_id) astate
| Sil.Store (Exp.Lvar lhs_pvar, _, _, _)
-> (* non-copy assignment; can only kill *)
Domain.kill_copies_with_var (Var.of_pvar lhs_pvar) astate
| Sil.Load _
(* lhs = *rhs where rhs isn't a pvar (or is a global). in any case, not a copy *)
(* note: since logical vars can't be reassigned, don't need to kill bindings for lhs id *)
| Sil.Store (Var _, _, _, _)
-> (* *lhs = rhs. not a copy, and not a write to lhs *)
astate
| Sil.Call (ret_id, _, actuals, _, _)
-> let kill_ret_id (id, _) = Domain.kill_copies_with_var (Var.of_id id) astate in
let kill_actuals_by_ref astate_acc = function
| Exp.Lvar pvar, {Typ.desc= Tptr _}
-> Domain.kill_copies_with_var (Var.of_pvar pvar) astate_acc
| _
-> astate_acc
in
let astate' = Option.value_map ~f:kill_ret_id ~default:astate ret_id in
if Config.curr_language_is Config.Java then astate'
(* Java doesn't have pass-by-reference *)
else List.fold ~f:kill_actuals_by_ref ~init:astate' actuals
| Sil.Store _ | Prune _ | Nullify _ | Abstract _ | Remove_temps _ | Declare_locals _
-> (* none of these can assign to program vars or logical vars *)
astate
end

@ -1,99 +0,0 @@
(*
* Copyright (c) 2015 - present Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*)
open! IStd
module F = Format
module TestInterpreter =
AnalyzerTester.Make (ProcCfg.Exceptional) (CopyPropagation.TransferFunctions)
let tests =
let open OUnit2 in
let open AnalyzerTester.StructuredSil in
let assert_empty = invariant "{ }" in
let test_list =
[ ("id_load_id_no_gen", [id_assign_id "b" "a"; (* means b = *a *)
assert_empty])
; ("id_set_id_no_gen", [id_set_id "b" "a"; (* means *b = a *)
assert_empty])
; ( "id_set_id_no_kill"
, [ id_assign_var "b" "a"
; invariant "{ b$0 -> &a }"
; id_set_id "b" "x"
; invariant "{ b$0 -> &a }" ] )
; ("id_assign_var_gen", [id_assign_var "b" "a"; invariant "{ b$0 -> &a }"])
; ( "var_assign_addrof_var_no_gen"
, [var_assign_addrof_var "b" "a"; (* means b = &a *)
assert_empty] )
; ("var_assign_id_gen", [var_assign_id "b" "a"; invariant "{ &b -> a$0 }"])
; ( "multi_command_gen"
, [ id_assign_var "b" "a"
; var_assign_id "c" "b"
; id_assign_var "d" "c"
; invariant "{ b$0 -> &a, d$0 -> &c, &c -> b$0 }" ] )
; ( "simple_kill"
, [id_assign_var "b" "a"; invariant "{ b$0 -> &a }"; var_assign_int "a" 1; assert_empty] )
; ( "kill_then_gen"
, [ id_assign_var "b" "a"
; invariant "{ b$0 -> &a }"
; var_assign_id "a" "c"
; invariant "{ &a -> c$0 }" ] )
; ( "same_copy"
, [ var_assign_id "b" "a"
; var_assign_id "c" "d"
; invariant "{ &b -> a$0, &c -> d$0 }"
; var_assign_id "c" "d"
; invariant "{ &b -> a$0, &c -> d$0 }" ] )
; ( "conservative_if"
, [ var_assign_id "b" "a"
; If
( unknown_exp
, [invariant "{ &b -> a$0 }"; var_assign_id "b" "c"; invariant "{ &b -> c$0 }"]
, [] )
; assert_empty ] )
; ( "if1"
, [ var_assign_id "b" "a"
; var_assign_id "c" "d"
; If
( unknown_exp
, [ invariant "{ &b -> a$0, &c -> d$0 }"
; var_assign_id "c" "e"
; invariant "{ &b -> a$0, &c -> e$0 }" ]
, [invariant "{ &b -> a$0, &c -> d$0 }"] )
; invariant "{ &b -> a$0 }" ] )
; ( "if2"
, [ If (unknown_exp, [var_assign_id "a" "b"], [var_assign_id "a" "b"])
; invariant "{ &a -> b$0 }" ] )
; ("if3", [If (unknown_exp, [var_assign_id "a" "b"], [var_assign_id "a" "c"]); assert_empty])
; ( "nested_if"
, [ var_assign_id "b" "a"
; var_assign_id "c" "b"
; If
( unknown_exp
, [ If
( var_of_str "unknown2"
, [ invariant "{ &b -> a$0, &c -> b$0 }"
; var_assign_id "b" "d"
; invariant "{ &b -> d$0, &c -> b$0 }" ]
, [] ) ]
, [] )
; invariant "{ &c -> b$0 }" ] )
; ( "loop_as_if"
, [var_assign_id "b" "a"; While (unknown_exp, [var_assign_id "b" "c"]); assert_empty] )
; ( "easy_loop_invariant"
, [ var_assign_id "b" "a"
; While (unknown_exp, [var_assign_id "c" "d"; invariant "{ &b -> a$0, &c -> d$0 }"])
; invariant "{ &b -> a$0 }" ] )
; ( "empty_loop"
, [ var_assign_id "b" "a"
; While (unknown_exp, [])
; var_assign_id "c" "b"
; invariant "{ &b -> a$0, &c -> b$0 }" ] ) ]
|> TestInterpreter.create_tests ProcData.empty_extras ~initial:CopyPropagation.Domain.empty
in
"copy_propagation_test_suite" >::: test_list

@ -19,7 +19,6 @@ let () =
; AccessTreeTests.tests
; AddressTakenTests.tests
; BoundedCallTreeTests.tests
; CopyPropagationTests.tests
; DifferentialTests.tests
; DifferentialFiltersTests.tests
; ProcCfgTests.tests

Loading…
Cancel
Save