-
Notifications
You must be signed in to change notification settings - Fork 5
Acyclic CFA reduction #214
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
base: main
Are you sure you want to change the base?
Changes from all commits
5b3c440
eca74c2
f0366c8
5ecb87f
12154f3
8a6c59b
16f2b65
efdaaeb
6268b66
73a44b0
367c7f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,104 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| open Lang | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| open Lang.Common | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Assumes program is in SSA, acyclic and pure. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let construct_final_edge proc = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Termination condition for each edge. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let term : (IDSet.elt, Var.t) Hashtbl.t = Hashtbl.create 30 in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Procedure.fold_blocks_topo_fwd | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (fun final_edge id block -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let preds = Procedure.blocks_pred proc id |> Iter.to_list in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Compute reachability of this block. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let reachable = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Always reachable if no predecessors. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| if List.is_empty preds then Expr.BasilExpr.boolconst true | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Otherwise, reachability is ANY of the predecessors reachability. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr.BasilExpr.applyintrin ~op:`OR | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (preds | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> List.filter_map (fst %> Hashtbl.get term) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> List.map Expr.BasilExpr.rvar) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+10
to
+22
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally prefer pattern matching rather than explicit conditions. I've also inlined the
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Create ITE statements from phi nodes. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let ites : Program.stmt = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let al = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| block.phis | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> List.map (function | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | ({ lhs; rhs = hd :: tl } : Var.t Block.phi) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a subtlety here that the block ID in Regardless, pattern matching on |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| let ite = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| List.fold_left | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (fun acc (in_edge, var) -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr.BasilExpr.ifthenelse | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (Expr.BasilExpr.rvar @@ Hashtbl.find term in_edge) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (Expr.BasilExpr.rvar var) acc) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (Expr.BasilExpr.rvar @@ snd hd) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+31
to
+36
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Local open of BasilExpr can avoid some repetition
Suggested change
I also add a local variable because I like to keep things in the local open as small as possible. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| tl | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (lhs, ite) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> failwith "Encountered phi node with no rhs.") | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Stmt.Instr_Assign { attrib = Attrib.empty; al } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Add a fresh termination variable to assign the condition. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let termination_var = Procedure.fresh_var proc ~pure:true Types.Boolean in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Hashtbl.add term id termination_var; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Construct our termination condition by combining | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| initial reachability with any assumes along this edge. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let termination_cond = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Expr.BasilExpr.applyintrin ~op:`AND | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ([ reachable ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| @ (Block.stmts_iter block | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> Iter.filter_map (function | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | Stmt.Instr_Assume { body; branch = true } -> Some body | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> None) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> Iter.to_list)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+54
to
+58
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer to factor out this filter (and avoid the repetition in the later inverse filter) by using a partition. For example let guard_expressions, non_guard_stmts =
Block.stmts_iter block |> Iter.to_list
|> List.partition_map_either (function
| Stmt.Instr_Assume { body; branch = true } -> Left body
| stmt -> Right stmt)This will also simplify the final list concats in this function. |
||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let termination = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Stmt.Instr_Assign | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| attrib = Attrib.empty; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| al = [ (termination_var, termination_cond) ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Final edge is existing statements plus: | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. the ites for the new edge being merged in. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. the statements for the new edge body. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. an assignment to the termination variable. | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| final_edge | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| @ List.concat | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ ites ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Filter out the now unnecessary guards. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| block.stmts |> Vector.to_list | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> List.filter (fun s -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| not | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| match s with | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | Stmt.Instr_Assume { branch = true } -> true | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| | _ -> false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| [ termination ]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| List.empty proc | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| let reduce_procedure (proc : Program.proc) : Program.proc = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Constructed reduced edge to replace procedure blocks. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let final_edge = construct_final_edge proc in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| let out_proc = | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| proc |> Procedure.iter_blocks |> Iter.map fst | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| |> Iter.fold (fun acc id -> Procedure.remove_block acc id) proc | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let out_proc, id = Procedure.fresh_block out_proc ~stmts:final_edge () in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| (* Make this the entry and return block. *) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| let out_proc = Procedure.set_entry_block out_proc id in | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Procedure.PG.map_graph | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| (fun g -> | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| Procedure.G.add_edge g (Procedure.Vert.End id) Procedure.Vert.Return) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| out_proc | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+93
to
+104
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just shadow
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| prog entry @f1; | ||
|
|
||
| proc @f1(a:bv64) -> (c:bv64) | ||
| [ | ||
| block %a [ | ||
| var x:bv64 := a; | ||
| goto(%b, %c); | ||
| ]; | ||
| block %b [ | ||
| guard(bvuge(x,0:bv64)); | ||
| var x := bvadd(x:bv64,1:bv64); | ||
| goto(%exit); | ||
| ]; | ||
| block %c [ | ||
| guard(bvult(x,0:bv64)); | ||
| var x := bvsub(x:bv64,1:bv64); | ||
| goto(%exit); | ||
| ]; | ||
| block %exit [ | ||
| var c:bv64 := x; | ||
| return; | ||
| ]; | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| (load-il "./cfa_reduction.il") | ||
| (run-transforms "ssa") | ||
| (run-transforms "cfa-reduction") | ||
| (run-transforms "simplify") | ||
| (dump-il "./out.il") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| $ bincaml script ./cfa_reduction.sexp | ||
| (load-il ./cfa_reduction.il) | ||
| (run-transforms ssa) | ||
| (run-transforms cfa-reduction) | ||
| (run-transforms simplify) | ||
| (dump-il ./out.il) | ||
| $ cat ./out.il | ||
| proc @f1(a:bv64) -> (c:bv64) { } | ||
|
|
||
|
|
||
| [ | ||
| block %block [ | ||
| var v:bool := true; | ||
| var v_2:bool := booland(v:bool, boolnot(bvult(a:bv64, 0x0:bv64))); | ||
| var x_6:bv64 := if v_2:bool then bvadd(a:bv64, 0x1:bv64) else bvsub(a:bv64, | ||
| 0x1:bv64); | ||
| var c:bv64 := x_6:bv64; | ||
| return; | ||
| ] | ||
| ]; | ||
| prog entry @f1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
term is too generic, a longer name like "termination_condition" would be better.