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

implements deadcode-elimination pass optimization #857

Merged
merged 18 commits into from
Aug 30, 2018
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
added attribute for updated terms
gitoleg committed Aug 24, 2018

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 1b8806b7ebe9592c593d673958f9492ab981fc7e
7 changes: 7 additions & 0 deletions lib/bap/bap.mli
Original file line number Diff line number Diff line change
@@ -7240,6 +7240,13 @@ module Std : sig
?skip:[`phi | `def | `jmp] list -> (** defaults to [[]] *)
t -> f:(exp -> exp) -> t

(** [map_elt ?phi ?def ?jmp blk] applies specified functions to every
corresponded subterm of [blk]. *)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

applies provided functions to the terms of corresponding classes. 
All functions default to the identity function.
```

val map_elts :
?phi:(phi term -> phi term) ->
?def:(def term -> def term) ->
?jmp:(jmp term -> jmp term) -> blk term -> blk term

(** [substitute ?skip blk x y] substitutes each occurrence of
expression [x] with expression [y] in block [blk]. The
substitution is performed deeply. If [skip] parameter is
11 changes: 11 additions & 0 deletions lib/bap_types/bap_ir.ml
Original file line number Diff line number Diff line change
@@ -1165,6 +1165,17 @@ module Ir_blk = struct
}
}

let map_elts ?phi ?def ?jmp blk =
let map get ~f = match f with
| None -> get blk.self
| Some f -> Array.map (get blk.self) ~f in {
blk with self = {
phis = map phis ~f:phi;
defs = map defs ~f:def;
jmps = map jmps ~f:jmp
}
}

let substitute ?skip blk x y =
map_exp ?skip blk ~f:(Exp.substitute x y)

4 changes: 4 additions & 0 deletions lib/bap_types/bap_ir.mli
Original file line number Diff line number Diff line change
@@ -241,6 +241,10 @@ module Ir_blk : sig
val map_exp :
?skip:[`phi | `def | `jmp] list ->
t -> f:(exp -> exp) -> t
val map_elts :
?phi:(phi term -> phi term) ->
?def:(def term -> def term) ->
?jmp:(jmp term -> jmp term) -> blk term -> blk term
val substitute :
?skip:[`phi | `def | `jmp] list ->
t -> exp -> exp -> t
2 changes: 1 addition & 1 deletion oasis/dead-code-elimination
Original file line number Diff line number Diff line change
@@ -10,5 +10,5 @@ Library dead_code_elimination_plugin
FindlibName: bap-plugin-dead_code_elimination
CompiledObject: best
BuildDepends: bap
InternalModules: Dead_code_elimination_main, Dead_code_diff
InternalModules: Dead_code_elimination_main, Optimization_data
XMETAExtraLines: tags="pass,analysis,optimization"
92 changes: 0 additions & 92 deletions plugins/dead_code_elimination/dead_code_diff.ml

This file was deleted.

56 changes: 38 additions & 18 deletions plugins/dead_code_elimination/dead_code_elimination_main.ml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ open Regular.Std
open Format
include Self()

module Diff = Dead_code_diff
module O = Optimization_data

type level = int

@@ -64,8 +64,20 @@ let rec substitute vars exp =
end in
substituter#map_exp exp |> Exp.fold_consts

let equal_kinds j j' = compare_jmp_kind (Jmp.kind j) (Jmp.kind j') = 0

