Skip to content

Commit 4db5147

Browse files
committed
Compiler: better never return detection
1 parent 88270a2 commit 4db5147

File tree

1 file changed

+68
-92
lines changed

1 file changed

+68
-92
lines changed

compiler/lib/generate.ml

Lines changed: 68 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,8 @@ let parallel_renaming params args continuation queue =
810810
px
811811
(instrs @ [ J.Variable_statement [ J.V y, Some (cx, J.N) ], J.N ])
812812
in
813-
st @ continuation queue)
813+
let never, code = continuation queue in
814+
never, st @ code)
814815
~init:continuation
815816
queue
816817

@@ -1359,7 +1360,9 @@ and translate_instrs ctx expr_queue loc instr =
13591360
and compile_block st queue (pc : Addr.t) frontier interm =
13601361
if (not (List.is_empty queue))
13611362
&& (Addr.Set.mem pc st.loops || not (Config.Flag.inline ()))
1362-
then flush_all queue (compile_block st [] pc frontier interm)
1363+
then
1364+
let never, code = compile_block st [] pc frontier interm in
1365+
never, flush_all queue code
13631366
else
13641367
match Addr.Set.mem pc st.loops with
13651368
| false -> compile_block_no_loop st queue pc frontier interm
@@ -1371,7 +1374,7 @@ and compile_block st queue (pc : Addr.t) frontier interm =
13711374
| [] -> J.Label.zero
13721375
in
13731376
st.loop_stack <- (pc, (lab, ref false)) :: st.loop_stack;
1374-
let body = compile_block_no_loop st queue pc frontier interm in
1377+
let never_body, body = compile_block_no_loop st queue pc frontier interm in
13751378
let body =
13761379
let rec remove_tailing_continue acc = function
13771380
| [] -> body
@@ -1386,13 +1389,13 @@ and compile_block st queue (pc : Addr.t) frontier interm =
13861389
, None
13871390
, None
13881391
, Js_simpl.block
1389-
(if Addr.Set.cardinal frontier > 0
1392+
(if never_body
13901393
then (
1391-
if debug () then Format.eprintf "@ break; }@]";
1392-
body @ [ J.Break_statement None, J.N ])
1393-
else (
13941394
if debug () then Format.eprintf "}@]";
1395-
body)) )
1395+
body)
1396+
else (
1397+
if debug () then Format.eprintf "@ break; }@]";
1398+
body @ [ J.Break_statement None, J.N ])) )
13961399
, source_location st.ctx pc )
13971400
in
13981401
let label =
@@ -1403,8 +1406,8 @@ and compile_block st queue (pc : Addr.t) frontier interm =
14031406
| [] -> assert false
14041407
in
14051408
match label with
1406-
| None -> [ for_loop ]
1407-
| Some label -> [ J.Labelled_statement (label, for_loop), J.N ])
1409+
| None -> never_body, [ for_loop ]
1410+
| Some label -> never_body, [ J.Labelled_statement (label, for_loop), J.N ])
14081411

