Skip to content

Commit 7379f9e

Browse files
authored
Merge pull request #774 from TimOrtel/dev-method-rename-simple-impl
Detect renamed functions and global variables.
2 parents b768923 + 2a8bce5 commit 7379f9e

File tree

84 files changed

+1156
-371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1156
-371
lines changed

.github/workflows/locked.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ jobs:
6767
- name: Test regression cram
6868
run: opam exec -- dune runtest tests/regression
6969

70+
- name: Test incremental cram
71+
run: opam exec -- dune runtest tests/incremental
72+
7073
- name: Test unit
7174
run: opam exec -- dune runtest unittest
7275

.github/workflows/unlocked.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ jobs:
9494
- name: Test regression cram
9595
run: opam exec -- dune runtest tests/regression
9696

97+
- name: Test incremental cram
98+
run: opam exec -- dune runtest tests/incremental
99+
97100
- name: Test unit
98101
run: opam exec -- dune runtest unittest
99102

@@ -179,6 +182,9 @@ jobs:
179182
- name: Test regression cram
180183
run: opam exec -- dune runtest tests/regression
181184

185+
- name: Test incremental cram
186+
run: opam exec -- dune runtest tests/incremental
187+
182188
- name: Test unit
183189
run: opam exec -- dune runtest unittest
184190