let substitute sub vars =
Term.map blk_t sub ~f:(Blk.map_exp ~skip:[`phi] ~f:(substitute vars))
let def d =
let rhs = substitute vars (Def.rhs d) in
if Exp.(Def.rhs d <> rhs) then
O.mark_updated (Def.with_rhs d rhs)
else d in
let jmp j =
let j' = Jmp.map_exp j ~f:(substitute vars) in
if Exp.(Jmp.cond j <> Jmp.cond j') || not (equal_kinds j j')
then O.mark_updated j'
else j in
Term.map blk_t sub ~f:(Blk.map_elts ~def ~jmp)

(* A simple constant propagation. Note, the input is required to be in SSA. *)
let propagate_consts can_touch sub =
@@ -101,13 +113,14 @@ let free_vars prog =
collect sub_t prog ~f:(fun sub -> sub_args sub ++ sub_free sub)

let process_sub free can_touch sub =
let rec loop s =
let rec loop dead s =
let s = propagate_consts can_touch s in
let dead = compute_dead can_touch free s in
if Set.is_empty dead then s
else loop (clean can_touch dead s) in
let sub' = loop (Sub.ssa sub) in
Diff.diff_of_sub sub sub'
let dead' = compute_dead can_touch free s in
let dead = Set.union dead dead' in
if Set.is_empty dead' then s, dead
else loop dead (clean can_touch dead' s) in
let sub', dead = loop Tid.Set.empty (Sub.ssa sub) in
O.create dead sub'

module Digest = Data.Cache.Digest

@@ -130,13 +143,13 @@ let run level proj =
Project.with_program proj @@
Term.map sub_t prog ~f:(fun sub ->
let digest = digest_of_sub sub level in
let diff = match Diff.Cache.load digest with
| Some diff -> diff
let data = match O.Cache.load digest with
| Some data -> data
| None ->
let diff = process_sub free can_touch sub in
Diff.Cache.save digest diff;
diff in
Diff.apply sub diff)
let data = process_sub free can_touch sub in
O.Cache.save digest data;
data in
O.apply sub data)

let () =
Config.manpage [
@@ -176,10 +189,17 @@ let () =
];
let level =
let doc =
"An integer that a level of optimization, i.e. what variables
are considered in analysis:
$(b,1) for virtual variables only, $(b,2) for virtual variables
and flags and $(b,3) for all physical and virtual." in
"Specifies the optimization level. The higher the value the more
aggressive (and less safe) optimizations are applied. On level
1, we optimize only the synthetic code that was generated by
the lifter. Since such code can't leave a scope of instruction
it is not affected by the imprecision of a control flow graph.
On level 2, we also move and optimize processor flags. This
removes a significant amount of code and simplifies the program
and is a fair compromise between safety and performance.
(Since flags are rarely used non-locally).
Finally, on level 3 we extend our analysis to all variables." in

Config.(param int ~default:2 ~doc "level") in

Config.when_ready (fun {Config.get=(!)} ->
68 changes: 68 additions & 0 deletions plugins/dead_code_elimination/optimization_data.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
open Core_kernel
open Bap.Std
open Regular.Std

type jmp_update = {
cond : exp;
kind : jmp_kind;
}

type update = Rhs of exp | Jmp of jmp_update

type t = {
deads : Tid.Set.t;
updates : update Tid.Map.t;
}

let updated_term = Value.Tag.register (module Unit)
~name:"updated-term"
~uuid:"d21d76fa-12dd-470f-902e-f0e890e382d3"

let mark_updated t = Term.set_attr t updated_term ()
let is_updated t = Option.is_some (Term.get_attr t updated_term)

let drop_index = (object
inherit Exp.mapper
method! map_sym var = Var.base var
end)#map_exp

let updates_of_sub sub =
let fold t cls init ~f = Seq.fold (Term.enum cls t) ~init ~f in
let update_rhs updates d =
let rhs = drop_index (Def.rhs d) in
Map.add updates (Term.tid d) (Rhs rhs) in
let update_jmp updates j =
let j = Jmp.map_exp ~f:drop_index j in
let data = Jmp {cond = Jmp.cond j; kind = Jmp.kind j} in
Map.add updates (Term.tid j) data in
let add_if add updates t =
if is_updated t then add updates t else updates in
fold sub blk_t Tid.Map.empty ~f:(fun updates b ->
fold b def_t updates ~f:(add_if update_rhs) |>
fold b jmp_t ~f:(add_if update_jmp))

let create ~deads sub = {deads; updates = updates_of_sub sub}

let apply sub {deads; updates} =
let apply_to_def d =
if Set.mem deads (Term.tid d) then None
else
match Map.find updates (Term.tid d) with
| None -> Some d
| Some (Rhs e) -> Some (Def.with_rhs d e)
| _ -> assert false in
let apply_to_jmp j =
match Map.find updates (Term.tid j) with
| None -> j
| Some (Jmp {cond; kind}) ->
let j = Jmp.with_cond j cond in
Jmp.with_kind j kind
| _ -> assert false in
Term.map blk_t sub ~f:(fun b ->
Term.filter_map def_t b ~f:apply_to_def |>
Term.map jmp_t ~f:apply_to_jmp)

include Data.Make(struct
type nonrec t = t
let version = "0.1"
end)
Original file line number Diff line number Diff line change
@@ -4,7 +4,9 @@ open Regular.Std

type t

val diff_of_sub : sub term -> sub term -> t
val mark_updated : 'a term -> 'a term

val create : deads:Tid.Set.t -> sub term -> t

val apply : sub term -> t -> sub term