-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
The main idea is to provide an inverse to inline when proving an equiv. Currently, it supports basic procedure unification that requires manual selection of the program slice to unify with, as well as, requiring near exact matches on program structure. An optional return value can be supplied for situations where the return expression is just a program variable and needs to be renamed/deconstructed. There is also support for statement outlining although, this is more of a transitivity * with program slicing so may require change. Syntax and variants: - Procedure outlining: outline {m} [s - e] lv? <@ M.foo - Statement outlining: outline {m} [s - e] { s1; s2; ... } with - m: 1 or 2 - s,e: code position - M.foo: path to procedure - lv: a left-value when `s = e`, one can use `[s]` instead of `[s-s]` For example usage see: tests/outline.ec
- Loading branch information
1 parent
1733c19
commit 12af606
Showing
11 changed files
with
632 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
open EcAst | ||
open EcTypes | ||
open EcModules | ||
open EcSymbols | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
type u_error = | ||
| UE_InvalidRetInstr | ||
| UE_UnexpectedReturn | ||
| UE_ExprNotInLockstep of expr * expr | ||
| UE_InstrNotInLockstep of instr * instr | ||
| UE_DifferentProgramLengths of stmt * stmt | ||
|
||
exception UnificationError of u_error | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
type u_value = | ||
| Empty | ||
| Fixed of expr | ||
|
||
type umap = u_value Msym.t | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
let rec unify_exprs umap e1 e2 = | ||
match e1.e_node, e2.e_node with | ||
| Eint _, Eint _ -> umap | ||
| Elocal _, Elocal _ -> umap | ||
| Evar pv, e2n -> | ||
let var = symbol_of_pv pv in | ||
|
||
(* Only update a value if it hasn't been fixed previously *) | ||
let update value = | ||
match value with | ||
| None -> | ||
begin | ||
match e2n with | ||
| Evar _ -> None | ||
| _ -> raise (UnificationError (UE_ExprNotInLockstep (e1, e2))) | ||
end | ||
| Some Empty -> Some (Fixed e2) | ||
| _ -> value | ||
in | ||
|
||
Msym.change update var umap | ||
| Eop _, Eop _ -> umap | ||
| Eapp (f1, a1), Eapp (f2, a2) -> | ||
let umap = unify_exprs umap f1 f2 in | ||
List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine a1 a2) | ||
| Equant (_, _, e1), Equant (_, _, e2) -> | ||
unify_exprs umap e1 e2 | ||
| Elet (_, e1, u1), Elet (_, e2, u2) -> | ||
let umap = unify_exprs umap e1 e2 in | ||
unify_exprs umap u1 u2 | ||
| Etuple t1, Etuple t2 -> | ||
List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine t1 t2) | ||
| Eif (c1, t1, f1), Eif (c2, t2, f2) -> | ||
let umap = unify_exprs umap c1 c2 in | ||
let umap = unify_exprs umap t1 t2 in | ||
unify_exprs umap f1 f2 | ||
| Ematch (c1, p1, _), Ematch (c2, p2, _) -> | ||
let umap = unify_exprs umap c1 c2 in | ||
List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine p1 p2) | ||
| Eproj (e1, _), Eproj (e2, _) -> | ||
unify_exprs umap e1 e2 | ||
| _ -> raise (UnificationError (UE_ExprNotInLockstep (e1, e2))) | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
let rec unify_instrs umap i1 i2 = | ||
match i1.i_node, i2.i_node with | ||
| Sasgn(_, e1), Sasgn(_, e2) | ||
| Srnd(_, e1), Srnd(_, e2) -> | ||
unify_exprs umap e1 e2 | ||
| Scall(_, _, args1), Scall(_, _, args2) -> | ||
List.fold_left (fun umap (e1, e2) -> unify_exprs umap e1 e2) umap (List.combine args1 args2) | ||
| Sif(e1, st1, sf1), Sif(e2, st2, sf2) -> | ||
let umap = unify_exprs umap e1 e2 in | ||
let umap = unify_stmts umap st1 st2 in | ||
unify_stmts umap sf1 sf2 | ||
| Swhile(e1, s1), Swhile(e2, s2) -> | ||
let umap = unify_exprs umap e1 e2 in | ||
unify_stmts umap s1 s2 | ||
| Smatch(e1, bs1), Smatch(e2, bs2) -> | ||
let umap = unify_exprs umap e1 e2 in | ||
List.fold_left (fun umap (b1, b2) -> unify_stmts umap (snd b1) (snd b2)) umap (List.combine bs1 bs2) | ||
| Sassert e1, Sassert e2 -> | ||
unify_exprs umap e1 e2 | ||
| Sabstract _, Sabstract _ -> umap | ||
| _ -> raise (UnificationError (UE_InstrNotInLockstep (i1, i2))); | ||
|
||
and unify_stmts umap s1 s2 = | ||
let s1n, s2n = s1.s_node, s2.s_node in | ||
if List.length s1n <> List.length s2n then | ||
raise (UnificationError (UE_DifferentProgramLengths (s1, s2))); | ||
List.fold_left (fun umap (i1, i2) -> unify_instrs umap i1 i2) umap (List.combine s1n s2n) | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
(* Given a function definition attempt to unify its body with the statements `sb` | ||
and if a return statement is given, also unify it's expression. *) | ||
let unify_func umap fdef sb sr = | ||
(* Unify the body *) | ||
let umap = unify_stmts umap fdef.f_body sb in | ||
|
||
(* Unify the return stmt (if it exists) and retrieve its lv *) | ||
match sr with | ||
| Some i -> begin | ||
(* Check that there is a return expression to unify with *) | ||
if fdef.f_ret = None then | ||
raise (UnificationError UE_UnexpectedReturn); | ||
|
||
(* Only unify with assignment instructions *) | ||
match i.i_node with | ||
| Sasgn (lv, e) -> Some lv, unify_exprs umap (Option.get fdef.f_ret) e | ||
| _ -> raise (UnificationError UE_InvalidRetInstr) | ||
end | ||
| _ -> None, umap |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
open EcTypes | ||
open EcModules | ||
open EcSymbols | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
(* `Unification` of procedures *) | ||
(* | ||
Given: r <@ foo(a1: t1, a2: t2, ...); and s1; s2; ...; sr. | ||
Attempt to find values for a1, a2, ... such that, the body of `foo` with a1, a2, ... | ||
replaced will exactly match s1; s2; ..., and that `r <- res` match sr. | ||
Where `res` is the return expression of `foo`. | ||
Currently, this is done by traversing the respective ASTs and when a relevant | ||
program variable is encountered on the lhs, use the rhs expression. | ||
FIXME: This is incredibly basic and should be iterated on with a more advanced | ||
procedure unification algorithm. | ||
*) | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
type u_error = | ||
| UE_InvalidRetInstr | ||
| UE_UnexpectedReturn | ||
| UE_ExprNotInLockstep of expr * expr | ||
| UE_InstrNotInLockstep of instr * instr | ||
| UE_DifferentProgramLengths of stmt * stmt | ||
|
||
exception UnificationError of u_error | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
type u_value = | ||
| Empty | ||
| Fixed of expr | ||
|
||
type umap = u_value Msym.t | ||
|
||
(*---------------------------------------------------------------------------------------*) | ||
(* The following functions attempt to unify unknown program variables | ||
in the lhs with expressions from the rhs *) | ||
val unify_exprs : umap -> expr -> expr -> umap | ||
val unify_instrs : umap -> instr -> instr -> umap | ||
val unify_stmts : umap -> stmt -> stmt -> umap | ||
val unify_func : umap -> function_def -> stmt -> instr option -> lvalue option * umap |
Oops, something went wrong.