14091412
and compile_block_no_loop st queue (pc : Addr.t) frontier interm =
14101413
if pc >= 0
@@ -1436,8 +1439,6 @@ and compile_block_no_loop st queue (pc : Addr.t) frontier interm =
14361439
let new_frontier = resolve_nodes interm grey in
14371440
let block = Addr.Map.find pc st.blocks in
14381441
let seq, queue = translate_instrs st.ctx queue (source_location st.ctx pc) block.body in
1439-
seq
1440-
@
14411442
match block.branch with
14421443
| Code.Pushtrap ((pc1, args1), x, (pc2, args2), pc3s) ->
14431444
(* FIX: document this *)
@@ -1469,17 +1470,18 @@ and compile_block_no_loop st queue (pc : Addr.t) frontier interm =
14691470
let try_catch_frontier = Addr.Set.union new_frontier handler_frontier_cont in
14701471
if debug () then Format.eprintf "@[<2>try {@,";
14711472
if Addr.Map.mem pc1 handler_interm then decr_preds st pc1;
1472-
let body =
1473-
prefix @ compile_branch st [] (pc1, args1) backs try_catch_frontier handler_interm
1473+
let never_body, body =
1474+
compile_branch st [] (pc1, args1) backs try_catch_frontier handler_interm
14741475
in
1476+
let body = prefix @ body in
14751477
if debug () then Format.eprintf "} catch {@,";
14761478
let x =
14771479
let block2 = Addr.Map.find pc2 st.blocks in
14781480
let m = Subst.build_mapping args2 block2.params in
14791481
try Var.Map.find x m with Not_found -> x
14801482
in
14811483
if Addr.Map.mem pc2 handler_interm then decr_preds st pc2;
1482-
let handler =
1484+
let never_handler, handler =
14831485
compile_branch st [] (pc2, args2) backs try_catch_frontier handler_interm
14841486
in
14851487
if debug () then Format.eprintf "}@]@ ";
@@ -1509,12 +1511,12 @@ and compile_block_no_loop st queue (pc : Addr.t) frontier interm =
15091511
None
15101512
with Escape -> Some (Var.fork x))
15111513
in
1512-
let after =
1514+
let never_after, after =
15131515
match Addr.Set.choose handler_frontier_cont with
1514-
| exception Not_found -> []
1516+
| exception Not_found -> false, []
15151517
| pc ->
15161518
if Addr.Set.mem pc frontier
1517-
then []
1519+
then false, []
15181520
else compile_block st [] pc frontier interm
15191521
in
15201522
let wrap_exn x =
@@ -1540,27 +1542,31 @@ and compile_block_no_loop st queue (pc : Addr.t) frontier interm =
15401542
:: handler
15411543
| false, None -> handler
15421544
in
1543-
flush_all
1544-
queue
1545-
(( J.Try_statement (body, Some (J.V handler_var, handler), None)
1546-
, source_location st.ctx pc )
1547-
:: after)
1548-
| _ -> (
1545+
( (never_body && never_handler) || never_after
1546+
, seq
1547+
@ flush_all
1548+
queue
1549+
(( J.Try_statement (body, Some (J.V handler_var, handler), None)
1550+
, source_location st.ctx pc )
1551+
:: after) )
1552+
| _ ->
15491553
let prefix, frontier_cont, new_interm = colapse_frontier st new_frontier interm in
15501554
assert (Addr.Set.cardinal frontier_cont <= 1);
15511555
List.iter succs ~f:(fun (pc, _) ->
15521556
if Addr.Map.mem pc new_interm then decr_preds st pc);
15531557
(* Beware evaluation order! *)
1554-
let cond =
1555-
compile_conditional st queue pc block.branch backs frontier_cont new_interm succs
1558+
let never_cond, cond =
1559+
compile_conditional st queue pc block.branch backs frontier_cont new_interm
15561560
in
1557-
prefix
1558-
@ cond
1559-
@
1560-
match Addr.Set.choose frontier_cont with
1561-
| exception Not_found -> []
1562-
| pc ->
1563-
if Addr.Set.mem pc frontier then [] else compile_block st [] pc frontier interm)
1561+
let never_after, after =
1562+
match Addr.Set.choose frontier_cont with
1563+
| exception Not_found -> false, []
1564+
| pc ->
1565+
if Addr.Set.mem pc frontier
1566+
then false, []
1567+
else compile_block st [] pc frontier interm
1568+
in
1569+
never_cond || never_after, seq @ prefix @ cond @ after
15641570

15651571
and colapse_frontier st new_frontier interm =
15661572
if Addr.Set.cardinal new_frontier > 1
@@ -1606,21 +1612,12 @@ and colapse_frontier st new_frontier interm =
16061612
Addr.Map.add pc (idx, (x, i, default = i)) interm) ))
16071613
else [], new_frontier, interm
16081614

