@@ -1564,10 +1564,12 @@ end
1564
1564
1565
1565
is_nothrow (ir:: IRCode , ssa:: SSAValue ) = has_flag (ir[ssa], IR_FLAG_NOTHROW)
1566
1566
1567
- function reachable_blocks (cfg:: CFG , from_bb:: Int , to_bb:: Union{Nothing, Int} = nothing )
1567
+ function reachable_blocks (cfg:: CFG , from_bb:: Int , to_bb:: Int )
1568
1568
worklist = Int[from_bb]
1569
1569
visited = BitSet (from_bb)
1570
- if to_bb != = nothing
1570
+ if to_bb == from_bb
1571
+ return visited
1572
+ else
1571
1573
push! (visited, to_bb)
1572
1574
end
1573
1575
function visit! (bb:: Int )
@@ -1582,100 +1584,78 @@ function reachable_blocks(cfg::CFG, from_bb::Int, to_bb::Union{Nothing,Int} = no
1582
1584
return visited
1583
1585
end
1584
1586
1585
- function try_resolve_finalizer! (ir:: IRCode , idx :: Int , finalizer_idx:: Int , defuse:: SSADefUse ,
1587
+ function try_resolve_finalizer! (ir:: IRCode , alloc_idx :: Int , finalizer_idx:: Int , defuse:: SSADefUse ,
1586
1588
inlining:: InliningState , lazydomtree:: LazyDomtree ,
1587
1589
lazypostdomtree:: LazyPostDomtree , @nospecialize (info:: CallInfo ))
1588
1590
# For now, require that:
1589
1591
# 1. The allocation dominates the finalizer registration
1590
- # 2. The finalizer registration dominates all uses reachable from the
1591
- # finalizer registration.
1592
- # 3. The insertion block for the finalizer is the post-dominator of all
1593
- # uses and the finalizer registration block. The insertion block must
1594
- # be dominated by the finalizer registration block.
1595
- # 4. The path from the finalizer registration to the finalizer inlining
1592
+ # 2. The insertion block for the finalizer is the post-dominator of all
1593
+ # uses (including the finalizer registration).
1594
+ # 3. The path from the finalizer registration to the finalizer inlining
1596
1595
# location is nothrow
1597
1596
#
1598
- # TODO : We could relax item 3 , by inlining the finalizer multiple times.
1597
+ # TODO : We could relax the check 2 , by inlining the finalizer multiple times.
1599
1598
1600
1599
# Check #1: The allocation dominates the finalizer registration
1601
1600
domtree = get! (lazydomtree)
1602
1601
finalizer_bb = block_for_inst (ir, finalizer_idx)
1603
- alloc_bb = block_for_inst (ir, idx )
1602
+ alloc_bb = block_for_inst (ir, alloc_idx )
1604
1603
dominates (domtree, alloc_bb, finalizer_bb) || return nothing
1605
1604
1606
- bb_insert_block:: Int = finalizer_bb
1607
- bb_insert_idx:: Union{Int,Nothing} = finalizer_idx
1608
- function note_block_use! (usebb:: Int , useidx:: Int )
1609
- new_bb_insert_block = nearest_common_dominator (get! (lazypostdomtree),
1610
- bb_insert_block, usebb)
1611
- if new_bb_insert_block == bb_insert_block && bb_insert_idx != = nothing
1612
- bb_insert_idx = max (bb_insert_idx:: Int , useidx)
1613
- elseif new_bb_insert_block == usebb
1614
- bb_insert_idx = useidx
1605
+ # Check #2: The insertion block for the finalizer is the post-dominator of all uses
1606
+ insert_bb:: Int = finalizer_bb
1607
+ insert_idx:: Union{Int,Nothing} = finalizer_idx
1608
+ function note_defuse! (x:: Union{Int,SSAUse} )
1609
+ defuse_idx = x isa SSAUse ? x. idx : x
1610
+ defuse_idx == finalizer_idx && return nothing
1611
+ defuse_bb = block_for_inst (ir, defuse_idx)
1612
+ new_insert_bb = nearest_common_dominator (get! (lazypostdomtree),
1613
+ insert_bb, defuse_bb)
1614
+ if new_insert_bb == insert_bb && insert_idx != = nothing
1615
+ insert_idx = max (insert_idx:: Int , defuse_idx)
1616
+ elseif new_insert_bb == defuse_bb
1617
+ insert_idx = defuse_idx
1615
1618
else
1616
- bb_insert_idx = nothing
1619
+ insert_idx = nothing
1617
1620
end
1618
- bb_insert_block = new_bb_insert_block
1621
+ insert_bb = new_insert_bb
1619
1622
nothing
1620
1623
end
1621
-
1622
- # Collect all reachable blocks between the finalizer registration and the
1623
- # insertion point
1624
- blocks = reachable_blocks (ir. cfg, finalizer_bb, alloc_bb)
1625
-
1626
- # Check #2
1627
- function check_defuse (x:: Union{Int,SSAUse} )
1628
- duidx = x isa SSAUse ? x. idx : x
1629
- duidx == finalizer_idx && return true
1630
- bb = block_for_inst (ir, duidx)
1631
- # Not reachable from finalizer registration - we're ok
1632
- bb ∉ blocks && return true
1633
- note_block_use! (bb, duidx)
1634
- if dominates (domtree, finalizer_bb, bb)
1635
- return true
1636
- else
1637
- return false
1638
- end
1639
- end
1640
- all (check_defuse, defuse. uses) || return nothing
1641
- all (check_defuse, defuse. defs) || return nothing
1642
- bb_insert_block != 0 || return nothing # verify post-dominator of all uses exists
1643
-
1644
- # Check #3
1645
- dominates (domtree, finalizer_bb, bb_insert_block) || return nothing
1624
+ foreach (note_defuse!, defuse. uses)
1625
+ foreach (note_defuse!, defuse. defs)
1626
+ insert_bb != 0 || return nothing # verify post-dominator of all uses exists
1646
1627
1647
1628
if ! OptimizationParams (inlining. interp). assume_fatal_throw
1648
1629
# Collect all reachable blocks between the finalizer registration and the
1649
1630
# insertion point
1650
- blocks = finalizer_bb == bb_insert_block ? Int[finalizer_bb] :
1651
- reachable_blocks (ir. cfg, finalizer_bb, bb_insert_block)
1631
+ blocks = reachable_blocks (ir. cfg, finalizer_bb, insert_bb)
1652
1632
1653
- # Check #4
1654
- function check_range_nothrow (ir :: IRCode , s:: Int , e:: Int )
1633
+ # Check #3
1634
+ function check_range_nothrow (s:: Int , e:: Int )
1655
1635
return all (s: e) do sidx:: Int
1656
1636
sidx == finalizer_idx && return true
1657
- sidx == idx && return true
1637
+ sidx == alloc_idx && return true
1658
1638
return is_nothrow (ir, SSAValue (sidx))
1659
1639
end
1660
1640
end
1661
1641
for bb in blocks
1662
1642
range = ir. cfg. blocks[bb]. stmts
1663
1643
s, e = first (range), last (range)
1664
- if bb == bb_insert_block
1665
- bb_insert_idx === nothing && continue
1666
- e = bb_insert_idx
1644
+ if bb == insert_bb
1645
+ insert_idx === nothing && continue
1646
+ e = insert_idx
1667
1647
end
1668
1648
if bb == finalizer_bb
1669
1649
s = finalizer_idx
1670
1650
end
1671
- check_range_nothrow (ir, s, e) || return nothing
1651
+ check_range_nothrow (s, e) || return nothing
1672
1652
end
1673
1653
end
1674
1654
1675
1655
# Ok, legality check complete. Figure out the exact statement where we're
1676
1656
# going to inline the finalizer.
1677
- loc = bb_insert_idx === nothing ? first (ir. cfg. blocks[bb_insert_block ]. stmts) : bb_insert_idx :: Int
1678
- attach_after = bb_insert_idx != = nothing
1657
+ loc = insert_idx === nothing ? first (ir. cfg. blocks[insert_bb ]. stmts) : insert_idx :: Int
1658
+ attach_after = insert_idx != = nothing
1679
1659
1680
1660
finalizer_stmt = ir[SSAValue (finalizer_idx)][:stmt ]
1681
1661
argexprs = Any[finalizer_stmt. args[2 ], finalizer_stmt. args[3 ]]
@@ -1702,11 +1682,10 @@ function try_resolve_finalizer!(ir::IRCode, idx::Int, finalizer_idx::Int, defuse
1702
1682
return nothing
1703
1683
end
1704
1684
1705
- function sroa_mutables! (ir:: IRCode , defuses:: IdDict{Int, Tuple{SPCSet, SSADefUse}} , used_ssas:: Vector{Int} , lazydomtree:: LazyDomtree , inlining:: Union{Nothing, InliningState} )
1685
+ function sroa_mutables! (ir:: IRCode , defuses:: IdDict{Int,Tuple{SPCSet,SSADefUse}} , used_ssas:: Vector{Int} , lazydomtree:: LazyDomtree , inlining:: Union{Nothing,InliningState} )
1706
1686
𝕃ₒ = inlining === nothing ? SimpleInferenceLattice. instance : optimizer_lattice (inlining. interp)
1707
1687
lazypostdomtree = LazyPostDomtree (ir)
1708
1688
for (defidx, (intermediaries, defuse)) in defuses
1709
- intermediaries = collect (intermediaries)
1710
1689
# Check if there are any uses we did not account for. If so, the variable
1711
1690
# escapes and we cannot eliminate the allocation. This works, because we're guaranteed
1712
1691
# not to include any intermediaries that have dead uses. As a result, missing uses will only ever
@@ -1906,7 +1885,7 @@ function sroa_mutables!(ir::IRCode, defuses::IdDict{Int, Tuple{SPCSet, SSADefUse
1906
1885
end
1907
1886
end
1908
1887
1909
- function form_new_preserves (origex:: Expr , intermediates :: Vector{Int} , new_preserves:: Vector{Any} )
1888
+ function form_new_preserves (origex:: Expr , intermediaries :: Union{ Vector{Int},SPCSet } , new_preserves:: Vector{Any} )
1910
1889
newex = Expr (:foreigncall )
1911
1890
nccallargs = length (origex. args[3 ]:: SimpleVector )
1912
1891
for i in 1 : (6 + nccallargs- 1 )
@@ -1915,7 +1894,7 @@ function form_new_preserves(origex::Expr, intermediates::Vector{Int}, new_preser
1915
1894
for i in (6 + nccallargs): length (origex. args)
1916
1895
x = origex. args[i]
1917
1896
# don't need to preserve intermediaries
1918
- if isa (x, SSAValue) && x. id in intermediates
1897
+ if isa (x, SSAValue) && x. id in intermediaries
1919
1898
continue
1920
1899
end
1921
1900
push! (newex. args, x)
0 commit comments