src/framework/constraints.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ struct
924924
| Some {changes; _} -> changes
925925
| None -> empty_change_info ()
926926
in
927-
List.(Printf.printf "change_info = { unchanged = %d; changed = %d; added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (length c.added) (length c.removed));
927+
List.(Printf.printf "change_info = { unchanged = %d; changed = %d (with unchangedHeader = %d); added = %d; removed = %d }\n" (length c.unchanged) (length c.changed) (BatList.count_matching (fun c -> c.unchangedHeader) c.changed) (length c.added) (length c.removed));
928928

929929
let changed_funs = List.filter_map (function
930930
| {old = {def = Some (Fun f); _}; diff = None; _} ->

src/incremental/compareAST.ml

Lines changed: 235 additions & 149 deletions
Large diffs are not rendered by default.

src/incremental/compareCFG.ml

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,43 +3,49 @@
33
open MyCFG
44
open Queue
55
open GoblintCil
6-
open CilMaps
76
include CompareAST
87

9-
let eq_node (x, fun1) (y, fun2) =
10-
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
11-
(* don't allow pseudo return node to be equal to normal return node, could make function unchanged, but have different sallstmts *)
8+
(*Non propagating version of &&>>. Discards the new rename_mapping and alwas propagates the one in prev_result. However propagates the renames_on_success*)
9+
let (&&<>) (prev_result: bool * rename_mapping) f : bool * rename_mapping =
10+
let (prev_equal, prev_rm) = prev_result in
11+
let (a, b, c, _) = prev_rm in
12+
13+
if prev_equal then
14+
let (r, ((_, _, _, updated_renames_on_success) : rename_mapping)) = f ~rename_mapping:prev_rm in
15+
(r, (a, b, c, updated_renames_on_success))
16+
else false, prev_rm
17+
18+
let eq_node (x, fun1) (y, fun2) ~rename_mapping =
1219
let isPseudoReturn f sid =
1320
let pid = CfgTools.get_pseudo_return_id f in
1421
sid == pid in
1522
match x,y with
1623
| Statement s1, Statement s2 ->
1724
let p1 = isPseudoReturn fun1 s1.sid in
1825
let p2 = isPseudoReturn fun2 s2.sid in
19-
((p1 && p2) || not (p1 || p2)) && eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2) ~rename_mapping:empty_rename_mapping
20-
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
21-
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
22-
| _ -> false
26+
((p1 && p2) || not (p1 || p2), rename_mapping) &&>> eq_stmt ~cfg_comp:true (s1, fun1) (s2, fun2)
27+
| Function f1, Function f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
28+
| FunctionEntry f1, FunctionEntry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
29+
| _ -> false, rename_mapping
2330

2431
(* TODO: compare ASMs properly instead of simply always assuming that they are not the same *)
25-
let eq_edge x y =
26-
let empty_rename_mapping: rename_mapping = (StringMap.empty, VarinfoMap.empty) in
32+
let eq_edge x y ~rename_mapping =
2733
match x, y with
28-
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 ~rename_mapping:empty_rename_mapping && eq_exp rv1 rv2 ~rename_mapping:empty_rename_mapping
29-
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 ~rename_mapping:empty_rename_mapping && GobList.equal (eq_exp ~rename_mapping:empty_rename_mapping) ars1 ars2
34+
| Assign (lv1, rv1), Assign (lv2, rv2) -> eq_lval lv1 lv2 ~rename_mapping &&<> eq_exp rv1 rv2
35+
| Proc (None,f1,ars1), Proc (None,f2,ars2) -> eq_exp f1 f2 ~rename_mapping &&<> forward_list_equal eq_exp ars1 ars2
3036
| Proc (Some r1,f1,ars1), Proc (Some r2,f2,ars2) ->
31-
eq_lval r1 r2 ~rename_mapping:empty_rename_mapping && eq_exp f1 f2 ~rename_mapping:empty_rename_mapping && GobList.equal (eq_exp ~rename_mapping:empty_rename_mapping) ars1 ars2
32-
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping:empty_rename_mapping
33-
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar ~rename_mapping:empty_rename_mapping
34-
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 ~rename_mapping:empty_rename_mapping && eq_varinfo fd1.svar fd2.svar ~rename_mapping:empty_rename_mapping
35-
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 ~rename_mapping:empty_rename_mapping && b1 = b2
36-
| ASM _, ASM _ -> false
37-
| Skip, Skip -> true
38-
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2 ~rename_mapping:empty_rename_mapping
39-
| _ -> false
37+
eq_lval r1 r2 ~rename_mapping &&<> eq_exp f1 f2 &&<> forward_list_equal eq_exp ars1 ars2
38+
| Entry f1, Entry f2 -> eq_varinfo f1.svar f2.svar ~rename_mapping
39+
| Ret (None,fd1), Ret (None,fd2) -> eq_varinfo fd1.svar fd2.svar ~rename_mapping
40+
| Ret (Some r1,fd1), Ret (Some r2,fd2) -> eq_exp r1 r2 ~rename_mapping &&<> eq_varinfo fd1.svar fd2.svar
41+
| Test (p1,b1), Test (p2,b2) -> eq_exp p1 p2 ~rename_mapping &&> (b1 = b2)
42+
| ASM _, ASM _ -> false, rename_mapping
43+
| Skip, Skip -> true, rename_mapping
44+
| VDecl v1, VDecl v2 -> eq_varinfo v1 v2 ~rename_mapping
45+
| _ -> false, rename_mapping
4046

4147
(* The order of the edges in the list is relevant. Therefore compare them one to one without sorting first *)
42-
let eq_edge_list xs ys = GobList.equal eq_edge xs ys
48+
let eq_edge_list xs ys = forward_list_equal ~propF:(&&<>) eq_edge xs ys
4349

4450
let to_edge_list ls = List.map (fun (loc, edge) -> edge) ls
4551

@@ -52,37 +58,40 @@ type biDirectionNodeMap = {node1to2: node NH.t; node2to1: node NH.t}
5258
* in the succesors of fromNode2 in the new CFG. Matching node tuples are added to the waitingList to repeat the matching
5359
* process on their successors. If a node from the old CFG can not be matched, it is added to diff and no further
5460
* comparison is done for its successors. The two function entry nodes make up the tuple to start the comparison from. *)
55-
let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 fun2 =
61+
62+
let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 fun2 rename_mapping : biDirectionNodeMap * unit NH.t * rename_mapping =
5663
let diff = NH.create 113 in
5764
let same = {node1to2=NH.create 113; node2to1=NH.create 113} in
5865
let waitingList : (node * node) t = Queue.create () in
5966

60-
let rec compareNext () =
61-
if Queue.is_empty waitingList then ()
67+
let rec compareNext rename_mapping : rename_mapping =
68+
if Queue.is_empty waitingList then rename_mapping
6269
else
6370
let fromNode1, fromNode2 = Queue.take waitingList in
6471
let outList1 = CfgOld.next fromNode1 in
6572
let outList2 = CfgNew.next fromNode2 in
6673

6774
(* Find a matching edge and successor node for (edgeList1, toNode1) in the list of successors of fromNode2.
6875
* If successful, add the matching node tuple to same, else add toNode1 to the differing nodes. *)
69-
let findMatch (edgeList1, toNode1) =
70-
let rec aux remSuc = match remSuc with
71-
| [] -> NH.replace diff toNode1 ()
76+
let findMatch (edgeList1, toNode1) rename_mapping : rename_mapping =
77+
let rec aux remSuc rename_mapping : rename_mapping = match remSuc with
78+
| [] -> NH.replace diff toNode1 (); rename_mapping
7279
| (locEdgeList2, toNode2)::remSuc' ->
7380
let edgeList2 = to_edge_list locEdgeList2 in
74-
if eq_node (toNode1, fun1) (toNode2, fun2) && eq_edge_list edgeList1 edgeList2 then
81+
let (isEq, updatedRenameMapping) = (true, rename_mapping) &&>> eq_node (toNode1, fun1) (toNode2, fun2) &&>> eq_edge_list edgeList1 edgeList2 in
82+
if isEq then
7583
begin
7684
match NH.find_opt same.node1to2 toNode1 with
77-
| Some n2 -> if not (Node.equal n2 toNode2) then NH.replace diff toNode1 ()
78-
| None -> NH.replace same.node1to2 toNode1 toNode2; NH.replace same.node2to1 toNode2 toNode1; Queue.add (toNode1, toNode2) waitingList
85+
| Some n2 -> if not (Node.equal n2 toNode2) then NH.replace diff toNode1 (); updatedRenameMapping
86+
| None -> NH.replace same.node1to2 toNode1 toNode2; NH.replace same.node2to1 toNode2 toNode1; Queue.add (toNode1, toNode2) waitingList;
87+
updatedRenameMapping
7988
end
80-
else aux remSuc' in
81-
aux outList2 in
89+
else aux remSuc' updatedRenameMapping in
90+
aux outList2 rename_mapping in
8291
(* For a toNode1 from the list of successors of fromNode1, check whether it might have duplicate matches.
8392
* In that case declare toNode1 as differing node. Else, try finding a match in the list of successors
8493
* of fromNode2 in the new CFG using findMatch. *)
85-
let iterOuts (locEdgeList1, toNode1) =
94+
let iterOuts (locEdgeList1, toNode1) rename_mapping : rename_mapping =
8695
let edgeList1 = to_edge_list locEdgeList1 in
8796
(* Differentiate between a possibly duplicate Test(1,false) edge and a single occurence. In the first
8897
* case the edge is directly added to the diff set to avoid undetected ambiguities during the recursive
@@ -93,13 +102,18 @@ let compareCfgs (module CfgOld : CfgForward) (module CfgNew : CfgForward) fun1 f
93102
let posAmbigEdge edgeList = let findTestFalseEdge (ll,_) = testFalseEdge (snd (List.hd ll)) in
94103
let numDuplicates l = List.length (List.find_all findTestFalseEdge l) in
95104
testFalseEdge (List.hd edgeList) && (numDuplicates outList1 > 1 || numDuplicates outList2 > 1) in
96-
if posAmbigEdge edgeList1 then NH.replace diff toNode1 ()
97-
else findMatch (edgeList1, toNode1) in
98-
List.iter iterOuts outList1; compareNext () in
105+
if posAmbigEdge edgeList1 then (NH.replace diff toNode1 (); rename_mapping)
106+
else findMatch (edgeList1, toNode1) rename_mapping in
107+
let updatedRenameMapping = List.fold_left (fun rm e -> iterOuts e rm) rename_mapping outList1 in
108+
compareNext updatedRenameMapping
109+
in
99110

100111
let entryNode1, entryNode2 = (FunctionEntry fun1, FunctionEntry fun2) in
101-
NH.replace same.node1to2 entryNode1 entryNode2; NH.replace same.node2to1 entryNode2 entryNode1;
102-
Queue.push (entryNode1,entryNode2) waitingList; compareNext (); (same, diff)
112+
NH.replace same.node1to2 entryNode1 entryNode2;
113+
NH.replace same.node2to1 entryNode2 entryNode1;
114+
Queue.push (entryNode1,entryNode2) waitingList;
115+
let updatedRenameMapping = compareNext rename_mapping in
116+
same, diff, updatedRenameMapping
103117

104118
(* This is the second phase of the CFG comparison of functions. It removes the nodes from the matching node set 'same'
105119
* that have an incoming backedge in the new CFG that can be reached from a differing new node. This is important to
@@ -122,7 +136,8 @@ let reexamine f1 f2 (same : biDirectionNodeMap) (diffNodes1 : unit NH.t) (module
122136
repeat ();
123137
NH.to_seq same.node1to2, NH.to_seq_keys diffNodes1
124138

125-
let compareFun (module CfgOld : CfgForward) (module CfgNew : CfgBidir) fun1 fun2 =
126-
let same, diff = Timing.wrap "compare-phase1" (fun () -> compareCfgs (module CfgOld) (module CfgNew) fun1 fun2) () in
139+
140+
let compareFun (module CfgOld : CfgForward) (module CfgNew : CfgBidir) fun1 fun2 rename_mapping : (node * node) list * node list * rename_mapping =
141+
let same, diff, rename_mapping = Timing.wrap "compare-phase1" (fun () -> compareCfgs (module CfgOld) (module CfgNew) fun1 fun2 rename_mapping) () in
127142
let unchanged, diffNodes1 = Timing.wrap "compare-phase2" (fun () -> reexamine fun1 fun2 same diff (module CfgOld) (module CfgNew)) () in
128-
List.of_seq unchanged, List.of_seq diffNodes1
143+
List.of_seq unchanged, List.of_seq diffNodes1, rename_mapping

0 commit comments

Comments
 (0)