@@ -360,10 +360,11 @@ struct LiftedValue
360
360
LiftedValue (@nospecialize val) = new (val)
361
361
end
362
362
const LiftedLeaves = IdDict{Any, Union{Nothing,LiftedValue}}
363
+ const LiftedDefs = IdDict{Any, Bool}
363
364
364
365
# try to compute lifted values that can replace `getfield(x, field)` call
365
366
# where `x` is an immutable struct that are defined at any of `leaves`
366
- function lift_leaves (compact:: IncrementalCompact , @nospecialize (result_t), field:: Int ,
367
+ function lift_leaves (compact:: IncrementalCompact , field:: Int ,
367
368
leaves:: Vector{Any} , 𝕃ₒ:: AbstractLattice )
368
369
# For every leaf, the lifted value
369
370
lifted_leaves = LiftedLeaves ()
@@ -393,15 +394,6 @@ function lift_leaves(compact::IncrementalCompact, @nospecialize(result_t), field
393
394
continue
394
395
end
395
396
return nothing
396
- # Expand the Expr(:new) to include it's element Expr(:new) nodes up until the one we want
397
- compact[leaf] = nothing
398
- for i = (length (def. args) + 1 ): (1 + field)
399
- ftyp = fieldtype (typ, i - 1 )
400
- isbitstype (ftyp) || return nothing
401
- ninst = effect_free (NewInstruction (Expr (:new , ftyp), result_t))
402
- push! (def. args, insert_node! (compact, leaf, ninst))
403
- end
404
- compact[leaf] = def
405
397
end
406
398
lift_arg! (compact, leaf, cache_key, def, 1 + field, lifted_leaves)
407
399
continue
@@ -505,8 +497,6 @@ function walk_to_def(compact::IncrementalCompact, @nospecialize(leaf))
505
497
return Pair {Any, Any} (def, leaf)
506
498
end
507
499
508
- make_MaybeUndef (@nospecialize (typ)) = isa (typ, MaybeUndef) ? typ : MaybeUndef (typ)
509
-
510
500
"""
511
501
lift_comparison!(cmp, compact::IncrementalCompact, idx::Int, stmt::Expr, 𝕃ₒ::AbstractLattice)
512
502
620
610
struct SkipToken end ; const SKIP_TOKEN = SkipToken ()
621
611
622
612
function lifted_value (compact:: IncrementalCompact , @nospecialize (old_node_ssa#= ::AnySSAValue=# ), @nospecialize (old_value),
623
- lifted_philikes:: Vector{LiftedPhilike} , lifted_leaves:: LiftedLeaves , reverse_mapping:: IdDict{AnySSAValue, Int} )
613
+ lifted_philikes:: Vector{LiftedPhilike} , lifted_leaves:: Union{ LiftedLeaves, LiftedDefs} , reverse_mapping:: IdDict{AnySSAValue, Int} )
624
614
val = old_value
625
615
if is_old (compact, old_node_ssa) && isa (val, SSAValue)
626
616
val = OldSSAValue (val. id)
@@ -630,6 +620,9 @@ function lifted_value(compact::IncrementalCompact, @nospecialize(old_node_ssa#=:
630
620
end
631
621
if val in keys (lifted_leaves)
632
622
lifted_val = lifted_leaves[val]
623
+ if isa (lifted_leaves, LiftedDefs)
624
+ return lifted_val
625
+ end
633
626
lifted_val === nothing && return UNDEF_TOKEN
634
627
val = lifted_val. val
635
628
if isa (val, AnySSAValue)
653
646
function perform_lifting! (compact:: IncrementalCompact ,
654
647
visited_philikes:: Vector{AnySSAValue} , @nospecialize (cache_key),
655
648
lifting_cache:: IdDict{Pair{AnySSAValue, Any}, AnySSAValue} ,
656
- @nospecialize (result_t), lifted_leaves:: LiftedLeaves , @nospecialize (stmt_val),
649
+ @nospecialize (result_t), lifted_leaves:: Union{ LiftedLeaves, LiftedDefs} , @nospecialize (stmt_val),
657
650
lazydomtree:: Union{LazyDomtree,Nothing} )
658
651
reverse_mapping = IdDict {AnySSAValue, Int} ()
659
652
for id in 1 : length (visited_philikes)
@@ -912,10 +905,11 @@ In a case when all usages are fully eliminated, `struct` allocation may also be
912
905
a result of succeeding dead code elimination.
913
906
"""
914
907
function sroa_pass! (ir:: IRCode , inlining:: Union{Nothing,InliningState} = nothing )
915
- 𝕃ₒ = inlining === nothing ? OptimizerLattice () : optimizer_lattice (inlining. interp)
908
+ 𝕃ₒ = inlining === nothing ? SimpleInferenceLattice . instance : optimizer_lattice (inlining. interp)
916
909
compact = IncrementalCompact (ir)
917
910
defuses = nothing # will be initialized once we encounter mutability in order to reduce dynamic allocations
918
911
lifting_cache = IdDict {Pair{AnySSAValue, Any}, AnySSAValue} ()
912
+ def_lifting_cache = IdDict {Pair{AnySSAValue, Any}, AnySSAValue} ()
919
913
# initialization of domtree is delayed to avoid the expensive computation in many cases
920
914
lazydomtree = LazyDomtree (ir)
921
915
for ((_, idx), stmt) in compact
@@ -1077,28 +1071,40 @@ function sroa_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
1077
1071
leaves, visited_philikes = collect_leaves (compact, val, struct_typ, 𝕃ₒ)
1078
1072
isempty (leaves) && continue
1079
1073
1080
- result_t = argextype (SSAValue (idx), compact)
1081
- lifted_result = lift_leaves (compact, result_t, field, leaves, 𝕃ₒ)
1074
+ lifted_result = lift_leaves (compact, field, leaves, 𝕃ₒ)
1082
1075
lifted_result === nothing && continue
1083
1076
lifted_leaves, any_undef = lifted_result
1084
1077
1085
- if any_undef
1086
- result_t = make_MaybeUndef (result_t)
1078
+ result_t = Union{}
1079
+ for v in values (lifted_leaves)
1080
+ v === nothing && continue
1081
+ result_t = tmerge (𝕃ₒ, result_t, argextype (v. val, compact))
1087
1082
end
1088
1083
1089
- val = perform_lifting! (compact,
1084
+ lifted_val = perform_lifting! (compact,
1090
1085
visited_philikes, field, lifting_cache, result_t, lifted_leaves, val, lazydomtree)
1091
1086
1092
1087
# Insert the undef check if necessary
1093
- if any_undef && val === nothing
1088
+ if any_undef
1089
+ if lifted_val === nothing
1090
+ def_val = false
1091
+ else
1092
+ lifted_leaves_def = LiftedDefs ()
1093
+ for (k, v) in pairs (lifted_leaves)
1094
+ lifted_leaves_def[k] = v === nothing ? false : true
1095
+ end
1096
+ def_val = perform_lifting! (compact,
1097
+ visited_philikes, field, def_lifting_cache, Bool, lifted_leaves_def, val, lazydomtree). val
1098
+ end
1094
1099
insert_node! (compact, SSAValue (idx), non_effect_free (NewInstruction (
1095
- Expr (:throw_undef_if_not , Symbol (" ##getfield##" ), false ), Nothing)))
1100
+ Expr (:throw_undef_if_not , Symbol (" ##getfield##" ), def_val), Nothing)))
1101
+
1096
1102
else
1097
1103
# val must be defined
1098
- @assert val != = nothing
1104
+ @assert lifted_val != = nothing
1099
1105
end
1100
1106
1101
- compact[idx] = val === nothing ? nothing : val . val
1107
+ compact[idx] = lifted_val === nothing ? nothing : lifted_val . val
1102
1108
compact[SSAValue (idx)][:flag ] |= IR_FLAG_REFINED
1103
1109
end
1104
1110
@@ -1572,7 +1578,6 @@ function mark_phi_cycles!(compact::IncrementalCompact, safe_phis::SPCSet, phi::I
1572
1578
end
1573
1579
1574
1580
function is_some_union (@nospecialize (t))
1575
- isa (t, MaybeUndef) && (t = t. typ)
1576
1581
return isa (t, Union)
1577
1582
end
1578
1583
@@ -1626,7 +1631,7 @@ the `typeassert` elimination depends on the transformation by `canonicalize_type
1626
1631
within `sroa_pass!` which redirects references of `typeassert`ed value to the corresponding `PiNode`.
1627
1632
"""
1628
1633
function adce_pass! (ir:: IRCode , inlining:: Union{Nothing,InliningState} = nothing )
1629
- 𝕃ₒ = inlining === nothing ? OptimizerLattice () : optimizer_lattice (inlining. interp)
1634
+ 𝕃ₒ = inlining === nothing ? SimpleInferenceLattice . instance : optimizer_lattice (inlining. interp)
1630
1635
phi_uses = fill (0 , length (ir. stmts) + length (ir. new_nodes))
1631
1636
all_phis = Int[]
1632
1637
unionphis = Pair{Int,Any}[] # sorted
@@ -1751,153 +1756,6 @@ function adce_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing)
1751
1756
return complete (compact)
1752
1757
end
1753
1758
1754
- function type_lift_pass! (ir:: IRCode )
1755
- lifted_undef = IdDict {Int, Any} ()
1756
- insts = ir. stmts
1757
- for idx in 1 : length (insts)
1758
- stmt = insts[idx][:inst ]
1759
- stmt isa Expr || continue
1760
- if (stmt. head === :isdefined || stmt. head === :undefcheck )
1761
- # after optimization, undef can only show up by being introduced in
1762
- # a phi node (or an UpsilonNode() argument to a PhiC node), so lift
1763
- # all these nodes that have maybe undef values
1764
- val = stmt. args[(stmt. head === :isdefined ) ? 1 : 2 ]
1765
- if stmt. head === :isdefined && (val isa GlobalRef || isexpr (val, :static_parameter ) ||
1766
- val isa Argument || val isa Symbol)
1767
- # this is a legal node, so assume it was not introduced by
1768
- # slot2ssa (at worst, we might leave in a runtime check that
1769
- # shouldn't have been there)
1770
- continue
1771
- end
1772
- # otherwise, we definitely have a corrupt node from slot2ssa, and
1773
- # must fix or delete that now
1774
- processed = IdDict {Int, Union{SSAValue, Bool}} ()
1775
- def = val
1776
- while true
1777
- # peek through PiNodes
1778
- isa (val, SSAValue) || break
1779
- def = insts[val. id][:inst ]
1780
- isa (def, PiNode) || break
1781
- val = def. val
1782
- end
1783
- if ! isa (val, SSAValue) || (! isa (def, PhiNode) && ! isa (def, PhiCNode))
1784
- # in most cases, reaching this statement implies we had a value
1785
- if stmt. head === :undefcheck
1786
- insts[idx][:inst ] = nothing
1787
- else
1788
- insts[idx][:inst ] = true
1789
- end
1790
- continue
1791
- end
1792
- stmt_id = val. id
1793
- worklist = Tuple{Int, Int, SSAValue, Int}[(stmt_id, 0 , SSAValue (0 ), 0 )]
1794
- if ! haskey (lifted_undef, stmt_id)
1795
- first = true
1796
- while ! isempty (worklist)
1797
- item, w_up_id, which, use = pop! (worklist)
1798
- def = insts[item][:inst ]
1799
- if isa (def, PhiNode)
1800
- edges = copy (def. edges)
1801
- values = Vector {Any} (undef, length (edges))
1802
- new_phi = if length (values) == 0
1803
- false
1804
- else
1805
- insert_node! (ir, item, NewInstruction (PhiNode (edges, values), Bool))
1806
- end
1807
- else
1808
- def = def:: PhiCNode
1809
- values = Vector {Any} (undef, length (def. values))
1810
- new_phi = if length (values) == 0
1811
- false
1812
- else
1813
- insert_node! (ir, item, NewInstruction (PhiCNode (values), Bool))
1814
- end
1815
- end
1816
- processed[item] = new_phi
1817
- if first
1818
- lifted_undef[stmt_id] = new_phi
1819
- first = false
1820
- end
1821
- local id:: Int = 0
1822
- all_same = true
1823
- local last_val
1824
- for i = 1 : length (values)
1825
- if ! isassigned (def. values, i)
1826
- val = false
1827
- elseif ! isa (def. values[i], SSAValue)
1828
- val = true
1829
- else
1830
- up_id = id = (def. values[i]:: SSAValue ). id
1831
- @label restart
1832
- if ! isa (ir. stmts[id][:type ], MaybeUndef)
1833
- val = true
1834
- else
1835
- node = insts[id][:inst ]
1836
- if isa (node, UpsilonNode)
1837
- if ! isdefined (node, :val )
1838
- val = false
1839
- elseif ! isa (node. val, SSAValue)
1840
- val = true
1841
- else
1842
- id = (node. val:: SSAValue ). id
1843
- @goto restart
1844
- end
1845
- else
1846
- while isa (node, PiNode)
1847
- id = (node. val:: SSAValue ). id
1848
- node = insts[id][:inst ]
1849
- end
1850
- if isa (node, Union{PhiNode, PhiCNode})
1851
- if haskey (processed, id)
1852
- val = processed[id]
1853
- else
1854
- # TODO : Re-check after convergence whether all the values are the same
1855
- all_same = false
1856
- push! (worklist, (id, up_id, new_phi:: SSAValue , i))
1857
- continue
1858
- end
1859
- else
1860
- val = true
1861
- end
1862
- end
1863
- end
1864
- end
1865
- if isa (def, PhiNode)
1866
- if ! @isdefined (last_val)
1867
- last_val = val
1868
- elseif all_same
1869
- all_same &= last_val === val
1870
- end
1871
- values[i] = val
1872
- else
1873
- values[i] = insert_node! (ir, up_id, NewInstruction (UpsilonNode (val), Bool))
1874
- end
1875
- end
1876
- if all_same && @isdefined (last_val)
1877
- # Decay the PhiNode back to the single value
1878
- ir[new_phi][:inst ] = last_val
1879
- isa (last_val, Bool) && (processed[item] = last_val)
1880
- end
1881
- if which != = SSAValue (0 )
1882
- phi = ir[which][:inst ]
1883
- if isa (phi, PhiNode)
1884
- phi. values[use] = new_phi
1885
- elseif isa (phi, PhiCNode)
1886
- phi. values[use] = insert_node! (ir, w_up_id, NewInstruction (UpsilonNode (new_phi), Bool))
1887
- end
1888
- end
1889
- end
1890
- end
1891
- inst = lifted_undef[stmt_id]
1892
- if stmt. head === :undefcheck
1893
- inst = Expr (:throw_undef_if_not , stmt. args[1 ], inst)
1894
- end
1895
- insts[idx][:inst ] = inst
1896
- end
1897
- end
1898
- ir
1899
- end
1900
-
1901
1759
function is_bb_empty (ir:: IRCode , bb:: BasicBlock )
1902
1760
isempty (bb. stmts) && return true
1903
1761
if length (bb. stmts) == 1
0 commit comments