1609-
and compile_decision_tree st _queue backs frontier interm succs loc cx dtree =
1615+
and compile_decision_tree st backs frontier interm loc cx dtree =
16101616
(* Some changes here may require corresponding changes
16111617
in function [DTree.fold_cont] above. *)
1612-
let rec loop cx = function
1618+
let rec loop cx : _ -> bool * _ = function
16131619
| DTree.Empty -> assert false
1614-
| DTree.Branch ((pc, _) as cont) ->
1615-
(* Block of code that never continues (either returns, throws an exception
1616-
or loops back) *)
1617-
(* If not found in successors, this is a backward edge *)
1618-
let never =
1619-
let d = try List.assoc pc succs with Not_found -> Addr.Set.empty in
1620-
(not (Addr.Set.mem pc frontier || Addr.Map.mem pc interm))
1621-
&& Addr.Set.is_empty d
1622-
in
1623-
never, compile_branch st [] cont backs frontier interm
1620+
| DTree.Branch cont -> compile_branch st [] cont backs frontier interm
16241621
| DTree.If (cond, cont1, cont2) ->
16251622
let never1, iftrue = loop cx cont1 in
16261623
let never2, iffalse = loop cx cont2 in
@@ -1670,9 +1667,10 @@ and compile_decision_tree st _queue backs frontier interm succs loc cx dtree =
16701667
let v = J.V (Code.Var.fresh ()) in
16711668
J.EVar v, [ J.Variable_statement [ v, Some (cx, J.N) ], J.N ]
16721669
in
1673-
binds @ snd (loop cx dtree)
1670+
let never, code = loop cx dtree in
1671+
never, binds @ code
16741672

