@@ -27,6 +27,7 @@ type t = cfg
2727
2828let null = KB.Object. null Theory.Program. cls
2929let is_null x = KB.Object. is_null x
30+ let is_call jmp = Option. is_some (Jmp. alt jmp)
3031let is_empty = function
3132 | {entry; blks =[] } -> is_null entry
3233 | _ -> false
@@ -55,71 +56,103 @@ module BIR = struct
5556 Blk.Builder. result b :: blks |>
5657 List. rev
5758
58- let resolve jmp = Option. (Jmp. (dst jmp >> | resolve))
59+ let dst jmp =
60+ match Option. (Jmp. (dst jmp >> | resolve)) with
61+ | Some First tid -> Some tid
62+ | _ -> None
63+
64+ let dsts blk =
65+ List. filter_map blk.jmps ~f: dst
66+
5967
6068 let references blks =
6169 List. fold ~init: Tid.Map. empty ~f: (fun refs {jmps} ->
6270 List. fold jmps ~init: refs ~f: (fun refs jmp ->
63- match resolve jmp with
64- | Some (First tid ) when Set . mem blks tid ->
71+ match dst jmp with
72+ | Some tid when Map . mem blks tid ->
6573 Map. update refs tid ~f: (function
6674 | None -> 1
6775 | Some refs -> refs+ 1 )
6876 | _ -> refs))
6977
70- let names =
71- List. fold ~init: Tid.Set. empty ~f: (fun blks {name} ->
72- Set. add blks name)
78+ let graph = List. fold
79+ ~init: (Theory.Label. null,Tid.Map. empty)
80+ ~f: (fun (_ ,blks ) blk ->
81+ blk.name, Map. add_exn blks blk.name blk)
7382
7483 let single_dst = function
7584 | [] | _ :: _ :: _ -> None
76- | [x] -> match resolve x with
77- | Some First tid -> Some tid
85+ | [x] -> match dst x with
86+ | Some tid when not (is_call x) -> Some tid
7887 | _ -> None
7988
89+
8090 let is_sub {weak; keep} = keep && weak
8191
8292 let can_contract refs b1 b2 =
83- is_sub b1 && is_sub b2 && match single_dst b1.jmps with
93+ not (Tid. equal b1.name b2.name) &&
94+ b2.weak && match single_dst b1.jmps with
8495 | None -> false
8596 | Some dst ->
8697 Tid. equal dst b2.name &&
8798 match Map. find refs dst with
8899 | Some 1 -> true
89100 | _ -> false
90101
91- (* pre: can_contract b1 b2 /\
92- can_contract b2 b3 .. *)
93- let contract blks = match List. hd blks, List. last blks with
94- | Some first ,Some last -> {
95- first with
96- defs = List. (rev@@ concat_map blks ~f: (fun {defs} -> List. rev defs));
97- jmps = last.jmps;
98- }
99- | _ -> assert false
100-
101- let normalize blks =
102- let names = names blks in
103- let refs = references names blks in
104- List. sort blks ~compare: (fun b1 b2 ->
105- Tid. compare b1.name b2.name) |>
106- List. group ~break: (fun b1 b2 ->
107- not @@ can_contract refs b1 b2) |>
108- List. map ~f: contract
102+ (* pre: can_contract b1 b2 *)
103+ let join x y = {
104+ x with
105+ defs = y.defs @ x.defs;
106+ jmps = y.jmps
107+ }
108+
109+ let (//) graph node =
110+ Map. remove graph node.name
111+
112+ let has_name name blk = Tid. equal name blk.name
113+
114+ let removed exit parent dst =
115+ if has_name exit dst then parent.name else exit
116+
117+ let contract refs graph ~entry ~exit =
118+ let rec contract output graph exit node =
119+ match Option. (single_dst node.jmps >> = Map. find graph) with
120+ | Some dst when can_contract refs node dst ->
121+ let node = join node dst in
122+ contract output (graph// dst) (removed exit node dst) node
123+ | _ -> follow output graph exit node
124+ and follow output graph exit node = List. fold (dsts node)
125+ ~init: (node::output,graph// node,exit)
126+ ~f: (fun (output ,graph ,exit ) name ->
127+ match Map. find graph name with
128+ | None -> output,graph,exit
129+ | Some node -> contract output graph exit node) in
130+ contract [] graph exit (Map. find_exn graph entry)
131+
132+ let normalize entry blks =
133+ let exit,graph = graph blks in
134+ let refs = references graph blks in
135+ let blks,leftovers,exit = contract refs graph ~entry ~exit in
136+ assert (Map. is_empty leftovers);
137+ match blks with
138+ | blk ::_ as blks when has_name exit blk -> blks
139+ | blks ->
140+ List. find_exn blks ~f: (has_name exit) ::
141+ List. filter blks ~f: (Fn. non (has_name exit))
109142
110143 let has_subs = List. exists ~f: is_sub
111144
112- let normalize = function
145+ let normalize entry = function
113146 | [] | [_] as xs -> xs
114- | xs -> if has_subs xs then normalize xs else xs
147+ | xs -> if has_subs xs then normalize entry xs else xs
115148
116149 (* postconditions:
117150 - the first block is the entry block
118151 - the last block is the exit block
119152 *)
120153 let reify {entry; blks} =
121154 if is_null entry then [] else
122- normalize blks |>
155+ normalize entry blks |>
123156 List. fold ~init: (None ,[] ) ~f: (fun (s ,blks ) b ->
124157 match make_blk b with
125158 | [] -> assert false
@@ -168,8 +201,8 @@ let slot = graph
168201module IR = struct
169202 include Theory. Empty
170203 let ret = Knowledge. return
171- let blk ?(keep =true ) tid =
172- {name= tid; defs= [] ; jmps= [] ; keep; weak= false }
204+ let blk ?(keep =false ) ?( weak = false ) tid =
205+ {name= tid; defs= [] ; jmps= [] ; keep; weak}
173206
174207 let def = (fun x -> x.defs), (fun x d -> {x with defs = d})
175208 let jmp = (fun x -> x.jmps), (fun x d -> match x.jmps with
@@ -227,7 +260,7 @@ module IR = struct
227260 | `Relinked ,blks -> KB. return blks
228261 | `Relink dst , blks ->
229262 let + tid = fresh in
230- blks @ [blk label ++ goto ~tid dst]
263+ blks @ [blk ~weak label ++ goto ~tid dst]
231264 | `Unbound ,[] -> assert false
232265 | `Unbound ,_ -> assert false in
233266 {entry = label; blks}
@@ -241,7 +274,7 @@ module IR = struct
241274 blks = [{
242275 name= entry;
243276 keep= false ;
244- weak= false ;
277+ weak= true ;
245278 jmps= [] ;
246279 defs= [Def. reify ~tid v x]
247280 }]
@@ -268,6 +301,7 @@ module IR = struct
268301 if <body> is empty.
269302 *)
270303 let repeat cnd body =
304+ let keep = true in
271305 cnd >> = fun cnd ->
272306 body >> | reify >> = function
273307 | {blks =[] } -> (* empty denotation *)
@@ -277,7 +311,7 @@ module IR = struct
277311 entry = head;
278312 blks = [{
279313 name = head;
280- keep = true ;
314+ keep;
281315 weak = false ;
282316 defs = [] ;
283317 jmps = [goto ~cnd ~tid head]}]}
@@ -289,13 +323,14 @@ module IR = struct
289323 fresh >> = fun jmp3 ->
290324 data {
291325 entry = head;
292- blks = blk tail ++ goto ~tid: jmp1 ~cnd loop ::
293- blk head ++ goto ~tid: jmp2 tail ::
326+ blks = blk ~keep tail ++ goto ~tid: jmp1 ~cnd loop ::
327+ blk ~keep head ++ goto ~tid: jmp2 tail ::
294328 b ++ goto ~tid: jmp3 tail ::
295329 blks
296330 }
297331
298332 let branch cnd yes nay =
333+ let keep = true in
299334 fresh >> = fun head ->
300335 fresh >> = fun tail ->
301336 cnd >> = fun cnd ->
@@ -314,8 +349,8 @@ module IR = struct
314349 ret {
315350 entry = head;
316351 blks =
317- blk tail ::
318- blk head ++
352+ blk ~keep tail ::
353+ blk ~keep head ++
319354 jump ~tid: jmp1 lhs ++
320355 goto ~tid: jmp2 tail ::
321356 b ++ goto ~tid: jmp3 tail ::
@@ -328,8 +363,8 @@ module IR = struct
328363 ret {
329364 entry = head;
330365 blks =
331- blk tail ::
332- blk head ++
366+ blk ~keep tail ::
367+ blk ~keep head ++
333368 jump ~tid: jmp1 tail ++
334369 goto ~tid: jmp2 rhs ::
335370 b ++ goto ~tid: jmp3 tail ::
@@ -343,8 +378,8 @@ module IR = struct
343378 ret {
344379 entry = head;
345380 blks =
346- blk tail ::
347- blk head ++
381+ blk ~keep tail ::
382+ blk ~keep head ++
348383 jump ~tid: jmp1 lhs ++
349384 goto ~tid: jmp2 rhs ::
350385 yes ++ goto ~tid: jmp3 tail ::
@@ -357,8 +392,8 @@ module IR = struct
357392 ret {
358393 entry = head;
359394 blks = [
360- blk tail;
361- blk head ++ jump ~tid: jmp1 tail ++ goto ~tid: jmp2 tail
395+ blk ~keep tail;
396+ blk ~keep head ++ jump ~tid: jmp1 tail ++ goto ~tid: jmp2 tail
362397 ]
363398 }
364399
@@ -368,11 +403,9 @@ module IR = struct
368403 fresh >> = fun tid ->
369404 ctrl {
370405 entry;
371- blks = [blk ~keep: false entry ++ Jmp. reify ~tid ~dst: (Jmp. indirect dst) () ]
406+ blks = [blk entry ++ Jmp. reify ~tid ~dst: (Jmp. indirect dst) () ]
372407 }
373408
374- let is_call jmp = Option. is_some (Jmp. alt jmp)
375-
376409 let is_unconditional jmp = match Jmp. cond jmp with
377410 | Int w when Word. (w = b1) -> true
378411 | _ -> false
0 commit comments