33open MyCFG
44open Queue
55open GoblintCil
6- open CilMaps
76include 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 ~prop F:( &&<> ) eq_edge xs ys
4349
4450let 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