@ -660,6 +660,9 @@ module Func = struct
let find name functions =
Function . Map . find ( Function . counterfeit name ) functions
let lookup cfg lbl =
Iter . find_exn ( IArray . to_iter cfg ) ~ f : ( fun k -> String . equal lbl k . lbl )
let mk ~ name ~ formals ~ freturn ~ fthrow ~ entry ~ cfg ~ loc =
let locals =
let locals_cmnd locals cmnd =
@ -671,51 +674,45 @@ module Func = struct
IArray . fold ~ f : locals_block cfg ( locals_block entry Reg . Set . empty )
in
let func = { name ; formals ; freturn ; fthrow ; locals ; entry ; loc } in
let resolve_parent_and_jumps block =
block . parent <- func ;
let lookup cfg lbl : block =
Iter . find_exn ( IArray . to_iter cfg ) ~ f : ( fun k ->
String . equal lbl k . lbl )
in
let set_dst jmp = jmp . dst <- lookup cfg jmp . dst . lbl in
match block . term with
| Switch { tbl ; els ; _ } ->
IArray . iter tbl ~ f : ( fun ( _ , jmp ) -> set_dst jmp ) ;
set_dst els
| Iswitch { tbl ; _ } -> IArray . iter tbl ~ f : set_dst
| Call { return ; throw ; _ } | ICall { return ; throw ; _ } ->
set_dst return ;
Option . iter throw ~ f : set_dst
| Return _ | Throw _ | Unreachable -> ()
in
let elim_jumps_to_jumps block =
let rec find_dst retreating jmp =
match jmp . dst . term with
| Switch { tbl ; els ; _ }
when IArray . is_empty tbl && IArray . is_empty jmp . dst . cmnd ->
find_dst ( retreating | | els . retreating ) els
| _ -> jmp
in
let set_dst jmp =
let tgt = find_dst jmp . retreating jmp in
if tgt != jmp then (
let rec resolve_parent_and_jumps ancestors src =
src . parent <- func ;
let ancestors = Block_label . Set . add src ancestors in
let jump jmp =
let dst = lookup cfg jmp . dst . lbl in
if Block_label . Set . mem dst ancestors then (
jmp . dst <- dst ;
jmp . retreating <- true ;
jmp )
else
match resolve_parent_and_jumps ancestors dst with
| None ->
jmp . dst <- dst ;
jmp
| Some tgt ->
jmp . dst <- tgt . dst ;
jmp . retreating <- tgt . retreating )
jmp . retreating <- tgt . retreating ;
tgt
in
match block . term with
let jump' jmp = ignore ( jump jmp ) in
match src . term with
| Switch { tbl ; els ; _ } ->
IArray . iter tbl ~ f : ( fun ( _ , jmp ) -> set_dst jmp ) ;
set_dst els
| Iswitch { tbl ; _ } -> IArray . iter tbl ~ f : set_dst
IArray . iter ~ f : ( fun ( _ , jmp ) -> jump' jmp ) tbl ;
let tgt = jump els in
if IArray . is_empty tbl && IArray . is_empty src . cmnd then Some tgt
else None
| Iswitch { tbl ; _ } ->
IArray . iter ~ f : jump' tbl ;
None
| Call { return ; throw ; _ } | ICall { return ; throw ; _ } ->
set_dst return ;
Option . iter throw ~ f : set_dst
| Return _ | Throw _ | Unreachable -> ()
jump' return ;
Option . iter ~ f : jump' throw ;
None
| Return _ | Throw _ | Unreachable -> None
in
let resolve_parent_and_jumps block =
ignore ( resolve_parent_and_jumps Block_label . Set . empty block )
in
resolve_parent_and_jumps entry ;
IArray . iter cfg ~ f : resolve_parent_and_jumps ;
elim_jumps_to_jumps entry ;
IArray . iter cfg ~ f : elim_jumps_to_jumps ;
func | > check invariant
end
@ -738,14 +735,12 @@ let set_derived_metadata functions =
in
let topsort roots =
let tips_to_roots = BlockQ . create () in
let rec visit ancestors func src =
let rec visit ancestors src =
if BlockQ . mem tips_to_roots src then ()
else
let ancestors = Block_label . Set . add src ancestors in
let jump jmp =
if Block_label . Set . mem jmp . dst ancestors then
jmp . retreating <- true
else visit ancestors func jmp . dst
if jmp . retreating then () else visit ancestors jmp . dst
in
( match src . term with
| Switch { tbl ; els ; _ } ->
@ -755,7 +750,7 @@ let set_derived_metadata functions =
| Call ( { callee ; return ; throw ; _ } as cal ) ->
if Block_label . Set . mem callee . entry ancestors then
cal . recursive <- true
else visit ancestors func callee. entry ;
else visit ancestors callee. entry ;
jump return ;
Option . iter ~ f : jump throw
| ICall ( { return ; throw ; _ } as call ) ->
@ -767,7 +762,7 @@ let set_derived_metadata functions =
BlockQ . enqueue_back_exn tips_to_roots src ()
in
FuncQ . iter roots ~ f : ( fun root ->
visit Block_label . Set . empty root root . entry ) ;
visit Block_label . Set . empty root . entry ) ;
tips_to_roots
in
let set_sort_indices tips_to_roots =