1675-
and compile_conditional st queue pc last backs frontier interm succs =
1673+
and compile_conditional st queue pc last backs frontier interm =
16761674
(if debug ()
16771675
then
16781676
match last with
@@ -1687,86 +1685,64 @@ and compile_conditional st queue pc last backs frontier interm succs =
16871685
match last with
16881686
| Return x ->
16891687
let (_px, cx), queue = access_queue queue x in
1690-
flush_all queue [ J.Return_statement (Some cx), loc ]
1688+
true, flush_all queue [ J.Return_statement (Some cx), loc ]
16911689
| Raise (x, k) ->
16921690
let (_px, cx), queue = access_queue queue x in
1693-
flush_all queue (throw_statement st.ctx cx k loc)
1691+
true, flush_all queue (throw_statement st.ctx cx k loc)
16941692
| Stop ->
16951693
let e_opt =
16961694
if st.ctx.Ctx.should_export then Some (s_var Constant.exports) else None
16971695
in
1698-
flush_all queue [ J.Return_statement e_opt, loc ]
1696+
true, flush_all queue [ J.Return_statement e_opt, loc ]
16991697
| Branch cont -> compile_branch st queue cont backs frontier interm
17001698
| Pushtrap _ -> assert false
1701-
| Poptrap cont -> flush_all queue (compile_branch st [] cont backs frontier interm)
1699+
| Poptrap cont ->
1700+
let never, code = compile_branch st [] cont backs frontier interm in
1701+
never, flush_all queue code
17021702
| Cond (x, c1, c2) ->
17031703
let (_px, cx), queue = access_queue queue x in
1704-
let b =
1705-
compile_decision_tree
1706-
st
1707-
queue
1708-
backs
1709-
frontier
1710-
interm
1711-
succs
1712-
loc
1713-
cx
1714-
(DTree.build_if c1 c2)
1704+
let never, b =
1705+
compile_decision_tree st backs frontier interm loc cx (DTree.build_if c1 c2)
17151706
in
1716-
flush_all queue b
1707+
never, flush_all queue b
17171708
| Switch (x, [||], a2) ->
17181709
let (_px, cx), queue = access_queue queue x in
1719-
let code =
1710+
let never, code =
17201711
compile_decision_tree
17211712
st
1722-
queue
17231713
backs
17241714
frontier
17251715
interm
1726-
succs
17271716
loc
17281717
(Mlvalue.Block.tag cx)
17291718
(DTree.build_switch a2)
17301719
in
1731-
flush_all queue code
1720+
never, flush_all queue code
17321721
| Switch (x, a1, [||]) ->
17331722
let (_px, cx), queue = access_queue queue x in
1734-
let code =
1735-
compile_decision_tree
1736-
st
1737-
queue
1738-
backs
1739-
frontier
1740-
interm
1741-
succs
1742-
loc
1743-
cx
1744-
(DTree.build_switch a1)
1723+
let never, code =
1724+
compile_decision_tree st backs frontier interm loc cx (DTree.build_switch a1)
17451725
in
1746-
flush_all queue code
1726+
never, flush_all queue code
17471727
| Switch (x, a1, a2) ->
17481728
(* The variable x is accessed several times, so we can directly
17491729
refer to it *)
1750-
let b1 =
1730+
let never1, b1 =
17511731
compile_decision_tree
17521732
st
1753-
queue
17541733
backs
17551734
frontier
17561735
interm
1757-
succs
17581736
loc
17591737
(var x)
17601738
(DTree.build_switch a1)
17611739
in
1762-
let b2 =
1740+
let never2, b2 =
17631741
compile_decision_tree
17641742
st
1765-
queue
17661743
backs
17671744
frontier
17681745
interm
1769-
succs
17701746
loc
17711747
(Mlvalue.Block.tag (var x))
17721748
(DTree.build_switch a2)
@@ -1776,11 +1752,11 @@ and compile_conditional st queue pc last backs frontier interm succs =
17761752
(Mlvalue.is_immediate (var x))
17771753
loc
17781754
(Js_simpl.block b1)
1779-
false
1755+
never1
17801756
(Js_simpl.block b2)
1781-
false
1757+
never2
17821758
in
1783-
flush_all queue code
1759+
never1 && never2, flush_all queue code
17841760
in
17851761
(if debug ()
17861762
then
@@ -1796,7 +1772,7 @@ and compile_argument_passing ctx queue (pc, args) _backs continuation =
17961772
let block = Addr.Map.find pc ctx.Ctx.blocks in
17971773
parallel_renaming block.params args continuation queue
17981774

1799-
and compile_branch st queue ((pc, _) as cont) backs frontier interm =
1775+
and compile_branch st queue ((pc, _) as cont) backs frontier interm : bool * _ =
18001776
compile_argument_passing st.ctx queue cont backs (fun queue ->
18011777
if Addr.Set.mem pc backs
18021778
then (
@@ -1816,11 +1792,11 @@ and compile_branch st queue ((pc, _) as cont) backs frontier interm =
18161792
if Option.is_none label
18171793
then Format.eprintf "continue;@ "
18181794
else Format.eprintf "continue (%d);@ " pc;
1819-
flush_all queue [ J.Continue_statement label, J.N ])
1795+
true, flush_all queue [ J.Continue_statement label, J.N ])
18201796
else if Addr.Set.mem pc frontier || Addr.Map.mem pc interm
18211797
then (
18221798
if debug () then Format.eprintf "(br %d)@ " pc;
1823-
flush_all queue (compile_branch_selection pc interm))
1799+
false, flush_all queue (compile_branch_selection pc interm))
18241800
else compile_block st queue pc frontier interm)
18251801

18261802
and compile_branch_selection pc interm =
@@ -1838,7 +1814,7 @@ and compile_closure ctx (pc, args) =
18381814
let current_blocks = st.visited_blocks in
18391815
st.visited_blocks <- Addr.Set.empty;
18401816
if debug () then Format.eprintf "@[<hov 2>closure{@,";
1841-
let res =
1817+
let _never, res =
18421818
compile_branch st [] (pc, args) Addr.Set.empty Addr.Set.empty Addr.Map.empty
18431819
in
18441820
if Addr.Set.cardinal st.visited_blocks <> Addr.Set.cardinal current_blocks

0 commit comments

Comments
 (0)